0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/module.h>
0010 #include <linux/moduleparam.h>
0011 #include <linux/init.h>
0012 #include <linux/bitops.h>
0013 #include <linux/err.h>
0014 #include <linux/of.h>
0015 #include <linux/gpio/consumer.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/regulator/driver.h>
0018 #include <linux/regulator/machine.h>
0019 #include <linux/regulator/of_regulator.h>
0020 #include <linux/slab.h>
0021
0022 #include <linux/regulator/arizona-ldo1.h>
0023
0024 #include <linux/mfd/arizona/core.h>
0025 #include <linux/mfd/arizona/pdata.h>
0026 #include <linux/mfd/arizona/registers.h>
0027
0028 #include <linux/mfd/madera/core.h>
0029 #include <linux/mfd/madera/pdata.h>
0030 #include <linux/mfd/madera/registers.h>
0031
0032 struct arizona_ldo1 {
0033 struct regulator_dev *regulator;
0034 struct regmap *regmap;
0035
0036 struct regulator_consumer_supply supply;
0037 struct regulator_init_data init_data;
0038
0039 struct gpio_desc *ena_gpiod;
0040 };
0041
0042 static int arizona_ldo1_hc_set_voltage_sel(struct regulator_dev *rdev,
0043 unsigned sel)
0044 {
0045 struct regmap *regmap = rdev_get_regmap(rdev);
0046 unsigned int val;
0047 int ret;
0048
0049 if (sel == rdev->desc->n_voltages - 1)
0050 val = ARIZONA_LDO1_HI_PWR;
0051 else
0052 val = 0;
0053
0054 ret = regmap_update_bits(regmap, ARIZONA_LDO1_CONTROL_2,
0055 ARIZONA_LDO1_HI_PWR, val);
0056 if (ret != 0)
0057 return ret;
0058
0059 if (val)
0060 return 0;
0061
0062 return regulator_set_voltage_sel_regmap(rdev, sel);
0063 }
0064
0065 static int arizona_ldo1_hc_get_voltage_sel(struct regulator_dev *rdev)
0066 {
0067 struct regmap *regmap = rdev_get_regmap(rdev);
0068 unsigned int val;
0069 int ret;
0070
0071 ret = regmap_read(regmap, ARIZONA_LDO1_CONTROL_2, &val);
0072 if (ret != 0)
0073 return ret;
0074
0075 if (val & ARIZONA_LDO1_HI_PWR)
0076 return rdev->desc->n_voltages - 1;
0077
0078 return regulator_get_voltage_sel_regmap(rdev);
0079 }
0080
0081 static const struct regulator_ops arizona_ldo1_hc_ops = {
0082 .list_voltage = regulator_list_voltage_linear_range,
0083 .map_voltage = regulator_map_voltage_linear_range,
0084 .get_voltage_sel = arizona_ldo1_hc_get_voltage_sel,
0085 .set_voltage_sel = arizona_ldo1_hc_set_voltage_sel,
0086 .get_bypass = regulator_get_bypass_regmap,
0087 .set_bypass = regulator_set_bypass_regmap,
0088 };
0089
0090 static const struct linear_range arizona_ldo1_hc_ranges[] = {
0091 REGULATOR_LINEAR_RANGE(900000, 0, 0x6, 50000),
0092 REGULATOR_LINEAR_RANGE(1800000, 0x7, 0x7, 0),
0093 };
0094
0095 static const struct regulator_desc arizona_ldo1_hc = {
0096 .name = "LDO1",
0097 .supply_name = "LDOVDD",
0098 .type = REGULATOR_VOLTAGE,
0099 .ops = &arizona_ldo1_hc_ops,
0100
0101 .vsel_reg = ARIZONA_LDO1_CONTROL_1,
0102 .vsel_mask = ARIZONA_LDO1_VSEL_MASK,
0103 .bypass_reg = ARIZONA_LDO1_CONTROL_1,
0104 .bypass_mask = ARIZONA_LDO1_BYPASS,
0105 .linear_ranges = arizona_ldo1_hc_ranges,
0106 .n_linear_ranges = ARRAY_SIZE(arizona_ldo1_hc_ranges),
0107 .n_voltages = 8,
0108 .enable_time = 1500,
0109 .ramp_delay = 24000,
0110
0111 .owner = THIS_MODULE,
0112 };
0113
0114 static const struct regulator_ops arizona_ldo1_ops = {
0115 .list_voltage = regulator_list_voltage_linear,
0116 .map_voltage = regulator_map_voltage_linear,
0117 .get_voltage_sel = regulator_get_voltage_sel_regmap,
0118 .set_voltage_sel = regulator_set_voltage_sel_regmap,
0119 };
0120
0121 static const struct regulator_desc arizona_ldo1 = {
0122 .name = "LDO1",
0123 .supply_name = "LDOVDD",
0124 .type = REGULATOR_VOLTAGE,
0125 .ops = &arizona_ldo1_ops,
0126
0127 .vsel_reg = ARIZONA_LDO1_CONTROL_1,
0128 .vsel_mask = ARIZONA_LDO1_VSEL_MASK,
0129 .min_uV = 900000,
0130 .uV_step = 25000,
0131 .n_voltages = 13,
0132 .enable_time = 500,
0133 .ramp_delay = 24000,
0134
0135 .owner = THIS_MODULE,
0136 };
0137
0138 static const struct regulator_init_data arizona_ldo1_dvfs = {
0139 .constraints = {
0140 .min_uV = 1200000,
0141 .max_uV = 1800000,
0142 .valid_ops_mask = REGULATOR_CHANGE_STATUS |
0143 REGULATOR_CHANGE_VOLTAGE,
0144 },
0145 .num_consumer_supplies = 1,
0146 };
0147
0148 static const struct regulator_init_data arizona_ldo1_default = {
0149 .constraints = {
0150 .valid_ops_mask = REGULATOR_CHANGE_STATUS,
0151 },
0152 .num_consumer_supplies = 1,
0153 };
0154
0155 static const struct regulator_init_data arizona_ldo1_wm5110 = {
0156 .constraints = {
0157 .min_uV = 1175000,
0158 .max_uV = 1200000,
0159 .valid_ops_mask = REGULATOR_CHANGE_STATUS |
0160 REGULATOR_CHANGE_VOLTAGE,
0161 },
0162 .num_consumer_supplies = 1,
0163 };
0164
0165 static const struct regulator_desc madera_ldo1 = {
0166 .name = "LDO1",
0167 .supply_name = "LDOVDD",
0168 .type = REGULATOR_VOLTAGE,
0169 .ops = &arizona_ldo1_ops,
0170
0171 .vsel_reg = MADERA_LDO1_CONTROL_1,
0172 .vsel_mask = MADERA_LDO1_VSEL_MASK,
0173 .min_uV = 900000,
0174 .uV_step = 25000,
0175 .n_voltages = 13,
0176 .enable_time = 3000,
0177
0178 .owner = THIS_MODULE,
0179 };
0180
0181 static const struct regulator_init_data madera_ldo1_default = {
0182 .constraints = {
0183 .min_uV = 1200000,
0184 .max_uV = 1200000,
0185 .valid_ops_mask = REGULATOR_CHANGE_STATUS,
0186 },
0187 .num_consumer_supplies = 1,
0188 };
0189
0190 static int arizona_ldo1_of_get_pdata(struct arizona_ldo1_pdata *pdata,
0191 struct regulator_config *config,
0192 const struct regulator_desc *desc,
0193 bool *external_dcvdd)
0194 {
0195 struct arizona_ldo1 *ldo1 = config->driver_data;
0196 struct device_node *np = config->dev->of_node;
0197 struct device_node *init_node, *dcvdd_node;
0198 struct regulator_init_data *init_data;
0199
0200 init_node = of_get_child_by_name(np, "ldo1");
0201 dcvdd_node = of_parse_phandle(np, "DCVDD-supply", 0);
0202
0203 if (init_node) {
0204 config->of_node = init_node;
0205
0206 init_data = of_get_regulator_init_data(config->dev, init_node,
0207 desc);
0208 if (init_data) {
0209 init_data->consumer_supplies = &ldo1->supply;
0210 init_data->num_consumer_supplies = 1;
0211
0212 if (dcvdd_node && dcvdd_node != init_node)
0213 *external_dcvdd = true;
0214
0215 pdata->init_data = init_data;
0216 }
0217 } else if (dcvdd_node) {
0218 *external_dcvdd = true;
0219 }
0220
0221 of_node_put(dcvdd_node);
0222
0223 return 0;
0224 }
0225
0226 static int arizona_ldo1_common_init(struct platform_device *pdev,
0227 struct arizona_ldo1 *ldo1,
0228 const struct regulator_desc *desc,
0229 struct arizona_ldo1_pdata *pdata,
0230 bool *external_dcvdd)
0231 {
0232 struct device *parent_dev = pdev->dev.parent;
0233 struct regulator_config config = { };
0234 int ret;
0235
0236 *external_dcvdd = false;
0237
0238 ldo1->supply.supply = "DCVDD";
0239 ldo1->init_data.consumer_supplies = &ldo1->supply;
0240 ldo1->supply.dev_name = dev_name(parent_dev);
0241
0242 config.dev = parent_dev;
0243 config.driver_data = ldo1;
0244 config.regmap = ldo1->regmap;
0245
0246 if (IS_ENABLED(CONFIG_OF)) {
0247 if (!dev_get_platdata(parent_dev)) {
0248 ret = arizona_ldo1_of_get_pdata(pdata,
0249 &config, desc,
0250 external_dcvdd);
0251 if (ret < 0)
0252 return ret;
0253 }
0254 }
0255
0256
0257
0258
0259
0260 config.ena_gpiod = gpiod_get_optional(parent_dev, "wlf,ldoena",
0261 GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
0262 if (IS_ERR(config.ena_gpiod))
0263 return PTR_ERR(config.ena_gpiod);
0264
0265 ldo1->ena_gpiod = config.ena_gpiod;
0266
0267 if (pdata->init_data)
0268 config.init_data = pdata->init_data;
0269 else
0270 config.init_data = &ldo1->init_data;
0271
0272
0273
0274
0275
0276 if (config.init_data->num_consumer_supplies == 0)
0277 *external_dcvdd = true;
0278
0279 ldo1->regulator = devm_regulator_register(&pdev->dev, desc, &config);
0280
0281 of_node_put(config.of_node);
0282
0283 if (IS_ERR(ldo1->regulator)) {
0284 ret = PTR_ERR(ldo1->regulator);
0285 dev_err(&pdev->dev, "Failed to register LDO1 supply: %d\n",
0286 ret);
0287 return ret;
0288 }
0289
0290 platform_set_drvdata(pdev, ldo1);
0291
0292 return 0;
0293 }
0294
0295 static int arizona_ldo1_probe(struct platform_device *pdev)
0296 {
0297 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
0298 struct arizona_ldo1 *ldo1;
0299 const struct regulator_desc *desc;
0300 bool external_dcvdd;
0301 int ret;
0302
0303 ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL);
0304 if (!ldo1)
0305 return -ENOMEM;
0306
0307 ldo1->regmap = arizona->regmap;
0308
0309
0310
0311
0312
0313
0314 switch (arizona->type) {
0315 case WM5102:
0316 case WM8997:
0317 case WM8998:
0318 case WM1814:
0319 desc = &arizona_ldo1_hc;
0320 ldo1->init_data = arizona_ldo1_dvfs;
0321 break;
0322 case WM5110:
0323 case WM8280:
0324 desc = &arizona_ldo1;
0325 ldo1->init_data = arizona_ldo1_wm5110;
0326 break;
0327 default:
0328 desc = &arizona_ldo1;
0329 ldo1->init_data = arizona_ldo1_default;
0330 break;
0331 }
0332
0333 ret = arizona_ldo1_common_init(pdev, ldo1, desc,
0334 &arizona->pdata.ldo1,
0335 &external_dcvdd);
0336 if (ret == 0)
0337 arizona->external_dcvdd = external_dcvdd;
0338
0339 return ret;
0340 }
0341
0342 static int arizona_ldo1_remove(struct platform_device *pdev)
0343 {
0344 struct arizona_ldo1 *ldo1 = platform_get_drvdata(pdev);
0345
0346 if (ldo1->ena_gpiod)
0347 gpiod_put(ldo1->ena_gpiod);
0348
0349 return 0;
0350 }
0351
0352 static int madera_ldo1_probe(struct platform_device *pdev)
0353 {
0354 struct madera *madera = dev_get_drvdata(pdev->dev.parent);
0355 struct arizona_ldo1 *ldo1;
0356 bool external_dcvdd;
0357 int ret;
0358
0359 ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL);
0360 if (!ldo1)
0361 return -ENOMEM;
0362
0363 ldo1->regmap = madera->regmap;
0364
0365 ldo1->init_data = madera_ldo1_default;
0366
0367 ret = arizona_ldo1_common_init(pdev, ldo1, &madera_ldo1,
0368 &madera->pdata.ldo1,
0369 &external_dcvdd);
0370 if (ret)
0371 return ret;
0372
0373 madera->internal_dcvdd = !external_dcvdd;
0374
0375 return 0;
0376 }
0377
0378 static struct platform_driver arizona_ldo1_driver = {
0379 .probe = arizona_ldo1_probe,
0380 .remove = arizona_ldo1_remove,
0381 .driver = {
0382 .name = "arizona-ldo1",
0383 },
0384 };
0385
0386 static struct platform_driver madera_ldo1_driver = {
0387 .probe = madera_ldo1_probe,
0388 .remove = arizona_ldo1_remove,
0389 .driver = {
0390 .name = "madera-ldo1",
0391 },
0392 };
0393
0394 static struct platform_driver * const madera_ldo1_drivers[] = {
0395 &arizona_ldo1_driver,
0396 &madera_ldo1_driver,
0397 };
0398
0399 static int __init arizona_ldo1_init(void)
0400 {
0401 return platform_register_drivers(madera_ldo1_drivers,
0402 ARRAY_SIZE(madera_ldo1_drivers));
0403 }
0404 module_init(arizona_ldo1_init);
0405
0406 static void __exit madera_ldo1_exit(void)
0407 {
0408 platform_unregister_drivers(madera_ldo1_drivers,
0409 ARRAY_SIZE(madera_ldo1_drivers));
0410 }
0411 module_exit(madera_ldo1_exit);
0412
0413
0414 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
0415 MODULE_DESCRIPTION("Arizona LDO1 driver");
0416 MODULE_LICENSE("GPL");
0417 MODULE_ALIAS("platform:arizona-ldo1");
0418 MODULE_ALIAS("platform:madera-ldo1");