root/drivers/regulator/arizona-ldo1.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. arizona_ldo1_hc_set_voltage_sel
  2. arizona_ldo1_hc_get_voltage_sel
  3. arizona_ldo1_of_get_pdata
  4. arizona_ldo1_common_init
  5. arizona_ldo1_probe
  6. arizona_ldo1_remove
  7. madera_ldo1_probe
  8. arizona_ldo1_init
  9. madera_ldo1_exit

   1 // SPDX-License-Identifier: GPL-2.0+
   2 //
   3 // arizona-ldo1.c  --  LDO1 supply for Arizona devices
   4 //
   5 // Copyright 2012 Wolfson Microelectronics PLC.
   6 //
   7 // Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
   8 
   9 #include <linux/module.h>
  10 #include <linux/moduleparam.h>
  11 #include <linux/init.h>
  12 #include <linux/bitops.h>
  13 #include <linux/err.h>
  14 #include <linux/of.h>
  15 #include <linux/gpio/consumer.h>
  16 #include <linux/platform_device.h>
  17 #include <linux/regulator/driver.h>
  18 #include <linux/regulator/machine.h>
  19 #include <linux/regulator/of_regulator.h>
  20 #include <linux/slab.h>
  21 
  22 #include <linux/regulator/arizona-ldo1.h>
  23 
  24 #include <linux/mfd/arizona/core.h>
  25 #include <linux/mfd/arizona/pdata.h>
  26 #include <linux/mfd/arizona/registers.h>
  27 
  28 #include <linux/mfd/madera/core.h>
  29 #include <linux/mfd/madera/pdata.h>
  30 #include <linux/mfd/madera/registers.h>
  31 
  32 struct arizona_ldo1 {
  33         struct regulator_dev *regulator;
  34         struct regmap *regmap;
  35 
  36         struct regulator_consumer_supply supply;
  37         struct regulator_init_data init_data;
  38 
  39         struct gpio_desc *ena_gpiod;
  40 };
  41 
  42 static int arizona_ldo1_hc_set_voltage_sel(struct regulator_dev *rdev,
  43                                            unsigned sel)
  44 {
  45         struct regmap *regmap = rdev_get_regmap(rdev);
  46         unsigned int val;
  47         int ret;
  48 
  49         if (sel == rdev->desc->n_voltages - 1)
  50                 val = ARIZONA_LDO1_HI_PWR;
  51         else
  52                 val = 0;
  53 
  54         ret = regmap_update_bits(regmap, ARIZONA_LDO1_CONTROL_2,
  55                                  ARIZONA_LDO1_HI_PWR, val);
  56         if (ret != 0)
  57                 return ret;
  58 
  59         if (val)
  60                 return 0;
  61 
  62         return regulator_set_voltage_sel_regmap(rdev, sel);
  63 }
  64 
  65 static int arizona_ldo1_hc_get_voltage_sel(struct regulator_dev *rdev)
  66 {
  67         struct regmap *regmap = rdev_get_regmap(rdev);
  68         unsigned int val;
  69         int ret;
  70 
  71         ret = regmap_read(regmap, ARIZONA_LDO1_CONTROL_2, &val);
  72         if (ret != 0)
  73                 return ret;
  74 
  75         if (val & ARIZONA_LDO1_HI_PWR)
  76                 return rdev->desc->n_voltages - 1;
  77 
  78         return regulator_get_voltage_sel_regmap(rdev);
  79 }
  80 
  81 static const struct regulator_ops arizona_ldo1_hc_ops = {
  82         .list_voltage = regulator_list_voltage_linear_range,
  83         .map_voltage = regulator_map_voltage_linear_range,
  84         .get_voltage_sel = arizona_ldo1_hc_get_voltage_sel,
  85         .set_voltage_sel = arizona_ldo1_hc_set_voltage_sel,
  86         .get_bypass = regulator_get_bypass_regmap,
  87         .set_bypass = regulator_set_bypass_regmap,
  88 };
  89 
  90 static const struct regulator_linear_range arizona_ldo1_hc_ranges[] = {
  91         REGULATOR_LINEAR_RANGE(900000, 0, 0x6, 50000),
  92         REGULATOR_LINEAR_RANGE(1800000, 0x7, 0x7, 0),
  93 };
  94 
  95 static const struct regulator_desc arizona_ldo1_hc = {
  96         .name = "LDO1",
  97         .supply_name = "LDOVDD",
  98         .type = REGULATOR_VOLTAGE,
  99         .ops = &arizona_ldo1_hc_ops,
 100 
 101         .vsel_reg = ARIZONA_LDO1_CONTROL_1,
 102         .vsel_mask = ARIZONA_LDO1_VSEL_MASK,
 103         .bypass_reg = ARIZONA_LDO1_CONTROL_1,
 104         .bypass_mask = ARIZONA_LDO1_BYPASS,
 105         .linear_ranges = arizona_ldo1_hc_ranges,
 106         .n_linear_ranges = ARRAY_SIZE(arizona_ldo1_hc_ranges),
 107         .n_voltages = 8,
 108         .enable_time = 1500,
 109         .ramp_delay = 24000,
 110 
 111         .owner = THIS_MODULE,
 112 };
 113 
 114 static const struct regulator_ops arizona_ldo1_ops = {
 115         .list_voltage = regulator_list_voltage_linear,
 116         .map_voltage = regulator_map_voltage_linear,
 117         .get_voltage_sel = regulator_get_voltage_sel_regmap,
 118         .set_voltage_sel = regulator_set_voltage_sel_regmap,
 119 };
 120 
 121 static const struct regulator_desc arizona_ldo1 = {
 122         .name = "LDO1",
 123         .supply_name = "LDOVDD",
 124         .type = REGULATOR_VOLTAGE,
 125         .ops = &arizona_ldo1_ops,
 126 
 127         .vsel_reg = ARIZONA_LDO1_CONTROL_1,
 128         .vsel_mask = ARIZONA_LDO1_VSEL_MASK,
 129         .min_uV = 900000,
 130         .uV_step = 25000,
 131         .n_voltages = 13,
 132         .enable_time = 500,
 133         .ramp_delay = 24000,
 134 
 135         .owner = THIS_MODULE,
 136 };
 137 
 138 static const struct regulator_init_data arizona_ldo1_dvfs = {
 139         .constraints = {
 140                 .min_uV = 1200000,
 141                 .max_uV = 1800000,
 142                 .valid_ops_mask = REGULATOR_CHANGE_STATUS |
 143                                   REGULATOR_CHANGE_VOLTAGE,
 144         },
 145         .num_consumer_supplies = 1,
 146 };
 147 
 148 static const struct regulator_init_data arizona_ldo1_default = {
 149         .constraints = {
 150                 .valid_ops_mask = REGULATOR_CHANGE_STATUS,
 151         },
 152         .num_consumer_supplies = 1,
 153 };
 154 
 155 static const struct regulator_init_data arizona_ldo1_wm5110 = {
 156         .constraints = {
 157                 .min_uV = 1175000,
 158                 .max_uV = 1200000,
 159                 .valid_ops_mask = REGULATOR_CHANGE_STATUS |
 160                                   REGULATOR_CHANGE_VOLTAGE,
 161         },
 162         .num_consumer_supplies = 1,
 163 };
 164 
 165 static const struct regulator_desc madera_ldo1 = {
 166         .name = "LDO1",
 167         .supply_name = "LDOVDD",
 168         .type = REGULATOR_VOLTAGE,
 169         .ops = &arizona_ldo1_ops,
 170 
 171         .vsel_reg = MADERA_LDO1_CONTROL_1,
 172         .vsel_mask = MADERA_LDO1_VSEL_MASK,
 173         .min_uV = 900000,
 174         .uV_step = 25000,
 175         .n_voltages = 13,
 176         .enable_time = 3000,
 177 
 178         .owner = THIS_MODULE,
 179 };
 180 
 181 static const struct regulator_init_data madera_ldo1_default = {
 182         .constraints = {
 183                 .min_uV = 1200000,
 184                 .max_uV = 1200000,
 185                 .valid_ops_mask = REGULATOR_CHANGE_STATUS,
 186         },
 187         .num_consumer_supplies = 1,
 188 };
 189 
 190 static int arizona_ldo1_of_get_pdata(struct arizona_ldo1_pdata *pdata,
 191                                      struct regulator_config *config,
 192                                      const struct regulator_desc *desc,
 193                                      bool *external_dcvdd)
 194 {
 195         struct arizona_ldo1 *ldo1 = config->driver_data;
 196         struct device_node *np = config->dev->of_node;
 197         struct device_node *init_node, *dcvdd_node;
 198         struct regulator_init_data *init_data;
 199 
 200         init_node = of_get_child_by_name(np, "ldo1");
 201         dcvdd_node = of_parse_phandle(np, "DCVDD-supply", 0);
 202 
 203         if (init_node) {
 204                 config->of_node = init_node;
 205 
 206                 init_data = of_get_regulator_init_data(config->dev, init_node,
 207                                                        desc);
 208                 if (init_data) {
 209                         init_data->consumer_supplies = &ldo1->supply;
 210                         init_data->num_consumer_supplies = 1;
 211 
 212                         if (dcvdd_node && dcvdd_node != init_node)
 213                                 *external_dcvdd = true;
 214 
 215                         pdata->init_data = init_data;
 216                 }
 217         } else if (dcvdd_node) {
 218                 *external_dcvdd = true;
 219         }
 220 
 221         of_node_put(dcvdd_node);
 222 
 223         return 0;
 224 }
 225 
 226 static int arizona_ldo1_common_init(struct platform_device *pdev,
 227                                     struct arizona_ldo1 *ldo1,
 228                                     const struct regulator_desc *desc,
 229                                     struct arizona_ldo1_pdata *pdata,
 230                                     bool *external_dcvdd)
 231 {
 232         struct device *parent_dev = pdev->dev.parent;
 233         struct regulator_config config = { };
 234         int ret;
 235 
 236         *external_dcvdd = false;
 237 
 238         ldo1->supply.supply = "DCVDD";
 239         ldo1->init_data.consumer_supplies = &ldo1->supply;
 240         ldo1->supply.dev_name = dev_name(parent_dev);
 241 
 242         config.dev = parent_dev;
 243         config.driver_data = ldo1;
 244         config.regmap = ldo1->regmap;
 245 
 246         if (IS_ENABLED(CONFIG_OF)) {
 247                 if (!dev_get_platdata(parent_dev)) {
 248                         ret = arizona_ldo1_of_get_pdata(pdata,
 249                                                         &config, desc,
 250                                                         external_dcvdd);
 251                         if (ret < 0)
 252                                 return ret;
 253                 }
 254         }
 255 
 256         /* We assume that high output = regulator off
 257          * Don't use devm, since we need to get against the parent device
 258          * so clean up would happen at the wrong time
 259          */
 260         config.ena_gpiod = gpiod_get_optional(parent_dev, "wlf,ldoena",
 261                                 GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
 262         if (IS_ERR(config.ena_gpiod))
 263                 return PTR_ERR(config.ena_gpiod);
 264 
 265         ldo1->ena_gpiod = config.ena_gpiod;
 266 
 267         if (pdata->init_data)
 268                 config.init_data = pdata->init_data;
 269         else
 270                 config.init_data = &ldo1->init_data;
 271 
 272         /*
 273          * LDO1 can only be used to supply DCVDD so if it has no
 274          * consumers then DCVDD is supplied externally.
 275          */
 276         if (config.init_data->num_consumer_supplies == 0)
 277                 *external_dcvdd = true;
 278 
 279         ldo1->regulator = devm_regulator_register(&pdev->dev, desc, &config);
 280 
 281         of_node_put(config.of_node);
 282 
 283         if (IS_ERR(ldo1->regulator)) {
 284                 ret = PTR_ERR(ldo1->regulator);
 285                 dev_err(&pdev->dev, "Failed to register LDO1 supply: %d\n",
 286                         ret);
 287                 return ret;
 288         }
 289 
 290         platform_set_drvdata(pdev, ldo1);
 291 
 292         return 0;
 293 }
 294 
 295 static int arizona_ldo1_probe(struct platform_device *pdev)
 296 {
 297         struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
 298         struct arizona_ldo1 *ldo1;
 299         const struct regulator_desc *desc;
 300         bool external_dcvdd;
 301         int ret;
 302 
 303         ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL);
 304         if (!ldo1)
 305                 return -ENOMEM;
 306 
 307         ldo1->regmap = arizona->regmap;
 308 
 309         /*
 310          * Since the chip usually supplies itself we provide some
 311          * default init_data for it.  This will be overridden with
 312          * platform data if provided.
 313          */
 314         switch (arizona->type) {
 315         case WM5102:
 316         case WM8997:
 317         case WM8998:
 318         case WM1814:
 319                 desc = &arizona_ldo1_hc;
 320                 ldo1->init_data = arizona_ldo1_dvfs;
 321                 break;
 322         case WM5110:
 323         case WM8280:
 324                 desc = &arizona_ldo1;
 325                 ldo1->init_data = arizona_ldo1_wm5110;
 326                 break;
 327         default:
 328                 desc = &arizona_ldo1;
 329                 ldo1->init_data = arizona_ldo1_default;
 330                 break;
 331         }
 332 
 333         ret = arizona_ldo1_common_init(pdev, ldo1, desc,
 334                                        &arizona->pdata.ldo1,
 335                                        &external_dcvdd);
 336         if (ret == 0)
 337                 arizona->external_dcvdd = external_dcvdd;
 338 
 339         return ret;
 340 }
 341 
 342 static int arizona_ldo1_remove(struct platform_device *pdev)
 343 {
 344         struct arizona_ldo1 *ldo1 = platform_get_drvdata(pdev);
 345 
 346         if (ldo1->ena_gpiod)
 347                 gpiod_put(ldo1->ena_gpiod);
 348 
 349         return 0;
 350 }
 351 
 352 static int madera_ldo1_probe(struct platform_device *pdev)
 353 {
 354         struct madera *madera = dev_get_drvdata(pdev->dev.parent);
 355         struct arizona_ldo1 *ldo1;
 356         bool external_dcvdd;
 357         int ret;
 358 
 359         ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL);
 360         if (!ldo1)
 361                 return -ENOMEM;
 362 
 363         ldo1->regmap = madera->regmap;
 364 
 365         ldo1->init_data = madera_ldo1_default;
 366 
 367         ret = arizona_ldo1_common_init(pdev, ldo1, &madera_ldo1,
 368                                        &madera->pdata.ldo1,
 369                                        &external_dcvdd);
 370         if (ret)
 371                 return ret;
 372 
 373         madera->internal_dcvdd = !external_dcvdd;
 374 
 375         return 0;
 376 }
 377 
 378 static struct platform_driver arizona_ldo1_driver = {
 379         .probe = arizona_ldo1_probe,
 380         .remove = arizona_ldo1_remove,
 381         .driver         = {
 382                 .name   = "arizona-ldo1",
 383         },
 384 };
 385 
 386 static struct platform_driver madera_ldo1_driver = {
 387         .probe = madera_ldo1_probe,
 388         .remove = arizona_ldo1_remove,
 389         .driver         = {
 390                 .name   = "madera-ldo1",
 391         },
 392 };
 393 
 394 static struct platform_driver * const madera_ldo1_drivers[] = {
 395         &arizona_ldo1_driver,
 396         &madera_ldo1_driver,
 397 };
 398 
 399 static int __init arizona_ldo1_init(void)
 400 {
 401         return platform_register_drivers(madera_ldo1_drivers,
 402                                          ARRAY_SIZE(madera_ldo1_drivers));
 403 }
 404 module_init(arizona_ldo1_init);
 405 
 406 static void __exit madera_ldo1_exit(void)
 407 {
 408         platform_unregister_drivers(madera_ldo1_drivers,
 409                                     ARRAY_SIZE(madera_ldo1_drivers));
 410 }
 411 module_exit(madera_ldo1_exit);
 412 
 413 /* Module information */
 414 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
 415 MODULE_DESCRIPTION("Arizona LDO1 driver");
 416 MODULE_LICENSE("GPL");
 417 MODULE_ALIAS("platform:arizona-ldo1");
 418 MODULE_ALIAS("platform:madera-ldo1");

/* [<][>][^][v][top][bottom][index][help] */