diff options
Diffstat (limited to 'drivers/regulator')
-rw-r--r-- | drivers/regulator/88pm800.c | 1 | ||||
-rw-r--r-- | drivers/regulator/Kconfig | 10 | ||||
-rw-r--r-- | drivers/regulator/Makefile | 1 | ||||
-rw-r--r-- | drivers/regulator/ab8500.c | 38 | ||||
-rw-r--r-- | drivers/regulator/act8865-regulator.c | 329 | ||||
-rw-r--r-- | drivers/regulator/arizona-ldo1.c | 2 | ||||
-rw-r--r-- | drivers/regulator/as3722-regulator.c | 6 | ||||
-rw-r--r-- | drivers/regulator/bcm590xx-regulator.c | 21 | ||||
-rw-r--r-- | drivers/regulator/core.c | 126 | ||||
-rw-r--r-- | drivers/regulator/da9211-regulator.c | 368 | ||||
-rw-r--r-- | drivers/regulator/da9211-regulator.h | 271 | ||||
-rw-r--r-- | drivers/regulator/lp872x.c | 9 | ||||
-rw-r--r-- | drivers/regulator/lp8755.c | 23 | ||||
-rw-r--r-- | drivers/regulator/ltc3589.c | 2 | ||||
-rw-r--r-- | drivers/regulator/max8952.c | 34 | ||||
-rw-r--r-- | drivers/regulator/mc13xxx-regulator-core.c | 37 | ||||
-rw-r--r-- | drivers/regulator/mc13xxx.h | 1 | ||||
-rw-r--r-- | drivers/regulator/palmas-regulator.c | 1106 | ||||
-rw-r--r-- | drivers/regulator/tps65218-regulator.c | 5 |
19 files changed, 1801 insertions, 589 deletions
diff --git a/drivers/regulator/88pm800.c b/drivers/regulator/88pm800.c index 7a721d67e6a..4e6c8c61190 100644 --- a/drivers/regulator/88pm800.c +++ b/drivers/regulator/88pm800.c @@ -52,7 +52,6 @@ #define PM800_BUCK1_3 (0x3F) #define PM800_BUCK2 (0x40) #define PM800_BUCK3 (0x41) -#define PM800_BUCK3 (0x41) #define PM800_BUCK4 (0x42) #define PM800_BUCK4_1 (0x43) #define PM800_BUCK4_2 (0x44) diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 789eb46090e..f5040fc49a3 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -198,6 +198,16 @@ config REGULATOR_DA9210 converter 12A DC-DC Buck controlled through an I2C interface. +config REGULATOR_DA9211 + tristate "Dialog Semiconductor DA9211/DA9212 regulator" + depends on I2C + select REGMAP_I2C + help + Say y here to support for the Dialog Semiconductor DA9211/DA9212. + The DA9211/DA9212 is a multi-phase synchronous step down + converter 12A DC-DC Buck controlled through an I2C + interface. + config REGULATOR_DBX500_PRCMU bool diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index d461110f446..aa4a6aa7b55 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o obj-$(CONFIG_REGULATOR_DA9055) += da9055-regulator.o obj-$(CONFIG_REGULATOR_DA9063) += da9063-regulator.o obj-$(CONFIG_REGULATOR_DA9210) += da9210-regulator.o +obj-$(CONFIG_REGULATOR_DA9211) += da9211-regulator.o obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o obj-$(CONFIG_REGULATOR_FAN53555) += fan53555.o diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index c625468c7f2..1fda14e12ea 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -3037,28 +3037,12 @@ static int ab8500_regulator_register(struct platform_device *pdev, return 0; } -static int -ab8500_regulator_of_probe(struct platform_device *pdev, - struct device_node *np) -{ - struct of_regulator_match *match = abx500_regulator.match; - int err, i; - - for (i = 0; i < abx500_regulator.info_size; i++) { - err = ab8500_regulator_register( - pdev, match[i].init_data, i, match[i].of_node); - if (err) - return err; - } - - return 0; -} - static int ab8500_regulator_probe(struct platform_device *pdev) { struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent); struct device_node *np = pdev->dev.of_node; - int err; + struct of_regulator_match *match; + int err, i; if (!ab8500) { dev_err(&pdev->dev, "null mfd parent\n"); @@ -3075,24 +3059,20 @@ static int ab8500_regulator_probe(struct platform_device *pdev) "Error parsing regulator init data: %d\n", err); return err; } - return ab8500_regulator_of_probe(pdev, np); -} - -static int ab8500_regulator_remove(struct platform_device *pdev) -{ - int err; - /* remove regulator debug */ - err = ab8500_regulator_debug_exit(pdev); - if (err) - return err; + match = abx500_regulator.match; + for (i = 0; i < abx500_regulator.info_size; i++) { + err = ab8500_regulator_register(pdev, match[i].init_data, i, + match[i].of_node); + if (err) + return err; + } return 0; } static struct platform_driver ab8500_regulator_driver = { .probe = ab8500_regulator_probe, - .remove = ab8500_regulator_remove, .driver = { .name = "ab8500-regulator", .owner = THIS_MODULE, diff --git a/drivers/regulator/act8865-regulator.c b/drivers/regulator/act8865-regulator.c index b92d7dd01a1..afd06f92dfd 100644 --- a/drivers/regulator/act8865-regulator.c +++ b/drivers/regulator/act8865-regulator.c @@ -1,6 +1,7 @@ /* - * act8865-regulator.c - Voltage regulation for the active-semi ACT8865 - * http://www.active-semi.com/sheets/ACT8865_Datasheet.pdf + * act8865-regulator.c - Voltage regulation for active-semi ACT88xx PMUs + * + * http://www.active-semi.com/products/power-management-units/act88xx/ * * Copyright (C) 2013 Atmel Corporation * @@ -28,6 +29,40 @@ #include <linux/regmap.h> /* + * ACT8846 Global Register Map. + */ +#define ACT8846_SYS0 0x00 +#define ACT8846_SYS1 0x01 +#define ACT8846_REG1_VSET 0x10 +#define ACT8846_REG1_CTRL 0x12 +#define ACT8846_REG2_VSET0 0x20 +#define ACT8846_REG2_VSET1 0x21 +#define ACT8846_REG2_CTRL 0x22 +#define ACT8846_REG3_VSET0 0x30 +#define ACT8846_REG3_VSET1 0x31 +#define ACT8846_REG3_CTRL 0x32 +#define ACT8846_REG4_VSET0 0x40 +#define ACT8846_REG4_VSET1 0x41 +#define ACT8846_REG4_CTRL 0x42 +#define ACT8846_REG5_VSET 0x50 +#define ACT8846_REG5_CTRL 0x51 +#define ACT8846_REG6_VSET 0x58 +#define ACT8846_REG6_CTRL 0x59 +#define ACT8846_REG7_VSET 0x60 +#define ACT8846_REG7_CTRL 0x61 +#define ACT8846_REG8_VSET 0x68 +#define ACT8846_REG8_CTRL 0x69 +#define ACT8846_REG9_VSET 0x70 +#define ACT8846_REG9_CTRL 0x71 +#define ACT8846_REG10_VSET 0x80 +#define ACT8846_REG10_CTRL 0x81 +#define ACT8846_REG11_VSET 0x90 +#define ACT8846_REG11_CTRL 0x91 +#define ACT8846_REG12_VSET 0xa0 +#define ACT8846_REG12_CTRL 0xa1 +#define ACT8846_REG13_CTRL 0xb1 + +/* * ACT8865 Global Register Map. */ #define ACT8865_SYS_MODE 0x00 @@ -70,7 +105,7 @@ static const struct regmap_config act8865_regmap_config = { .val_bits = 8, }; -static const struct regulator_linear_range act8865_volatge_ranges[] = { +static const struct regulator_linear_range act8865_voltage_ranges[] = { REGULATOR_LINEAR_RANGE(600000, 0, 23, 25000), REGULATOR_LINEAR_RANGE(1200000, 24, 47, 50000), REGULATOR_LINEAR_RANGE(2400000, 48, 63, 100000), @@ -86,114 +121,70 @@ static struct regulator_ops act8865_ops = { .is_enabled = regulator_is_enabled_regmap, }; -static const struct regulator_desc act8865_reg[] = { - { - .name = "DCDC_REG1", - .id = ACT8865_ID_DCDC1, - .ops = &act8865_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = ACT8865_VOLTAGE_NUM, - .linear_ranges = act8865_volatge_ranges, - .n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges), - .vsel_reg = ACT8865_DCDC1_VSET1, - .vsel_mask = ACT8865_VSEL_MASK, - .enable_reg = ACT8865_DCDC1_CTRL, - .enable_mask = ACT8865_ENA, - .owner = THIS_MODULE, - }, - { - .name = "DCDC_REG2", - .id = ACT8865_ID_DCDC2, - .ops = &act8865_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = ACT8865_VOLTAGE_NUM, - .linear_ranges = act8865_volatge_ranges, - .n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges), - .vsel_reg = ACT8865_DCDC2_VSET1, - .vsel_mask = ACT8865_VSEL_MASK, - .enable_reg = ACT8865_DCDC2_CTRL, - .enable_mask = ACT8865_ENA, - .owner = THIS_MODULE, - }, - { - .name = "DCDC_REG3", - .id = ACT8865_ID_DCDC3, - .ops = &act8865_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = ACT8865_VOLTAGE_NUM, - .linear_ranges = act8865_volatge_ranges, - .n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges), - .vsel_reg = ACT8865_DCDC3_VSET1, - .vsel_mask = ACT8865_VSEL_MASK, - .enable_reg = ACT8865_DCDC3_CTRL, - .enable_mask = ACT8865_ENA, - .owner = THIS_MODULE, - }, - { - .name = "LDO_REG1", - .id = ACT8865_ID_LDO1, - .ops = &act8865_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = ACT8865_VOLTAGE_NUM, - .linear_ranges = act8865_volatge_ranges, - .n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges), - .vsel_reg = ACT8865_LDO1_VSET, - .vsel_mask = ACT8865_VSEL_MASK, - .enable_reg = ACT8865_LDO1_CTRL, - .enable_mask = ACT8865_ENA, - .owner = THIS_MODULE, - }, - { - .name = "LDO_REG2", - .id = ACT8865_ID_LDO2, - .ops = &act8865_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = ACT8865_VOLTAGE_NUM, - .linear_ranges = act8865_volatge_ranges, - .n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges), - .vsel_reg = ACT8865_LDO2_VSET, - .vsel_mask = ACT8865_VSEL_MASK, - .enable_reg = ACT8865_LDO2_CTRL, - .enable_mask = ACT8865_ENA, - .owner = THIS_MODULE, - }, - { - .name = "LDO_REG3", - .id = ACT8865_ID_LDO3, - .ops = &act8865_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = ACT8865_VOLTAGE_NUM, - .linear_ranges = act8865_volatge_ranges, - .n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges), - .vsel_reg = ACT8865_LDO3_VSET, - .vsel_mask = ACT8865_VSEL_MASK, - .enable_reg = ACT8865_LDO3_CTRL, - .enable_mask = ACT8865_ENA, - .owner = THIS_MODULE, - }, - { - .name = "LDO_REG4", - .id = ACT8865_ID_LDO4, - .ops = &act8865_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = ACT8865_VOLTAGE_NUM, - .linear_ranges = act8865_volatge_ranges, - .n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges), - .vsel_reg = ACT8865_LDO4_VSET, - .vsel_mask = ACT8865_VSEL_MASK, - .enable_reg = ACT8865_LDO4_CTRL, - .enable_mask = ACT8865_ENA, - .owner = THIS_MODULE, - }, +#define ACT88xx_REG(_name, _family, _id, _vsel_reg) \ + [_family##_ID_##_id] = { \ + .name = _name, \ + .id = _family##_ID_##_id, \ + .type = REGULATOR_VOLTAGE, \ + .ops = &act8865_ops, \ + .n_voltages = ACT8865_VOLTAGE_NUM, \ + .linear_ranges = act8865_voltage_ranges, \ + .n_linear_ranges = ARRAY_SIZE(act8865_voltage_ranges), \ + .vsel_reg = _family##_##_id##_##_vsel_reg, \ + .vsel_mask = ACT8865_VSEL_MASK, \ + .enable_reg = _family##_##_id##_CTRL, \ + .enable_mask = ACT8865_ENA, \ + .owner = THIS_MODULE, \ + } + +static const struct regulator_desc act8846_regulators[] = { + ACT88xx_REG("REG1", ACT8846, REG1, VSET), + ACT88xx_REG("REG2", ACT8846, REG2, VSET0), + ACT88xx_REG("REG3", ACT8846, REG3, VSET0), + ACT88xx_REG("REG4", ACT8846, REG4, VSET0), + ACT88xx_REG("REG5", ACT8846, REG5, VSET), + ACT88xx_REG("REG6", ACT8846, REG6, VSET), + ACT88xx_REG("REG7", ACT8846, REG7, VSET), + ACT88xx_REG("REG8", ACT8846, REG8, VSET), + ACT88xx_REG("REG9", ACT8846, REG9, VSET), + ACT88xx_REG("REG10", ACT8846, REG10, VSET), + ACT88xx_REG("REG11", ACT8846, REG11, VSET), + ACT88xx_REG("REG12", ACT8846, REG12, VSET), +}; + +static const struct regulator_desc act8865_regulators[] = { + ACT88xx_REG("DCDC_REG1", ACT8865, DCDC1, VSET1), + ACT88xx_REG("DCDC_REG2", ACT8865, DCDC2, VSET1), + ACT88xx_REG("DCDC_REG3", ACT8865, DCDC3, VSET1), + ACT88xx_REG("LDO_REG1", ACT8865, LDO1, VSET), + ACT88xx_REG("LDO_REG2", ACT8865, LDO2, VSET), + ACT88xx_REG("LDO_REG3", ACT8865, LDO3, VSET), + ACT88xx_REG("LDO_REG4", ACT8865, LDO4, VSET), }; #ifdef CONFIG_OF static const struct of_device_id act8865_dt_ids[] = { - { .compatible = "active-semi,act8865" }, + { .compatible = "active-semi,act8846", .data = (void *)ACT8846 }, + { .compatible = "active-semi,act8865", .data = (void *)ACT8865 }, { } }; MODULE_DEVICE_TABLE(of, act8865_dt_ids); +static struct of_regulator_match act8846_matches[] = { + [ACT8846_ID_REG1] = { .name = "REG1" }, + [ACT8846_ID_REG2] = { .name = "REG2" }, + [ACT8846_ID_REG3] = { .name = "REG3" }, + [ACT8846_ID_REG4] = { .name = "REG4" }, + [ACT8846_ID_REG5] = { .name = "REG5" }, + [ACT8846_ID_REG6] = { .name = "REG6" }, + [ACT8846_ID_REG7] = { .name = "REG7" }, + [ACT8846_ID_REG8] = { .name = "REG8" }, + [ACT8846_ID_REG9] = { .name = "REG9" }, + [ACT8846_ID_REG10] = { .name = "REG10" }, + [ACT8846_ID_REG11] = { .name = "REG11" }, + [ACT8846_ID_REG12] = { .name = "REG12" }, +}; + static struct of_regulator_match act8865_matches[] = { [ACT8865_ID_DCDC1] = { .name = "DCDC_REG1"}, [ACT8865_ID_DCDC2] = { .name = "DCDC_REG2"}, @@ -206,11 +197,13 @@ static struct of_regulator_match act8865_matches[] = { static int act8865_pdata_from_dt(struct device *dev, struct device_node **of_node, - struct act8865_platform_data *pdata) + struct act8865_platform_data *pdata, + unsigned long type) { - int matched, i; + int matched, i, num_matches; struct device_node *np; struct act8865_regulator_data *regulator; + struct of_regulator_match *matches; np = of_get_child_by_name(dev->of_node, "regulators"); if (!np) { @@ -218,26 +211,39 @@ static int act8865_pdata_from_dt(struct device *dev, return -EINVAL; } - matched = of_regulator_match(dev, np, - act8865_matches, ARRAY_SIZE(act8865_matches)); + switch (type) { + case ACT8846: + matches = act8846_matches; + num_matches = ARRAY_SIZE(act8846_matches); + break; + case ACT8865: + matches = act8865_matches; + num_matches = ARRAY_SIZE(act8865_matches); + break; + default: + dev_err(dev, "invalid device id %lu\n", type); + return -EINVAL; + } + + matched = of_regulator_match(dev, np, matches, num_matches); of_node_put(np); if (matched <= 0) return matched; pdata->regulators = devm_kzalloc(dev, - sizeof(struct act8865_regulator_data) * - ARRAY_SIZE(act8865_matches), GFP_KERNEL); + sizeof(struct act8865_regulator_data) * + num_matches, GFP_KERNEL); if (!pdata->regulators) return -ENOMEM; - pdata->num_regulators = matched; + pdata->num_regulators = num_matches; regulator = pdata->regulators; - for (i = 0; i < ARRAY_SIZE(act8865_matches); i++) { + for (i = 0; i < num_matches; i++) { regulator->id = i; - regulator->name = act8865_matches[i].name; - regulator->platform_data = act8865_matches[i].init_data; - of_node[i] = act8865_matches[i].of_node; + regulator->name = matches[i].name; + regulator->platform_data = matches[i].init_data; + of_node[i] = matches[i].of_node; regulator++; } @@ -246,42 +252,84 @@ static int act8865_pdata_from_dt(struct device *dev, #else static inline int act8865_pdata_from_dt(struct device *dev, struct device_node **of_node, - struct act8865_platform_data *pdata) + struct act8865_platform_data *pdata, + unsigned long type) { return 0; } #endif +static struct regulator_init_data +*act8865_get_init_data(int id, struct act8865_platform_data *pdata) +{ + int i; + + if (!pdata) + return NULL; + + for (i = 0; i < pdata->num_regulators; i++) { + if (pdata->regulators[i].id == id) + return pdata->regulators[i].platform_data; + } + + return NULL; +} + static int act8865_pmic_probe(struct i2c_client *client, - const struct i2c_device_id *i2c_id) + const struct i2c_device_id *i2c_id) { - struct regulator_dev *rdev; + static const struct regulator_desc *regulators; + struct act8865_platform_data pdata_of, *pdata; struct device *dev = &client->dev; - struct act8865_platform_data *pdata = dev_get_platdata(dev); - struct regulator_config config = { }; + struct device_node **of_node; + int i, ret, num_regulators; struct act8865 *act8865; - struct device_node *of_node[ACT8865_REG_NUM]; - int i, id; - int ret = -EINVAL; - int error; + unsigned long type; + + pdata = dev_get_platdata(dev); if (dev->of_node && !pdata) { const struct of_device_id *id; - struct act8865_platform_data pdata_of; id = of_match_device(of_match_ptr(act8865_dt_ids), dev); if (!id) return -ENODEV; - ret = act8865_pdata_from_dt(dev, of_node, &pdata_of); + type = (unsigned long) id->data; + } else { + type = i2c_id->driver_data; + } + + switch (type) { + case ACT8846: + regulators = act8846_regulators; + num_regulators = ARRAY_SIZE(act8846_regulators); + break; + case ACT8865: + regulators = act8865_regulators; + num_regulators = ARRAY_SIZE(act8865_regulators); + break; + default: + dev_err(dev, "invalid device id %lu\n", type); + return -EINVAL; + } + + of_node = devm_kzalloc(dev, sizeof(struct device_node *) * + num_regulators, GFP_KERNEL); + if (!of_node) + return -ENOMEM; + + if (dev->of_node && !pdata) { + ret = act8865_pdata_from_dt(dev, of_node, &pdata_of, type); if (ret < 0) return ret; pdata = &pdata_of; } - if (pdata->num_regulators > ACT8865_REG_NUM) { - dev_err(dev, "Too many regulators found!\n"); + if (pdata->num_regulators > num_regulators) { + dev_err(dev, "too many regulators: %d\n", + pdata->num_regulators); return -EINVAL; } @@ -291,39 +339,40 @@ static int act8865_pmic_probe(struct i2c_client *client, act8865->regmap = devm_regmap_init_i2c(client, &act8865_regmap_config); if (IS_ERR(act8865->regmap)) { - error = PTR_ERR(act8865->regmap); + ret = PTR_ERR(act8865->regmap); dev_err(&client->dev, "Failed to allocate register map: %d\n", - error); - return error; + ret); + return ret; } /* Finally register devices */ - for (i = 0; i < ACT8865_REG_NUM; i++) { - - id = pdata->regulators[i].id; + for (i = 0; i < num_regulators; i++) { + const struct regulator_desc *desc = ®ulators[i]; + struct regulator_config config = { }; + struct regulator_dev *rdev; config.dev = dev; - config.init_data = pdata->regulators[i].platform_data; + config.init_data = act8865_get_init_data(desc->id, pdata); config.of_node = of_node[i]; config.driver_data = act8865; config.regmap = act8865->regmap; - rdev = devm_regulator_register(&client->dev, &act8865_reg[i], - &config); + rdev = devm_regulator_register(&client->dev, desc, &config); if (IS_ERR(rdev)) { - dev_err(dev, "failed to register %s\n", - act8865_reg[id].name); + dev_err(dev, "failed to register %s\n", desc->name); return PTR_ERR(rdev); } } i2c_set_clientdata(client, act8865); + devm_kfree(dev, of_node); return 0; } static const struct i2c_device_id act8865_ids[] = { - { "act8865", 0 }, + { .name = "act8846", .driver_data = ACT8846 }, + { .name = "act8865", .driver_data = ACT8865 }, { }, }; MODULE_DEVICE_TABLE(i2c, act8865_ids); @@ -339,6 +388,6 @@ static struct i2c_driver act8865_pmic_driver = { module_i2c_driver(act8865_pmic_driver); -MODULE_DESCRIPTION("active-semi act8865 voltage regulator driver"); +MODULE_DESCRIPTION("active-semi act88xx voltage regulator driver"); MODULE_AUTHOR("Wenyou Yang <wenyou.yang@atmel.com>"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c index 04f262a836b..4c9db589f6c 100644 --- a/drivers/regulator/arizona-ldo1.c +++ b/drivers/regulator/arizona-ldo1.c @@ -143,8 +143,6 @@ static struct regulator_ops arizona_ldo1_ops = { .map_voltage = regulator_map_voltage_linear, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, - .get_bypass = regulator_get_bypass_regmap, - .set_bypass = regulator_set_bypass_regmap, }; static const struct regulator_desc arizona_ldo1 = { diff --git a/drivers/regulator/as3722-regulator.c b/drivers/regulator/as3722-regulator.c index 85585219ce8..b68f05f3853 100644 --- a/drivers/regulator/as3722-regulator.c +++ b/drivers/regulator/as3722-regulator.c @@ -219,7 +219,7 @@ static const struct as3722_register_mapping as3722_reg_lookup[] = { { .regulator_id = AS3722_REGULATOR_ID_LDO3, .name = "as3722-ldo3", - .name = "vin-ldo3-4", + .sname = "vin-ldo3-4", .vsel_reg = AS3722_LDO3_VOLTAGE_REG, .vsel_mask = AS3722_LDO3_VSEL_MASK, .enable_reg = AS3722_LDOCONTROL0_REG, @@ -231,7 +231,7 @@ static const struct as3722_register_mapping as3722_reg_lookup[] = { { .regulator_id = AS3722_REGULATOR_ID_LDO4, .name = "as3722-ldo4", - .name = "vin-ldo3-4", + .sname = "vin-ldo3-4", .vsel_reg = AS3722_LDO4_VOLTAGE_REG, .vsel_mask = AS3722_LDO_VSEL_MASK, .enable_reg = AS3722_LDOCONTROL0_REG, @@ -433,6 +433,7 @@ static struct regulator_ops as3722_ldo3_extcntrl_ops = { }; static const struct regulator_linear_range as3722_ldo_ranges[] = { + REGULATOR_LINEAR_RANGE(0, 0x00, 0x00, 0), REGULATOR_LINEAR_RANGE(825000, 0x01, 0x24, 25000), REGULATOR_LINEAR_RANGE(1725000, 0x40, 0x7F, 25000), }; @@ -609,6 +610,7 @@ static bool as3722_sd0_is_low_voltage(struct as3722_regulators *as3722_regs) } static const struct regulator_linear_range as3722_sd2345_ranges[] = { + REGULATOR_LINEAR_RANGE(0, 0x00, 0x00, 0), REGULATOR_LINEAR_RANGE(612500, 0x01, 0x40, 12500), REGULATOR_LINEAR_RANGE(1425000, 0x41, 0x70, 25000), REGULATOR_LINEAR_RANGE(2650000, 0x71, 0x7F, 50000), diff --git a/drivers/regulator/bcm590xx-regulator.c b/drivers/regulator/bcm590xx-regulator.c index 57544e254a7..5d1fd6f3d10 100644 --- a/drivers/regulator/bcm590xx-regulator.c +++ b/drivers/regulator/bcm590xx-regulator.c @@ -119,6 +119,10 @@ static const unsigned int ldo_c_table[] = { 2900000, 3000000, 3300000, }; +static const unsigned int ldo_vbus[] = { + 5000000, +}; + /* DCDC group CSR: supported voltages in microvolts */ static const struct regulator_linear_range dcdc_csr_ranges[] = { REGULATOR_LINEAR_RANGE(860000, 2, 50, 10000), @@ -192,6 +196,7 @@ static struct bcm590xx_info bcm590xx_regs[] = { BCM590XX_REG_TABLE(gpldo4, ldo_a_table), BCM590XX_REG_TABLE(gpldo5, ldo_a_table), BCM590XX_REG_TABLE(gpldo6, ldo_a_table), + BCM590XX_REG_TABLE(vbus, ldo_vbus), }; struct bcm590xx_reg { @@ -326,10 +331,8 @@ static struct bcm590xx_board *bcm590xx_parse_dt_reg_data( } data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); - if (!data) { - dev_err(&pdev->dev, "failed to allocate regulator board data\n"); + if (!data) return NULL; - } np = of_node_get(np); regulators = of_get_child_by_name(np, "regulators"); @@ -374,10 +377,8 @@ static int bcm590xx_probe(struct platform_device *pdev) &bcm590xx_reg_matches); pmu = devm_kzalloc(&pdev->dev, sizeof(*pmu), GFP_KERNEL); - if (!pmu) { - dev_err(&pdev->dev, "Memory allocation failed for pmu\n"); + if (!pmu) return -ENOMEM; - } pmu->mfd = bcm590xx; @@ -385,17 +386,13 @@ static int bcm590xx_probe(struct platform_device *pdev) pmu->desc = devm_kzalloc(&pdev->dev, BCM590XX_NUM_REGS * sizeof(struct regulator_desc), GFP_KERNEL); - if (!pmu->desc) { - dev_err(&pdev->dev, "Memory alloc fails for desc\n"); + if (!pmu->desc) return -ENOMEM; - } pmu->info = devm_kzalloc(&pdev->dev, BCM590XX_NUM_REGS * sizeof(struct bcm590xx_info *), GFP_KERNEL); - if (!pmu->info) { - dev_err(&pdev->dev, "Memory alloc fails for info\n"); + if (!pmu->info) return -ENOMEM; - } info = bcm590xx_regs; diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 4c1f999041d..a3c3785901f 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -24,6 +24,7 @@ #include <linux/suspend.h> #include <linux/delay.h> #include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/of.h> #include <linux/regmap.h> #include <linux/regulator/of_regulator.h> @@ -77,7 +78,7 @@ struct regulator_map { */ struct regulator_enable_gpio { struct list_head list; - int gpio; + struct gpio_desc *gpiod; u32 enable_count; /* a number of enabled shared GPIO */ u32 request_count; /* a number of requested shared GPIO */ unsigned int ena_gpio_invert:1; @@ -846,7 +847,9 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, rdev->constraints->min_uV == rdev->constraints->max_uV) { int current_uV = _regulator_get_voltage(rdev); if (current_uV < 0) { - rdev_err(rdev, "failed to get the current voltage\n"); + rdev_err(rdev, + "failed to get the current voltage(%d)\n", + current_uV); return current_uV; } if (current_uV < rdev->constraints->min_uV || @@ -856,8 +859,8 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, rdev->constraints->max_uV); if (ret < 0) { rdev_err(rdev, - "failed to apply %duV constraint\n", - rdev->constraints->min_uV); + "failed to apply %duV constraint(%d)\n", + rdev->constraints->min_uV, ret); return ret; } } @@ -1660,10 +1663,13 @@ static int regulator_ena_gpio_request(struct regulator_dev *rdev, const struct regulator_config *config) { struct regulator_enable_gpio *pin; + struct gpio_desc *gpiod; int ret; + gpiod = gpio_to_desc(config->ena_gpio); + list_for_each_entry(pin, ®ulator_ena_gpio_list, list) { - if (pin->gpio == config->ena_gpio) { + if (pin->gpiod == gpiod) { rdev_dbg(rdev, "GPIO %d is already used\n", config->ena_gpio); goto update_ena_gpio_to_rdev; @@ -1682,7 +1688,7 @@ static int regulator_ena_gpio_request(struct regulator_dev *rdev, return -ENOMEM; } - pin->gpio = config->ena_gpio; + pin->gpiod = gpiod; pin->ena_gpio_invert = config->ena_gpio_invert; list_add(&pin->list, ®ulator_ena_gpio_list); @@ -1701,10 +1707,10 @@ static void regulator_ena_gpio_free(struct regulator_dev *rdev) /* Free the GPIO only in case of no use */ list_for_each_entry_safe(pin, n, ®ulator_ena_gpio_list, list) { - if (pin->gpio == rdev->ena_pin->gpio) { + if (pin->gpiod == rdev->ena_pin->gpiod) { if (pin->request_count <= 1) { pin->request_count = 0; - gpio_free(pin->gpio); + gpiod_put(pin->gpiod); list_del(&pin->list); kfree(pin); } else { @@ -1732,8 +1738,8 @@ static int regulator_ena_gpio_ctrl(struct regulator_dev *rdev, bool enable) if (enable) { /* Enable GPIO at initial use */ if (pin->enable_count == 0) - gpio_set_value_cansleep(pin->gpio, - !pin->ena_gpio_invert); + gpiod_set_value_cansleep(pin->gpiod, + !pin->ena_gpio_invert); pin->enable_count++; } else { @@ -1744,8 +1750,8 @@ static int regulator_ena_gpio_ctrl(struct regulator_dev *rdev, bool enable) /* Disable GPIO if not used */ if (pin->enable_count <= 1) { - gpio_set_value_cansleep(pin->gpio, - pin->ena_gpio_invert); + gpiod_set_value_cansleep(pin->gpiod, + pin->ena_gpio_invert); pin->enable_count = 0; } } @@ -2180,7 +2186,13 @@ int regulator_count_voltages(struct regulator *regulator) { struct regulator_dev *rdev = regulator->rdev; - return rdev->desc->n_voltages ? : -EINVAL; + if (rdev->desc->n_voltages) + return rdev->desc->n_voltages; + + if (!rdev->supply) + return -EINVAL; + + return regulator_count_voltages(rdev->supply); } EXPORT_SYMBOL_GPL(regulator_count_voltages); @@ -2203,12 +2215,17 @@ int regulator_list_voltage(struct regulator *regulator, unsigned selector) if (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1 && !selector) return rdev->desc->fixed_uV; - if (!ops->list_voltage || selector >= rdev->desc->n_voltages) + if (ops->list_voltage) { + if (selector >= rdev->desc->n_voltages) + return -EINVAL; + mutex_lock(&rdev->mutex); + ret = ops->list_voltage(rdev, selector); + mutex_unlock(&rdev->mutex); + } else if (rdev->supply) { + ret = regulator_list_voltage(rdev->supply, selector); + } else { return -EINVAL; - - mutex_lock(&rdev->mutex); - ret = ops->list_voltage(rdev, selector); - mutex_unlock(&rdev->mutex); + } if (ret > 0) { if (ret < rdev->constraints->min_uV) @@ -2222,6 +2239,77 @@ int regulator_list_voltage(struct regulator *regulator, unsigned selector) EXPORT_SYMBOL_GPL(regulator_list_voltage); /** + * regulator_get_regmap - get the regulator's register map + * @regulator: regulator source + * + * Returns the register map for the given regulator, or an ERR_PTR value + * if the regulator doesn't use regmap. + */ +struct regmap *regulator_get_regmap(struct regulator *regulator) +{ + struct regmap *map = regulator->rdev->regmap; + + return map ? map : ERR_PTR(-EOPNOTSUPP); +} + +/** + * regulator_get_hardware_vsel_register - get the HW voltage selector register + * @regulator: regulator source + * @vsel_reg: voltage selector register, output parameter + * @vsel_mask: mask for voltage selector bitfield, output parameter + * + * Returns the hardware register offset and bitmask used for setting the + * regulator voltage. This might be useful when configuring voltage-scaling + * hardware or firmware that can make I2C requests behind the kernel's back, + * for example. + * + * On success, the output parameters @vsel_reg and @vsel_mask are filled in + * and 0 is returned, otherwise a negative errno is returned. + */ +int regulator_get_hardware_vsel_register(struct regulator *regulator, + unsigned *vsel_reg, + unsigned *vsel_mask) +{ + struct regulator_dev *rdev = regulator->rdev; + struct regulator_ops *ops = rdev->desc->ops; + + if (ops->set_voltage_sel != regulator_set_voltage_sel_regmap) + return -EOPNOTSUPP; + + *vsel_reg = rdev->desc->vsel_reg; + *vsel_mask = rdev->desc->vsel_mask; + + return 0; +} +EXPORT_SYMBOL_GPL(regulator_get_hardware_vsel_register); + +/** + * regulator_list_hardware_vsel - get the HW-specific register value for a selector + * @regulator: regulator source + * @selector: identify voltage to list + * + * Converts the selector to a hardware-specific voltage selector that can be + * directly written to the regulator registers. The address of the voltage + * register can be determined by calling @regulator_get_hardware_vsel_register. + * + * On error a negative errno is returned. + */ +int regulator_list_hardware_vsel(struct regulator *regulator, + unsigned selector) +{ + struct regulator_dev *rdev = regulator->rdev; + struct regulator_ops *ops = rdev->desc->ops; + + if (selector >= rdev->desc->n_voltages) + return -EINVAL; + if (ops->set_voltage_sel != regulator_set_voltage_sel_regmap) + return -EOPNOTSUPP; + + return selector; +} +EXPORT_SYMBOL_GPL(regulator_list_hardware_vsel); + +/** * regulator_get_linear_step - return the voltage step size between VSEL values * @regulator: regulator source * @@ -2618,6 +2706,8 @@ static int _regulator_get_voltage(struct regulator_dev *rdev) ret = rdev->desc->ops->list_voltage(rdev, 0); } else if (rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1)) { ret = rdev->desc->fixed_uV; + } else if (rdev->supply) { + ret = regulator_get_voltage(rdev->supply); } else { return -EINVAL; } diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c new file mode 100644 index 00000000000..1482adafa1a --- /dev/null +++ b/drivers/regulator/da9211-regulator.c @@ -0,0 +1,368 @@ +/* + * da9211-regulator.c - Regulator device driver for DA9211 + * Copyright (C) 2014 Dialog Semiconductor Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + */ + +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regmap.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/regulator/da9211.h> +#include "da9211-regulator.h" + +#define DA9211_BUCK_MODE_SLEEP 1 +#define DA9211_BUCK_MODE_SYNC 2 +#define DA9211_BUCK_MODE_AUTO 3 + +/* DA9211 REGULATOR IDs */ +#define DA9211_ID_BUCKA 0 +#define DA9211_ID_BUCKB 1 + +struct da9211 { + struct device *dev; + struct regmap *regmap; + struct da9211_pdata *pdata; + struct regulator_dev *rdev[DA9211_MAX_REGULATORS]; + int num_regulator; + int chip_irq; +}; + +static const struct regmap_range_cfg da9211_regmap_range[] = { + { + .selector_reg = DA9211_REG_PAGE_CON, + .selector_mask = DA9211_REG_PAGE_MASK, + .selector_shift = DA9211_REG_PAGE_SHIFT, + .window_start = 0, + .window_len = 256, + .range_min = 0, + .range_max = 2*256, + }, +}; + +static const struct regmap_config da9211_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 2 * 256, + .ranges = da9211_regmap_range, + .num_ranges = ARRAY_SIZE(da9211_regmap_range), +}; + +/* Default limits measured in millivolts and milliamps */ +#define DA9211_MIN_MV 300 +#define DA9211_MAX_MV 1570 +#define DA9211_STEP_MV 10 + +/* Current limits for buck (uA) indices corresponds with register values */ +static const int da9211_current_limits[] = { + 2000000, 2200000, 2400000, 2600000, 2800000, 3000000, 3200000, 3400000, + 3600000, 3800000, 4000000, 4200000, 4400000, 4600000, 4800000, 5000000 +}; + +static unsigned int da9211_buck_get_mode(struct regulator_dev *rdev) +{ + int id = rdev_get_id(rdev); + struct da9211 *chip = rdev_get_drvdata(rdev); + unsigned int data; + int ret, mode = 0; + + ret = regmap_read(chip->regmap, DA9211_REG_BUCKA_CONF+id, &data); + if (ret < 0) + return ret; + + switch (data & 0x03) { + case DA9211_BUCK_MODE_SYNC: + mode = REGULATOR_MODE_FAST; + break; + case DA9211_BUCK_MODE_AUTO: + mode = REGULATOR_MODE_NORMAL; + break; + case DA9211_BUCK_MODE_SLEEP: + mode = REGULATOR_MODE_STANDBY; + break; + } + + return mode; +} + +static int da9211_buck_set_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + int id = rdev_get_id(rdev); + struct da9211 *chip = rdev_get_drvdata(rdev); + int val = 0; + + switch (mode) { + case REGULATOR_MODE_FAST: + val = DA9211_BUCK_MODE_SYNC; + break; + case REGULATOR_MODE_NORMAL: + val = DA9211_BUCK_MODE_AUTO; + break; + case REGULATOR_MODE_STANDBY: + val = DA9211_BUCK_MODE_SLEEP; + break; + } + + return regmap_update_bits(chip->regmap, DA9211_REG_BUCKA_CONF+id, + 0x03, val); +} + +static int da9211_set_current_limit(struct regulator_dev *rdev, int min, + int max) +{ + int id = rdev_get_id(rdev); + struct da9211 *chip = rdev_get_drvdata(rdev); + int i; + + /* search for closest to maximum */ + for (i = ARRAY_SIZE(da9211_current_limits)-1; i >= 0; i--) { + if (min <= da9211_current_limits[i] && + max >= da9211_current_limits[i]) { + return regmap_update_bits(chip->regmap, + DA9211_REG_BUCK_ILIM, + (0x0F << id*4), (i << id*4)); + } + } + + return -EINVAL; +} + +static int da9211_get_current_limit(struct regulator_dev *rdev) +{ + int id = rdev_get_id(rdev); + struct da9211 *chip = rdev_get_drvdata(rdev); + unsigned int data; + int ret; + + ret = regmap_read(chip->regmap, DA9211_REG_BUCK_ILIM, &data); + if (ret < 0) + return ret; + + /* select one of 16 values: 0000 (2000mA) to 1111 (5000mA) */ + data = (data >> id*4) & 0x0F; + return da9211_current_limits[data]; +} + +static struct regulator_ops da9211_buck_ops = { + .get_mode = da9211_buck_get_mode, + .set_mode = da9211_buck_set_mode, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear, + .set_current_limit = da9211_set_current_limit, + .get_current_limit = da9211_get_current_limit, +}; + +#define DA9211_BUCK(_id) \ +{\ + .name = #_id,\ + .ops = &da9211_buck_ops,\ + .type = REGULATOR_VOLTAGE,\ + .id = DA9211_ID_##_id,\ + .n_voltages = (DA9211_MAX_MV - DA9211_MIN_MV) / DA9211_STEP_MV + 1,\ + .min_uV = (DA9211_MIN_MV * 1000),\ + .uV_step = (DA9211_STEP_MV * 1000),\ + .enable_reg = DA9211_REG_BUCKA_CONT + DA9211_ID_##_id,\ + .enable_mask = DA9211_BUCKA_EN,\ + .vsel_reg = DA9211_REG_VBUCKA_A + DA9211_ID_##_id * 2,\ + .vsel_mask = DA9211_VBUCK_MASK,\ + .owner = THIS_MODULE,\ +} + +static struct regulator_desc da9211_regulators[] = { + DA9211_BUCK(BUCKA), + DA9211_BUCK(BUCKB), +}; + +static irqreturn_t da9211_irq_handler(int irq, void *data) +{ + struct da9211 *chip = data; + int reg_val, err, ret = IRQ_NONE; + + err = regmap_read(chip->regmap, DA9211_REG_EVENT_B, ®_val); + if (err < 0) + goto error_i2c; + + if (reg_val & DA9211_E_OV_CURR_A) { + regulator_notifier_call_chain(chip->rdev[0], + REGULATOR_EVENT_OVER_CURRENT, + rdev_get_drvdata(chip->rdev[0])); + + err = regmap_write(chip->regmap, DA9211_REG_EVENT_B, + DA9211_E_OV_CURR_A); + if (err < 0) + goto error_i2c; + + ret = IRQ_HANDLED; + } + + if (reg_val & DA9211_E_OV_CURR_B) { + regulator_notifier_call_chain(chip->rdev[1], + REGULATOR_EVENT_OVER_CURRENT, + rdev_get_drvdata(chip->rdev[1])); + + err = regmap_write(chip->regmap, DA9211_REG_EVENT_B, + DA9211_E_OV_CURR_B); + if (err < 0) + goto error_i2c; + + ret = IRQ_HANDLED; + } + + return ret; + +error_i2c: + dev_err(chip->dev, "I2C error : %d\n", err); + return IRQ_NONE; +} + +static int da9211_regulator_init(struct da9211 *chip) +{ + struct regulator_config config = { }; + int i, ret; + unsigned int data; + + ret = regmap_read(chip->regmap, DA9211_REG_CONFIG_E, &data); + if (ret < 0) { + dev_err(chip->dev, "Failed to read CONTROL_E reg: %d\n", ret); + return ret; + } + + data &= DA9211_SLAVE_SEL; + /* If configuration for 1/2 bucks is different between platform data + * and the register, driver should exit. + */ + if ((chip->pdata->num_buck == 2 && data == 0x40) + || (chip->pdata->num_buck == 1 && data == 0x00)) { + if (data == 0) + chip->num_regulator = 1; + else + chip->num_regulator = 2; + } else { + dev_err(chip->dev, "Configuration is mismatched\n"); + return -EINVAL; + } + + for (i = 0; i < chip->num_regulator; i++) { + if (chip->pdata) + config.init_data = + &(chip->pdata->init_data[i]); + + config.dev = chip->dev; + config.driver_data = chip; + config.regmap = chip->regmap; + + chip->rdev[i] = devm_regulator_register(chip->dev, + &da9211_regulators[i], &config); + if (IS_ERR(chip->rdev[i])) { + dev_err(chip->dev, + "Failed to register DA9211 regulator\n"); + return PTR_ERR(chip->rdev[i]); + } + + if (chip->chip_irq != 0) { + ret = regmap_update_bits(chip->regmap, + DA9211_REG_MASK_B, DA9211_M_OV_CURR_A << i, 1); + if (ret < 0) { + dev_err(chip->dev, + "Failed to update mask reg: %d\n", ret); + return ret; + } + } + } + + return 0; +} +/* + * I2C driver interface functions + */ +static int da9211_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct da9211 *chip; + int error, ret; + + chip = devm_kzalloc(&i2c->dev, sizeof(struct da9211), GFP_KERNEL); + + chip->dev = &i2c->dev; + chip->regmap = devm_regmap_init_i2c(i2c, &da9211_regmap_config); + if (IS_ERR(chip->regmap)) { + error = PTR_ERR(chip->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + error); + return error; + } + + i2c_set_clientdata(i2c, chip); + + chip->pdata = i2c->dev.platform_data; + if (!chip->pdata) { + dev_err(&i2c->dev, "No platform init data supplied\n"); + return -ENODEV; + } + + chip->chip_irq = i2c->irq; + + if (chip->chip_irq != 0) { + ret = devm_request_threaded_irq(chip->dev, chip->chip_irq, NULL, + da9211_irq_handler, + IRQF_TRIGGER_LOW|IRQF_ONESHOT, + "da9211", chip); + if (ret != 0) { + dev_err(chip->dev, "Failed to request IRQ: %d\n", + chip->chip_irq); + return ret; + } + } else { + dev_warn(chip->dev, "No IRQ configured\n"); + } + + ret = da9211_regulator_init(chip); + + if (ret < 0) + dev_err(&i2c->dev, "Failed to initialize regulator: %d\n", ret); + + return ret; +} + +static const struct i2c_device_id da9211_i2c_id[] = { + {"da9211", 0}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, da9211_i2c_id); + +static struct i2c_driver da9211_regulator_driver = { + .driver = { + .name = "da9211", + .owner = THIS_MODULE, + }, + .probe = da9211_i2c_probe, + .id_table = da9211_i2c_id, +}; + +module_i2c_driver(da9211_regulator_driver); + +MODULE_AUTHOR("James Ban <James.Ban.opensource@diasemi.com>"); +MODULE_DESCRIPTION("Regulator device driver for Dialog DA9211"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/da9211-regulator.h b/drivers/regulator/da9211-regulator.h new file mode 100644 index 00000000000..88b1769e805 --- /dev/null +++ b/drivers/regulator/da9211-regulator.h @@ -0,0 +1,271 @@ +/* + * da9211-regulator.h - Regulator definitions for DA9211 + * Copyright (C) 2014 Dialog Semiconductor Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + */ + +#ifndef __DA9211_REGISTERS_H__ +#define __DA9211_REGISTERS_H__ + +/* Page selection */ +#define DA9211_REG_PAGE_CON 0x00 + +/* System Control and Event Registers */ +#define DA9211_REG_STATUS_A 0x50 +#define DA9211_REG_STATUS_B 0x51 +#define DA9211_REG_EVENT_A 0x52 +#define DA9211_REG_EVENT_B 0x53 +#define DA9211_REG_MASK_A 0x54 +#define DA9211_REG_MASK_B 0x55 +#define DA9211_REG_CONTROL_A 0x56 + +/* GPIO Control Registers */ +#define DA9211_REG_GPIO_0_1 0x58 +#define DA9211_REG_GPIO_2_3 0x59 +#define DA9211_REG_GPIO_4 0x5A + +/* Regulator Registers */ +#define DA9211_REG_BUCKA_CONT 0x5D +#define DA9211_REG_BUCKB_CONT 0x5E +#define DA9211_REG_BUCK_ILIM 0xD0 +#define DA9211_REG_BUCKA_CONF 0xD1 +#define DA9211_REG_BUCKB_CONF 0xD2 +#define DA9211_REG_BUCK_CONF 0xD3 +#define DA9211_REG_VBACKA_MAX 0xD5 +#define DA9211_REG_VBACKB_MAX 0xD6 +#define DA9211_REG_VBUCKA_A 0xD7 +#define DA9211_REG_VBUCKA_B 0xD8 +#define DA9211_REG_VBUCKB_A 0xD9 +#define DA9211_REG_VBUCKB_B 0xDA + +/* I2C Interface Settings */ +#define DA9211_REG_INTERFACE 0x105 + +/* BUCK Phase Selection*/ +#define DA9211_REG_CONFIG_E 0x147 + +/* + * Registers bits + */ +/* DA9211_REG_PAGE_CON (addr=0x00) */ +#define DA9211_REG_PAGE_SHIFT 1 +#define DA9211_REG_PAGE_MASK 0x02 +/* On I2C registers 0x00 - 0xFF */ +#define DA9211_REG_PAGE0 0 +/* On I2C registers 0x100 - 0x1FF */ +#define DA9211_REG_PAGE2 2 +#define DA9211_PAGE_WRITE_MODE 0x00 +#define DA9211_REPEAT_WRITE_MODE 0x40 +#define DA9211_PAGE_REVERT 0x80 + +/* DA9211_REG_STATUS_A (addr=0x50) */ +#define DA9211_GPI0 0x01 +#define DA9211_GPI1 0x02 +#define DA9211_GPI2 0x04 +#define DA9211_GPI3 0x08 +#define DA9211_GPI4 0x10 + +/* DA9211_REG_EVENT_A (addr=0x52) */ +#define DA9211_E_GPI0 0x01 +#define DA9211_E_GPI1 0x02 +#define DA9211_E_GPI2 0x04 +#define DA9211_E_GPI3 0x08 +#define DA9211_E_GPI4 0x10 +#define DA9211_E_UVLO_IO 0x40 + +/* DA9211_REG_EVENT_B (addr=0x53) */ +#define DA9211_E_PWRGOOD_A 0x01 +#define DA9211_E_PWRGOOD_B 0x02 +#define DA9211_E_TEMP_WARN 0x04 +#define DA9211_E_TEMP_CRIT 0x08 +#define DA9211_E_OV_CURR_A 0x10 +#define DA9211_E_OV_CURR_B 0x20 + +/* DA9211_REG_MASK_A (addr=0x54) */ +#define DA9211_M_GPI0 0x01 +#define DA9211_M_GPI1 0x02 +#define DA9211_M_GPI2 0x04 +#define DA9211_M_GPI3 0x08 +#define DA9211_M_GPI4 0x10 +#define DA9211_M_UVLO_IO 0x40 + +/* DA9211_REG_MASK_B (addr=0x55) */ +#define DA9211_M_PWRGOOD_A 0x01 +#define DA9211_M_PWRGOOD_B 0x02 +#define DA9211_M_TEMP_WARN 0x04 +#define DA9211_M_TEMP_CRIT 0x08 +#define DA9211_M_OV_CURR_A 0x10 +#define DA9211_M_OV_CURR_B 0x20 + +/* DA9211_REG_CONTROL_A (addr=0x56) */ +#define DA9211_DEBOUNCING_SHIFT 0 +#define DA9211_DEBOUNCING_MASK 0x07 +#define DA9211_SLEW_RATE_SHIFT 3 +#define DA9211_SLEW_RATE_A_MASK 0x18 +#define DA9211_SLEW_RATE_B_SHIFT 5 +#define DA9211_SLEW_RATE_B_MASK 0x60 +#define DA9211_V_LOCK 0x80 + +/* DA9211_REG_GPIO_0_1 (addr=0x58) */ +#define DA9211_GPIO0_PIN_SHIFT 0 +#define DA9211_GPIO0_PIN_MASK 0x03 +#define DA9211_GPIO0_PIN_GPI 0x00 +#define DA9211_GPIO0_PIN_GPO_OD 0x02 +#define DA9211_GPIO0_PIN_GPO 0x03 +#define DA9211_GPIO0_TYPE 0x04 +#define DA9211_GPIO0_TYPE_GPI 0x00 +#define DA9211_GPIO0_TYPE_GPO 0x04 +#define DA9211_GPIO0_MODE 0x08 +#define DA9211_GPIO1_PIN_SHIFT 4 +#define DA9211_GPIO1_PIN_MASK 0x30 +#define DA9211_GPIO1_PIN_GPI 0x00 +#define DA9211_GPIO1_PIN_VERROR 0x10 +#define DA9211_GPIO1_PIN_GPO_OD 0x20 +#define DA9211_GPIO1_PIN_GPO 0x30 +#define DA9211_GPIO1_TYPE_SHIFT 0x40 +#define DA9211_GPIO1_TYPE_GPI 0x00 +#define DA9211_GPIO1_TYPE_GPO 0x40 +#define DA9211_GPIO1_MODE 0x80 + +/* DA9211_REG_GPIO_2_3 (addr=0x59) */ +#define DA9211_GPIO2_PIN_SHIFT 0 +#define DA9211_GPIO2_PIN_MASK 0x03 +#define DA9211_GPIO2_PIN_GPI 0x00 +#define DA9211_GPIO5_PIN_BUCK_CLK 0x10 +#define DA9211_GPIO2_PIN_GPO_OD 0x02 +#define DA9211_GPIO2_PIN_GPO 0x03 +#define DA9211_GPIO2_TYPE 0x04 +#define DA9211_GPIO2_TYPE_GPI 0x00 +#define DA9211_GPIO2_TYPE_GPO 0x04 +#define DA9211_GPIO2_MODE 0x08 +#define DA9211_GPIO3_PIN_SHIFT 4 +#define DA9211_GPIO3_PIN_MASK 0x30 +#define DA9211_GPIO3_PIN_GPI 0x00 +#define DA9211_GPIO3_PIN_IERROR 0x10 +#define DA9211_GPIO3_PIN_GPO_OD 0x20 +#define DA9211_GPIO3_PIN_GPO 0x30 +#define DA9211_GPIO3_TYPE_SHIFT 0x40 +#define DA9211_GPIO3_TYPE_GPI 0x00 +#define DA9211_GPIO3_TYPE_GPO 0x40 +#define DA9211_GPIO3_MODE 0x80 + +/* DA9211_REG_GPIO_4 (addr=0x5A) */ +#define DA9211_GPIO4_PIN_SHIFT 0 +#define DA9211_GPIO4_PIN_MASK 0x03 +#define DA9211_GPIO4_PIN_GPI 0x00 +#define DA9211_GPIO4_PIN_GPO_OD 0x02 +#define DA9211_GPIO4_PIN_GPO 0x03 +#define DA9211_GPIO4_TYPE 0x04 +#define DA9211_GPIO4_TYPE_GPI 0x00 +#define DA9211_GPIO4_TYPE_GPO 0x04 +#define DA9211_GPIO4_MODE 0x08 + +/* DA9211_REG_BUCKA_CONT (addr=0x5D) */ +#define DA9211_BUCKA_EN 0x01 +#define DA9211_BUCKA_GPI_SHIFT 1 +#define DA9211_BUCKA_GPI_MASK 0x06 +#define DA9211_BUCKA_GPI_OFF 0x00 +#define DA9211_BUCKA_GPI_GPIO0 0x02 +#define DA9211_BUCKA_GPI_GPIO1 0x04 +#define DA9211_BUCKA_GPI_GPIO3 0x06 +#define DA9211_BUCKA_PD_DIS 0x08 +#define DA9211_VBUCKA_SEL 0x10 +#define DA9211_VBUCKA_SEL_A 0x00 +#define DA9211_VBUCKA_SEL_B 0x10 +#define DA9211_VBUCKA_GPI_SHIFT 5 +#define DA9211_VBUCKA_GPI_MASK 0x60 +#define DA9211_VBUCKA_GPI_OFF 0x00 +#define DA9211_VBUCKA_GPI_GPIO1 0x20 +#define DA9211_VBUCKA_GPI_GPIO2 0x40 +#define DA9211_VBUCKA_GPI_GPIO4 0x60 + +/* DA9211_REG_BUCKB_CONT (addr=0x5E) */ +#define DA9211_BUCKB_EN 0x01 +#define DA9211_BUCKB_GPI_SHIFT 1 +#define DA9211_BUCKB_GPI_MASK 0x06 +#define DA9211_BUCKB_GPI_OFF 0x00 +#define DA9211_BUCKB_GPI_GPIO0 0x02 +#define DA9211_BUCKB_GPI_GPIO1 0x04 +#define DA9211_BUCKB_GPI_GPIO3 0x06 +#define DA9211_BUCKB_PD_DIS 0x08 +#define DA9211_VBUCKB_SEL 0x10 +#define DA9211_VBUCKB_SEL_A 0x00 +#define DA9211_VBUCKB_SEL_B 0x10 +#define DA9211_VBUCKB_GPI_SHIFT 5 +#define DA9211_VBUCKB_GPI_MASK 0x60 +#define DA9211_VBUCKB_GPI_OFF 0x00 +#define DA9211_VBUCKB_GPI_GPIO1 0x20 +#define DA9211_VBUCKB_GPI_GPIO2 0x40 +#define DA9211_VBUCKB_GPI_GPIO4 0x60 + +/* DA9211_REG_BUCK_ILIM (addr=0xD0) */ +#define DA9211_BUCKA_ILIM_SHIFT 0 +#define DA9211_BUCKA_ILIM_MASK 0x0F +#define DA9211_BUCKB_ILIM_SHIFT 4 +#define DA9211_BUCKB_ILIM_MASK 0xF0 + +/* DA9211_REG_BUCKA_CONF (addr=0xD1) */ +#define DA9211_BUCKA_MODE_SHIFT 0 +#define DA9211_BUCKA_MODE_MASK 0x03 +#define DA9211_BUCKA_MODE_MANUAL 0x00 +#define DA9211_BUCKA_MODE_SLEEP 0x01 +#define DA9211_BUCKA_MODE_SYNC 0x02 +#define DA9211_BUCKA_MODE_AUTO 0x03 +#define DA9211_BUCKA_UP_CTRL_SHIFT 2 +#define DA9211_BUCKA_UP_CTRL_MASK 0x1C +#define DA9211_BUCKA_DOWN_CTRL_SHIFT 5 +#define DA9211_BUCKA_DOWN_CTRL_MASK 0xE0 + +/* DA9211_REG_BUCKB_CONF (addr=0xD2) */ +#define DA9211_BUCKB_MODE_SHIFT 0 +#define DA9211_BUCKB_MODE_MASK 0x03 +#define DA9211_BUCKB_MODE_MANUAL 0x00 +#define DA9211_BUCKB_MODE_SLEEP 0x01 +#define DA9211_BUCKB_MODE_SYNC 0x02 +#define DA9211_BUCKB_MODE_AUTO 0x03 +#define DA9211_BUCKB_UP_CTRL_SHIFT 2 +#define DA9211_BUCKB_UP_CTRL_MASK 0x1C +#define DA9211_BUCKB_DOWN_CTRL_SHIFT 5 +#define DA9211_BUCKB_DOWN_CTRL_MASK 0xE0 + +/* DA9211_REG_BUCK_CONF (addr=0xD3) */ +#define DA9211_PHASE_SEL_A_SHIFT 0 +#define DA9211_PHASE_SEL_A_MASK 0x03 +#define DA9211_PHASE_SEL_B_SHIFT 2 +#define DA9211_PHASE_SEL_B_MASK 0x04 +#define DA9211_PH_SH_EN_A_SHIFT 3 +#define DA9211_PH_SH_EN_A_MASK 0x08 +#define DA9211_PH_SH_EN_B_SHIFT 4 +#define DA9211_PH_SH_EN_B_MASK 0x10 + +/* DA9211_REG_VBUCKA_MAX (addr=0xD5) */ +#define DA9211_VBUCKA_BASE_SHIFT 0 +#define DA9211_VBUCKA_BASE_MASK 0x7F + +/* DA9211_REG_VBUCKB_MAX (addr=0xD6) */ +#define DA9211_VBUCKB_BASE_SHIFT 0 +#define DA9211_VBUCKB_BASE_MASK 0x7F + +/* DA9211_REG_VBUCKA/B_A/B (addr=0xD7/0xD8/0xD9/0xDA) */ +#define DA9211_VBUCK_SHIFT 0 +#define DA9211_VBUCK_MASK 0x7F +#define DA9211_VBUCK_BIAS 0 +#define DA9211_BUCK_SL 0x80 + +/* DA9211_REG_INTERFACE (addr=0x105) */ +#define DA9211_IF_BASE_ADDR_SHIFT 4 +#define DA9211_IF_BASE_ADDR_MASK 0xF0 + +/* DA9211_REG_CONFIG_E (addr=0x147) */ +#define DA9211_SLAVE_SEL 0x40 + +#endif /* __DA9211_REGISTERS_H__ */ diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c index 2e022aabd95..021d64d856b 100644 --- a/drivers/regulator/lp872x.c +++ b/drivers/regulator/lp872x.c @@ -845,7 +845,6 @@ static struct lp872x_platform_data struct device_node *np = dev->of_node; struct lp872x_platform_data *pdata; struct of_regulator_match *match; - struct regulator_init_data *d; int num_matches; int count; int i; @@ -892,14 +891,6 @@ static struct lp872x_platform_data pdata->regulator_data[i].id = (enum lp872x_regulator_id)match[i].driver_data; pdata->regulator_data[i].init_data = match[i].init_data; - - /* Operation mode configuration for buck/buck1/buck2 */ - if (strncmp(match[i].name, "buck", 4)) - continue; - - d = pdata->regulator_data[i].init_data; - d->constraints.valid_modes_mask |= LP872X_VALID_OPMODE; - d->constraints.valid_ops_mask |= REGULATOR_CHANGE_MODE; } out: return pdata; diff --git a/drivers/regulator/lp8755.c b/drivers/regulator/lp8755.c index 785a25e9a43..4a415d4ee46 100644 --- a/drivers/regulator/lp8755.c +++ b/drivers/regulator/lp8755.c @@ -339,22 +339,18 @@ static int lp8755_regulator_init(struct lp8755_chip *pchip) rconfig.init_data = pdata->buck_data[buck_num]; rconfig.of_node = pchip->dev->of_node; pchip->rdev[buck_num] = - regulator_register(&lp8755_regulators[buck_num], &rconfig); + devm_regulator_register(pchip->dev, + &lp8755_regulators[buck_num], &rconfig); if (IS_ERR(pchip->rdev[buck_num])) { ret = PTR_ERR(pchip->rdev[buck_num]); pchip->rdev[buck_num] = NULL; dev_err(pchip->dev, "regulator init failed: buck %d\n", buck_num); - goto err_buck; + return ret; } } return 0; - -err_buck: - for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++) - regulator_unregister(pchip->rdev[icnt]); - return ret; } static irqreturn_t lp8755_irq_handler(int irq, void *data) @@ -490,23 +486,19 @@ static int lp8755_probe(struct i2c_client *client, ret = lp8755_regulator_init(pchip); if (ret < 0) { dev_err(&client->dev, "fail to initialize regulators\n"); - goto err_regulator; + goto err; } pchip->irq = client->irq; ret = lp8755_int_config(pchip); if (ret < 0) { dev_err(&client->dev, "fail to irq config\n"); - goto err_irq; + goto err; } return ret; -err_irq: - for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++) - regulator_unregister(pchip->rdev[icnt]); - -err_regulator: +err: /* output disable */ for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++) lp8755_write(pchip, icnt, 0x00); @@ -519,9 +511,6 @@ static int lp8755_remove(struct i2c_client *client) int icnt; struct lp8755_chip *pchip = i2c_get_clientdata(client); - for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++) - regulator_unregister(pchip->rdev[icnt]); - for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++) lp8755_write(pchip, icnt, 0x00); diff --git a/drivers/regulator/ltc3589.c b/drivers/regulator/ltc3589.c index 217d10d6f8f..c756955bfcc 100644 --- a/drivers/regulator/ltc3589.c +++ b/drivers/regulator/ltc3589.c @@ -255,7 +255,7 @@ static int ltc3589_parse_regulators_dt(struct ltc3589 *ltc3589) struct device_node *node; int i, ret; - node = of_find_node_by_name(dev->of_node, "regulators"); + node = of_get_child_by_name(dev->of_node, "regulators"); if (!node) { dev_err(dev, "regulators node not found\n"); return -EINVAL; diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c index c2792f0271a..f7f9efcfedb 100644 --- a/drivers/regulator/max8952.c +++ b/drivers/regulator/max8952.c @@ -229,7 +229,6 @@ static int max8952_pmic_probe(struct i2c_client *client, config.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; rdev = devm_regulator_register(&client->dev, ®ulator, &config); - if (IS_ERR(rdev)) { ret = PTR_ERR(rdev); dev_err(&client->dev, "regulator init failed (%d)\n", ret); @@ -241,21 +240,19 @@ static int max8952_pmic_probe(struct i2c_client *client, if (gpio_is_valid(pdata->gpio_vid0) && gpio_is_valid(pdata->gpio_vid1)) { - if (!gpio_request(pdata->gpio_vid0, "MAX8952 VID0")) - gpio_direction_output(pdata->gpio_vid0, - (pdata->default_mode) & 0x1); - else + unsigned long gpio_flags; + + gpio_flags = max8952->vid0 ? + GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; + if (devm_gpio_request_one(&client->dev, pdata->gpio_vid0, + gpio_flags, "MAX8952 VID0")) err = 1; - if (!gpio_request(pdata->gpio_vid1, "MAX8952 VID1")) - gpio_direction_output(pdata->gpio_vid1, - (pdata->default_mode >> 1) & 0x1); - else { - if (!err) - gpio_free(pdata->gpio_vid0); + gpio_flags = max8952->vid1 ? + GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; + if (devm_gpio_request_one(&client->dev, pdata->gpio_vid1, + gpio_flags, "MAX8952 VID1")) err = 2; - } - } else err = 3; @@ -314,16 +311,6 @@ static int max8952_pmic_probe(struct i2c_client *client, return 0; } -static int max8952_pmic_remove(struct i2c_client *client) -{ - struct max8952_data *max8952 = i2c_get_clientdata(client); - struct max8952_platform_data *pdata = max8952->pdata; - - gpio_free(pdata->gpio_vid0); - gpio_free(pdata->gpio_vid1); - return 0; -} - static const struct i2c_device_id max8952_ids[] = { { "max8952", 0 }, { }, @@ -332,7 +319,6 @@ MODULE_DEVICE_TABLE(i2c, max8952_ids); static struct i2c_driver max8952_pmic_driver = { .probe = max8952_pmic_probe, - .remove = max8952_pmic_remove, .driver = { .name = "max8952", .of_match_table = of_match_ptr(max8952_dt_match), diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c index 05b971726ff..afba024953e 100644 --- a/drivers/regulator/mc13xxx-regulator-core.c +++ b/drivers/regulator/mc13xxx-regulator-core.c @@ -33,17 +33,12 @@ static int mc13xxx_regulator_enable(struct regulator_dev *rdev) struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; int id = rdev_get_id(rdev); - int ret; dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); - mc13xxx_lock(priv->mc13xxx); - ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13xxx_regulators[id].reg, - mc13xxx_regulators[id].enable_bit, - mc13xxx_regulators[id].enable_bit); - mc13xxx_unlock(priv->mc13xxx); - - return ret; + return mc13xxx_reg_rmw(priv->mc13xxx, mc13xxx_regulators[id].reg, + mc13xxx_regulators[id].enable_bit, + mc13xxx_regulators[id].enable_bit); } static int mc13xxx_regulator_disable(struct regulator_dev *rdev) @@ -51,16 +46,11 @@ static int mc13xxx_regulator_disable(struct regulator_dev *rdev) struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; int id = rdev_get_id(rdev); - int ret; dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); - mc13xxx_lock(priv->mc13xxx); - ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13xxx_regulators[id].reg, - mc13xxx_regulators[id].enable_bit, 0); - mc13xxx_unlock(priv->mc13xxx); - - return ret; + return mc13xxx_reg_rmw(priv->mc13xxx, mc13xxx_regulators[id].reg, + mc13xxx_regulators[id].enable_bit, 0); } static int mc13xxx_regulator_is_enabled(struct regulator_dev *rdev) @@ -70,10 +60,7 @@ static int mc13xxx_regulator_is_enabled(struct regulator_dev *rdev) int ret, id = rdev_get_id(rdev); unsigned int val; - mc13xxx_lock(priv->mc13xxx); ret = mc13xxx_reg_read(priv->mc13xxx, mc13xxx_regulators[id].reg, &val); - mc13xxx_unlock(priv->mc13xxx); - if (ret) return ret; @@ -86,15 +73,10 @@ static int mc13xxx_regulator_set_voltage_sel(struct regulator_dev *rdev, struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; int id = rdev_get_id(rdev); - int ret; - mc13xxx_lock(priv->mc13xxx); - ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13xxx_regulators[id].vsel_reg, - mc13xxx_regulators[id].vsel_mask, - selector << mc13xxx_regulators[id].vsel_shift); - mc13xxx_unlock(priv->mc13xxx); - - return ret; + return mc13xxx_reg_rmw(priv->mc13xxx, mc13xxx_regulators[id].vsel_reg, + mc13xxx_regulators[id].vsel_mask, + selector << mc13xxx_regulators[id].vsel_shift); } static int mc13xxx_regulator_get_voltage(struct regulator_dev *rdev) @@ -106,11 +88,8 @@ static int mc13xxx_regulator_get_voltage(struct regulator_dev *rdev) dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); - mc13xxx_lock(priv->mc13xxx); ret = mc13xxx_reg_read(priv->mc13xxx, mc13xxx_regulators[id].vsel_reg, &val); - mc13xxx_unlock(priv->mc13xxx); - if (ret) return ret; diff --git a/drivers/regulator/mc13xxx.h b/drivers/regulator/mc13xxx.h index 06c8903f182..2ab9bfd93b4 100644 --- a/drivers/regulator/mc13xxx.h +++ b/drivers/regulator/mc13xxx.h @@ -21,7 +21,6 @@ struct mc13xxx_regulator { int vsel_reg; int vsel_shift; int vsel_mask; - int hi_bit; }; struct mc13xxx_regulator_priv { diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index 864ed02ce4b..a7ce34d1b5f 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -27,28 +27,21 @@ #include <linux/of_platform.h> #include <linux/regulator/of_regulator.h> -struct regs_info { - char *name; - char *sname; - u8 vsel_addr; - u8 ctrl_addr; - u8 tstep_addr; - int sleep_id; -}; - static const struct regulator_linear_range smps_low_ranges[] = { + REGULATOR_LINEAR_RANGE(0, 0x0, 0x0, 0), REGULATOR_LINEAR_RANGE(500000, 0x1, 0x6, 0), REGULATOR_LINEAR_RANGE(510000, 0x7, 0x79, 10000), REGULATOR_LINEAR_RANGE(1650000, 0x7A, 0x7f, 0), }; static const struct regulator_linear_range smps_high_ranges[] = { + REGULATOR_LINEAR_RANGE(0, 0x0, 0x0, 0), REGULATOR_LINEAR_RANGE(1000000, 0x1, 0x6, 0), REGULATOR_LINEAR_RANGE(1020000, 0x7, 0x79, 20000), REGULATOR_LINEAR_RANGE(3300000, 0x7A, 0x7f, 0), }; -static const struct regs_info palmas_regs_info[] = { +static struct palmas_regs_info palmas_generic_regs_info[] = { { .name = "SMPS12", .sname = "smps1-in", @@ -234,6 +227,153 @@ static const struct regs_info palmas_regs_info[] = { }, }; +static struct palmas_regs_info tps65917_regs_info[] = { + { + .name = "SMPS1", + .sname = "smps1-in", + .vsel_addr = TPS65917_SMPS1_VOLTAGE, + .ctrl_addr = TPS65917_SMPS1_CTRL, + .sleep_id = TPS65917_EXTERNAL_REQSTR_ID_SMPS1, + }, + { + .name = "SMPS2", + .sname = "smps2-in", + .vsel_addr = TPS65917_SMPS2_VOLTAGE, + .ctrl_addr = TPS65917_SMPS2_CTRL, + .sleep_id = TPS65917_EXTERNAL_REQSTR_ID_SMPS2, + }, + { + .name = "SMPS3", + .sname = "smps3-in", + .vsel_addr = TPS65917_SMPS3_VOLTAGE, + .ctrl_addr = TPS65917_SMPS3_CTRL, + .sleep_id = TPS65917_EXTERNAL_REQSTR_ID_SMPS3, + }, + { + .name = "SMPS4", + .sname = "smps4-in", + .vsel_addr = TPS65917_SMPS4_VOLTAGE, + .ctrl_addr = TPS65917_SMPS4_CTRL, + .sleep_id = TPS65917_EXTERNAL_REQSTR_ID_SMPS4, + }, + { + .name = "SMPS5", + .sname = "smps5-in", + .vsel_addr = TPS65917_SMPS5_VOLTAGE, + .ctrl_addr = TPS65917_SMPS5_CTRL, + .sleep_id = TPS65917_EXTERNAL_REQSTR_ID_SMPS5, + }, + { + .name = "LDO1", + .sname = "ldo1-in", + .vsel_addr = TPS65917_LDO1_VOLTAGE, + .ctrl_addr = TPS65917_LDO1_CTRL, + .sleep_id = TPS65917_EXTERNAL_REQSTR_ID_LDO1, + }, + { + .name = "LDO2", + .sname = "ldo2-in", + .vsel_addr = TPS65917_LDO2_VOLTAGE, + .ctrl_addr = TPS65917_LDO2_CTRL, + .sleep_id = TPS65917_EXTERNAL_REQSTR_ID_LDO2, + }, + { + .name = "LDO3", + .sname = "ldo3-in", + .vsel_addr = TPS65917_LDO3_VOLTAGE, + .ctrl_addr = TPS65917_LDO3_CTRL, + .sleep_id = TPS65917_EXTERNAL_REQSTR_ID_LDO3, + }, + { + .name = "LDO4", + .sname = "ldo4-in", + .vsel_addr = TPS65917_LDO4_VOLTAGE, + .ctrl_addr = TPS65917_LDO4_CTRL, + .sleep_id = TPS65917_EXTERNAL_REQSTR_ID_LDO4, + }, + { + .name = "LDO5", + .sname = "ldo5-in", + .vsel_addr = TPS65917_LDO5_VOLTAGE, + .ctrl_addr = TPS65917_LDO5_CTRL, + .sleep_id = TPS65917_EXTERNAL_REQSTR_ID_LDO5, + }, + { + .name = "REGEN1", + .ctrl_addr = TPS65917_REGEN1_CTRL, + .sleep_id = TPS65917_EXTERNAL_REQSTR_ID_REGEN1, + }, + { + .name = "REGEN2", + .ctrl_addr = TPS65917_REGEN2_CTRL, + .sleep_id = TPS65917_EXTERNAL_REQSTR_ID_REGEN2, + }, + { + .name = "REGEN3", + .ctrl_addr = TPS65917_REGEN3_CTRL, + .sleep_id = TPS65917_EXTERNAL_REQSTR_ID_REGEN3, + }, +}; + +#define EXTERNAL_REQUESTOR(_id, _offset, _pos) \ + [PALMAS_EXTERNAL_REQSTR_ID_##_id] = { \ + .id = PALMAS_EXTERNAL_REQSTR_ID_##_id, \ + .reg_offset = _offset, \ + .bit_pos = _pos, \ + } + +static struct palmas_sleep_requestor_info palma_sleep_req_info[] = { + EXTERNAL_REQUESTOR(REGEN1, 0, 0), + EXTERNAL_REQUESTOR(REGEN2, 0, 1), + EXTERNAL_REQUESTOR(SYSEN1, 0, 2), + EXTERNAL_REQUESTOR(SYSEN2, 0, 3), + EXTERNAL_REQUESTOR(CLK32KG, 0, 4), + EXTERNAL_REQUESTOR(CLK32KGAUDIO, 0, 5), + EXTERNAL_REQUESTOR(REGEN3, 0, 6), + EXTERNAL_REQUESTOR(SMPS12, 1, 0), + EXTERNAL_REQUESTOR(SMPS3, 1, 1), + EXTERNAL_REQUESTOR(SMPS45, 1, 2), + EXTERNAL_REQUESTOR(SMPS6, 1, 3), + EXTERNAL_REQUESTOR(SMPS7, 1, 4), + EXTERNAL_REQUESTOR(SMPS8, 1, 5), + EXTERNAL_REQUESTOR(SMPS9, 1, 6), + EXTERNAL_REQUESTOR(SMPS10, 1, 7), + EXTERNAL_REQUESTOR(LDO1, 2, 0), + EXTERNAL_REQUESTOR(LDO2, 2, 1), + EXTERNAL_REQUESTOR(LDO3, 2, 2), + EXTERNAL_REQUESTOR(LDO4, 2, 3), + EXTERNAL_REQUESTOR(LDO5, 2, 4), + EXTERNAL_REQUESTOR(LDO6, 2, 5), + EXTERNAL_REQUESTOR(LDO7, 2, 6), + EXTERNAL_REQUESTOR(LDO8, 2, 7), + EXTERNAL_REQUESTOR(LDO9, 3, 0), + EXTERNAL_REQUESTOR(LDOLN, 3, 1), + EXTERNAL_REQUESTOR(LDOUSB, 3, 2), +}; + +#define EXTERNAL_REQUESTOR_TPS65917(_id, _offset, _pos) \ + [TPS65917_EXTERNAL_REQSTR_ID_##_id] = { \ + .id = TPS65917_EXTERNAL_REQSTR_ID_##_id, \ + .reg_offset = _offset, \ + .bit_pos = _pos, \ + } + +static struct palmas_sleep_requestor_info tps65917_sleep_req_info[] = { + EXTERNAL_REQUESTOR_TPS65917(REGEN1, 0, 0), + EXTERNAL_REQUESTOR_TPS65917(REGEN2, 0, 1), + EXTERNAL_REQUESTOR_TPS65917(REGEN3, 0, 6), + EXTERNAL_REQUESTOR_TPS65917(SMPS1, 1, 0), + EXTERNAL_REQUESTOR_TPS65917(SMPS2, 1, 1), + EXTERNAL_REQUESTOR_TPS65917(SMPS3, 1, 2), + EXTERNAL_REQUESTOR_TPS65917(SMPS4, 1, 3), + EXTERNAL_REQUESTOR_TPS65917(SMPS5, 1, 4), + EXTERNAL_REQUESTOR_TPS65917(LDO1, 2, 0), + EXTERNAL_REQUESTOR_TPS65917(LDO2, 2, 1), + EXTERNAL_REQUESTOR_TPS65917(LDO3, 2, 2), + EXTERNAL_REQUESTOR_TPS65917(LDO4, 2, 3), + EXTERNAL_REQUESTOR_TPS65917(LDO5, 2, 4), +}; + static unsigned int palmas_smps_ramp_delay[4] = {0, 10000, 5000, 2500}; #define SMPS_CTRL_MODE_OFF 0x00 @@ -294,12 +434,15 @@ static int palmas_ldo_write(struct palmas *palmas, unsigned int reg, static int palmas_set_mode_smps(struct regulator_dev *dev, unsigned int mode) { - struct palmas_pmic *pmic = rdev_get_drvdata(dev); int id = rdev_get_id(dev); + struct palmas_pmic *pmic = rdev_get_drvdata(dev); + struct palmas_pmic_driver_data *ddata = pmic->palmas->pmic_ddata; + struct palmas_regs_info *rinfo = &ddata->palmas_regs_info[id]; unsigned int reg; bool rail_enable = true; - palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, ®); + palmas_smps_read(pmic->palmas, rinfo->ctrl_addr, ®); + reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK; if (reg == SMPS_CTRL_MODE_OFF) @@ -321,8 +464,11 @@ static int palmas_set_mode_smps(struct regulator_dev *dev, unsigned int mode) pmic->current_reg_mode[id] = reg & PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK; if (rail_enable) - palmas_smps_write(pmic->palmas, - palmas_regs_info[id].ctrl_addr, reg); + palmas_smps_write(pmic->palmas, rinfo->ctrl_addr, reg); + + /* Switch the enable value to ensure this is used for enable */ + pmic->desc[id].enable_val = pmic->current_reg_mode[id]; + return 0; } @@ -349,10 +495,11 @@ static unsigned int palmas_get_mode_smps(struct regulator_dev *dev) static int palmas_smps_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) { - struct palmas_pmic *pmic = rdev_get_drvdata(rdev); int id = rdev_get_id(rdev); + struct palmas_pmic *pmic = rdev_get_drvdata(rdev); + struct palmas_pmic_driver_data *ddata = pmic->palmas->pmic_ddata; + struct palmas_regs_info *rinfo = &ddata->palmas_regs_info[id]; unsigned int reg = 0; - unsigned int addr = palmas_regs_info[id].tstep_addr; int ret; /* SMPS3 and SMPS7 do not have tstep_addr setting */ @@ -371,7 +518,7 @@ static int palmas_smps_set_ramp_delay(struct regulator_dev *rdev, else reg = 1; - ret = palmas_smps_write(pmic->palmas, addr, reg); + ret = palmas_smps_write(pmic->palmas, rinfo->tstep_addr, reg); if (ret < 0) { dev_err(pmic->palmas->dev, "TSTEP write failed: %d\n", ret); return ret; @@ -418,13 +565,37 @@ static struct regulator_ops palmas_ops_smps10 = { .get_bypass = regulator_get_bypass_regmap, }; +static struct regulator_ops tps65917_ops_smps = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .set_mode = palmas_set_mode_smps, + .get_mode = palmas_get_mode_smps, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .set_voltage_time_sel = regulator_set_voltage_time_sel, +}; + +static struct regulator_ops tps65917_ops_ext_control_smps = { + .set_mode = palmas_set_mode_smps, + .get_mode = palmas_get_mode_smps, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, +}; + static int palmas_is_enabled_ldo(struct regulator_dev *dev) { - struct palmas_pmic *pmic = rdev_get_drvdata(dev); int id = rdev_get_id(dev); + struct palmas_pmic *pmic = rdev_get_drvdata(dev); + struct palmas_pmic_driver_data *ddata = pmic->palmas->pmic_ddata; + struct palmas_regs_info *rinfo = &ddata->palmas_regs_info[id]; unsigned int reg; - palmas_ldo_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, ®); + palmas_ldo_read(pmic->palmas, rinfo->ctrl_addr, ®); reg &= PALMAS_LDO1_CTRL_STATUS; @@ -457,14 +628,26 @@ static struct regulator_ops palmas_ops_extreg = { static struct regulator_ops palmas_ops_ext_control_extreg = { }; +static struct regulator_ops tps65917_ops_ldo = { + .is_enabled = palmas_is_enabled_ldo, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .set_voltage_time_sel = regulator_set_voltage_time_sel, +}; + static int palmas_regulator_config_external(struct palmas *palmas, int id, struct palmas_reg_init *reg_init) { - int sleep_id = palmas_regs_info[id].sleep_id; + struct palmas_pmic_driver_data *ddata = palmas->pmic_ddata; + struct palmas_regs_info *rinfo = &ddata->palmas_regs_info[id]; int ret; - ret = palmas_ext_control_req_config(palmas, sleep_id, - reg_init->roof_floor, true); + ret = palmas_ext_control_req_config(palmas, rinfo->sleep_id, + reg_init->roof_floor, true); if (ret < 0) dev_err(palmas->dev, "Ext control config for regulator %d failed %d\n", @@ -482,10 +665,10 @@ static int palmas_smps_init(struct palmas *palmas, int id, struct palmas_reg_init *reg_init) { unsigned int reg; - unsigned int addr; int ret; - - addr = palmas_regs_info[id].ctrl_addr; + struct palmas_pmic_driver_data *ddata = palmas->pmic_ddata; + struct palmas_regs_info *rinfo = &ddata->palmas_regs_info[id]; + unsigned int addr = rinfo->ctrl_addr; ret = palmas_smps_read(palmas, addr, ®); if (ret) @@ -520,12 +703,11 @@ static int palmas_smps_init(struct palmas *palmas, int id, if (ret) return ret; - if (palmas_regs_info[id].vsel_addr && reg_init->vsel) { - addr = palmas_regs_info[id].vsel_addr; + if (rinfo->vsel_addr && reg_init->vsel) { reg = reg_init->vsel; - ret = palmas_smps_write(palmas, addr, reg); + ret = palmas_smps_write(palmas, rinfo->vsel_addr, reg); if (ret) return ret; } @@ -533,7 +715,6 @@ static int palmas_smps_init(struct palmas *palmas, int id, if (reg_init->roof_floor && (id != PALMAS_REG_SMPS10_OUT1) && (id != PALMAS_REG_SMPS10_OUT2)) { /* Enable externally controlled regulator */ - addr = palmas_regs_info[id].ctrl_addr; ret = palmas_smps_read(palmas, addr, ®); if (ret < 0) return ret; @@ -555,8 +736,10 @@ static int palmas_ldo_init(struct palmas *palmas, int id, unsigned int reg; unsigned int addr; int ret; + struct palmas_pmic_driver_data *ddata = palmas->pmic_ddata; + struct palmas_regs_info *rinfo = &ddata->palmas_regs_info[id]; - addr = palmas_regs_info[id].ctrl_addr; + addr = rinfo->ctrl_addr; ret = palmas_ldo_read(palmas, addr, ®); if (ret) @@ -578,7 +761,6 @@ static int palmas_ldo_init(struct palmas *palmas, int id, if (reg_init->roof_floor) { /* Enable externally controlled regulator */ - addr = palmas_regs_info[id].ctrl_addr; ret = palmas_update_bits(palmas, PALMAS_LDO_BASE, addr, PALMAS_LDO1_CTRL_MODE_ACTIVE, PALMAS_LDO1_CTRL_MODE_ACTIVE); @@ -599,8 +781,10 @@ static int palmas_extreg_init(struct palmas *palmas, int id, unsigned int addr; int ret; unsigned int val = 0; + struct palmas_pmic_driver_data *ddata = palmas->pmic_ddata; + struct palmas_regs_info *rinfo = &ddata->palmas_regs_info[id]; - addr = palmas_regs_info[id].ctrl_addr; + addr = rinfo->ctrl_addr; if (reg_init->mode_sleep) val = PALMAS_REGEN1_CTRL_MODE_SLEEP; @@ -615,7 +799,6 @@ static int palmas_extreg_init(struct palmas *palmas, int id, if (reg_init->roof_floor) { /* Enable externally controlled regulator */ - addr = palmas_regs_info[id].ctrl_addr; ret = palmas_update_bits(palmas, PALMAS_RESOURCE_BASE, addr, PALMAS_REGEN1_CTRL_MODE_ACTIVE, PALMAS_REGEN1_CTRL_MODE_ACTIVE); @@ -635,8 +818,11 @@ static void palmas_enable_ldo8_track(struct palmas *palmas) unsigned int reg; unsigned int addr; int ret; + struct palmas_pmic_driver_data *ddata = palmas->pmic_ddata; + struct palmas_regs_info *rinfo; - addr = palmas_regs_info[PALMAS_REG_LDO8].ctrl_addr; + rinfo = &ddata->palmas_regs_info[PALMAS_REG_LDO8]; + addr = rinfo->ctrl_addr; ret = palmas_ldo_read(palmas, addr, ®); if (ret) { @@ -655,7 +841,7 @@ static void palmas_enable_ldo8_track(struct palmas *palmas) * output is defined by the LDO8_VOLTAGE.VSEL register divided by two, * and can be set from 0.45 to 1.65 V. */ - addr = palmas_regs_info[PALMAS_REG_LDO8].vsel_addr; + addr = rinfo->vsel_addr; ret = palmas_ldo_read(palmas, addr, ®); if (ret) { dev_err(palmas->dev, "Error in reading ldo8 voltage reg\n"); @@ -670,169 +856,230 @@ static void palmas_enable_ldo8_track(struct palmas *palmas) return; } -static struct of_regulator_match palmas_matches[] = { - { .name = "smps12", }, - { .name = "smps123", }, - { .name = "smps3", }, - { .name = "smps45", }, - { .name = "smps457", }, - { .name = "smps6", }, - { .name = "smps7", }, - { .name = "smps8", }, - { .name = "smps9", }, - { .name = "smps10_out2", }, - { .name = "smps10_out1", }, - { .name = "ldo1", }, - { .name = "ldo2", }, - { .name = "ldo3", }, - { .name = "ldo4", }, - { .name = "ldo5", }, - { .name = "ldo6", }, - { .name = "ldo7", }, - { .name = "ldo8", }, - { .name = "ldo9", }, - { .name = "ldoln", }, - { .name = "ldousb", }, - { .name = "regen1", }, - { .name = "regen2", }, - { .name = "regen3", }, - { .name = "sysen1", }, - { .name = "sysen2", }, -}; - -static void palmas_dt_to_pdata(struct device *dev, - struct device_node *node, - struct palmas_pmic_platform_data *pdata) +static int palmas_ldo_registration(struct palmas_pmic *pmic, + struct palmas_pmic_driver_data *ddata, + struct palmas_pmic_platform_data *pdata, + const char *pdev_name, + struct regulator_config config) { - struct device_node *regulators; - u32 prop; - int idx, ret; + int id, ret; + struct regulator_dev *rdev; + struct palmas_reg_init *reg_init; + struct palmas_regs_info *rinfo; + struct regulator_desc *desc; - node = of_node_get(node); - regulators = of_get_child_by_name(node, "regulators"); - if (!regulators) { - dev_info(dev, "regulator node not found\n"); - return; - } + for (id = ddata->ldo_begin; id < ddata->max_reg; id++) { + if (pdata && pdata->reg_init[id]) + reg_init = pdata->reg_init[id]; + else + reg_init = NULL; - ret = of_regulator_match(dev, regulators, palmas_matches, - PALMAS_NUM_REGS); - of_node_put(regulators); - if (ret < 0) { - dev_err(dev, "Error parsing regulator init data: %d\n", ret); - return; - } + rinfo = &ddata->palmas_regs_info[id]; + /* Miss out regulators which are not available due + * to alternate functions. + */ - for (idx = 0; idx < PALMAS_NUM_REGS; idx++) { - if (!palmas_matches[idx].init_data || - !palmas_matches[idx].of_node) - continue; + /* Register the regulators */ + desc = &pmic->desc[id]; + desc->name = rinfo->name; + desc->id = id; + desc->type = REGULATOR_VOLTAGE; + desc->owner = THIS_MODULE; - pdata->reg_data[idx] = palmas_matches[idx].init_data; + if (id < PALMAS_REG_REGEN1) { + desc->n_voltages = PALMAS_LDO_NUM_VOLTAGES; + if (reg_init && reg_init->roof_floor) + desc->ops = &palmas_ops_ext_control_ldo; + else + desc->ops = &palmas_ops_ldo; + desc->min_uV = 900000; + desc->uV_step = 50000; + desc->linear_min_sel = 1; + desc->enable_time = 500; + desc->vsel_reg = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE, + rinfo->vsel_addr); + desc->vsel_mask = PALMAS_LDO1_VOLTAGE_VSEL_MASK; + desc->enable_reg = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE, + rinfo->ctrl_addr); + desc->enable_mask = PALMAS_LDO1_CTRL_MODE_ACTIVE; - pdata->reg_init[idx] = devm_kzalloc(dev, - sizeof(struct palmas_reg_init), GFP_KERNEL); + /* Check if LDO8 is in tracking mode or not */ + if (pdata && (id == PALMAS_REG_LDO8) && + pdata->enable_ldo8_tracking) { + palmas_enable_ldo8_track(pmic->palmas); + desc->min_uV = 450000; + desc->uV_step = 25000; + } - pdata->reg_init[idx]->warm_reset = - of_property_read_bool(palmas_matches[idx].of_node, - "ti,warm-reset"); + /* LOD6 in vibrator mode will have enable time 2000us */ + if (pdata && pdata->ldo6_vibrator && + (id == PALMAS_REG_LDO6)) + desc->enable_time = 2000; + } else { + desc->n_voltages = 1; + if (reg_init && reg_init->roof_floor) + desc->ops = &palmas_ops_ext_control_extreg; + else + desc->ops = &palmas_ops_extreg; + desc->enable_reg = + PALMAS_BASE_TO_REG(PALMAS_RESOURCE_BASE, + rinfo->ctrl_addr); + desc->enable_mask = PALMAS_REGEN1_CTRL_MODE_ACTIVE; + } - ret = of_property_read_u32(palmas_matches[idx].of_node, - "ti,roof-floor", &prop); - /* EINVAL: Property not found */ - if (ret != -EINVAL) { - int econtrol; + if (pdata) + config.init_data = pdata->reg_data[id]; + else + config.init_data = NULL; - /* use default value, when no value is specified */ - econtrol = PALMAS_EXT_CONTROL_NSLEEP; - if (!ret) { - switch (prop) { - case 1: - econtrol = PALMAS_EXT_CONTROL_ENABLE1; - break; - case 2: - econtrol = PALMAS_EXT_CONTROL_ENABLE2; - break; - case 3: - econtrol = PALMAS_EXT_CONTROL_NSLEEP; - break; - default: - WARN_ON(1); - dev_warn(dev, - "%s: Invalid roof-floor option: %u\n", - palmas_matches[idx].name, prop); - break; - } - } - pdata->reg_init[idx]->roof_floor = econtrol; - } + desc->supply_name = rinfo->sname; + config.of_node = ddata->palmas_matches[id].of_node; - ret = of_property_read_u32(palmas_matches[idx].of_node, - "ti,mode-sleep", &prop); - if (!ret) - pdata->reg_init[idx]->mode_sleep = prop; + rdev = devm_regulator_register(pmic->dev, desc, &config); + if (IS_ERR(rdev)) { + dev_err(pmic->dev, + "failed to register %s regulator\n", + pdev_name); + return PTR_ERR(rdev); + } - ret = of_property_read_bool(palmas_matches[idx].of_node, - "ti,smps-range"); - if (ret) - pdata->reg_init[idx]->vsel = - PALMAS_SMPS12_VOLTAGE_RANGE; + /* Save regulator for cleanup */ + pmic->rdev[id] = rdev; - if (idx == PALMAS_REG_LDO8) - pdata->enable_ldo8_tracking = of_property_read_bool( - palmas_matches[idx].of_node, - "ti,enable-ldo8-tracking"); + /* Initialise sleep/init values from platform data */ + if (pdata) { + reg_init = pdata->reg_init[id]; + if (reg_init) { + if (id <= ddata->ldo_end) + ret = palmas_ldo_init(pmic->palmas, id, + reg_init); + else + ret = palmas_extreg_init(pmic->palmas, + id, reg_init); + if (ret) + return ret; + } + } } - pdata->ldo6_vibrator = of_property_read_bool(node, "ti,ldo6-vibrator"); + return 0; } - -static int palmas_regulators_probe(struct platform_device *pdev) +static int tps65917_ldo_registration(struct palmas_pmic *pmic, + struct palmas_pmic_driver_data *ddata, + struct palmas_pmic_platform_data *pdata, + const char *pdev_name, + struct regulator_config config) { - struct palmas *palmas = dev_get_drvdata(pdev->dev.parent); - struct palmas_pmic_platform_data *pdata = dev_get_platdata(&pdev->dev); - struct device_node *node = pdev->dev.of_node; + int id, ret; struct regulator_dev *rdev; - struct regulator_config config = { }; - struct palmas_pmic *pmic; struct palmas_reg_init *reg_init; - int id = 0, ret; - unsigned int addr, reg; + struct palmas_regs_info *rinfo; + struct regulator_desc *desc; - if (node && !pdata) { - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + for (id = ddata->ldo_begin; id < ddata->max_reg; id++) { + if (pdata && pdata->reg_init[id]) + reg_init = pdata->reg_init[id]; + else + reg_init = NULL; - if (!pdata) - return -ENOMEM; + /* Miss out regulators which are not available due + * to alternate functions. + */ + rinfo = &ddata->palmas_regs_info[id]; - palmas_dt_to_pdata(&pdev->dev, node, pdata); - } + /* Register the regulators */ + desc = &pmic->desc[id]; + desc->name = rinfo->name; + desc->id = id; + desc->type = REGULATOR_VOLTAGE; + desc->owner = THIS_MODULE; + + if (id < TPS65917_REG_REGEN1) { + desc->n_voltages = PALMAS_LDO_NUM_VOLTAGES; + if (reg_init && reg_init->roof_floor) + desc->ops = &palmas_ops_ext_control_ldo; + else + desc->ops = &tps65917_ops_ldo; + desc->min_uV = 900000; + desc->uV_step = 50000; + desc->linear_min_sel = 1; + desc->enable_time = 500; + desc->vsel_reg = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE, + rinfo->vsel_addr); + desc->vsel_mask = PALMAS_LDO1_VOLTAGE_VSEL_MASK; + desc->enable_reg = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE, + rinfo->ctrl_addr); + desc->enable_mask = PALMAS_LDO1_CTRL_MODE_ACTIVE; + /* + * To be confirmed. Discussion on going with PMIC Team. + * It is of the order of ~60mV/uS. + */ + desc->ramp_delay = 2500; + } else { + desc->n_voltages = 1; + if (reg_init && reg_init->roof_floor) + desc->ops = &palmas_ops_ext_control_extreg; + else + desc->ops = &palmas_ops_extreg; + desc->enable_reg = + PALMAS_BASE_TO_REG(PALMAS_RESOURCE_BASE, + rinfo->ctrl_addr); + desc->enable_mask = PALMAS_REGEN1_CTRL_MODE_ACTIVE; + } - pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL); - if (!pmic) - return -ENOMEM; + if (pdata) + config.init_data = pdata->reg_data[id]; + else + config.init_data = NULL; - pmic->dev = &pdev->dev; - pmic->palmas = palmas; - palmas->pmic = pmic; - platform_set_drvdata(pdev, pmic); + desc->supply_name = rinfo->sname; + config.of_node = ddata->palmas_matches[id].of_node; - ret = palmas_smps_read(palmas, PALMAS_SMPS_CTRL, ®); - if (ret) - return ret; + rdev = devm_regulator_register(pmic->dev, desc, &config); + if (IS_ERR(rdev)) { + dev_err(pmic->dev, + "failed to register %s regulator\n", + pdev_name); + return PTR_ERR(rdev); + } - if (reg & PALMAS_SMPS_CTRL_SMPS12_SMPS123_EN) - pmic->smps123 = 1; + /* Save regulator for cleanup */ + pmic->rdev[id] = rdev; - if (reg & PALMAS_SMPS_CTRL_SMPS45_SMPS457_EN) - pmic->smps457 = 1; + /* Initialise sleep/init values from platform data */ + if (pdata) { + reg_init = pdata->reg_init[id]; + if (reg_init) { + if (id < TPS65917_REG_REGEN1) + ret = palmas_ldo_init(pmic->palmas, + id, reg_init); + else + ret = palmas_extreg_init(pmic->palmas, + id, reg_init); + if (ret) + return ret; + } + } + } - config.regmap = palmas->regmap[REGULATOR_SLAVE]; - config.dev = &pdev->dev; - config.driver_data = pmic; + return 0; +} - for (id = 0; id < PALMAS_REG_LDO1; id++) { +static int palmas_smps_registration(struct palmas_pmic *pmic, + struct palmas_pmic_driver_data *ddata, + struct palmas_pmic_platform_data *pdata, + const char *pdev_name, + struct regulator_config config) +{ + int id, ret; + unsigned int addr, reg; + struct regulator_dev *rdev; + struct palmas_reg_init *reg_init; + struct palmas_regs_info *rinfo; + struct regulator_desc *desc; + + for (id = ddata->smps_start; id <= ddata->smps_end; id++) { bool ramp_delay_support = false; /* @@ -866,30 +1113,31 @@ static int palmas_regulators_probe(struct platform_device *pdev) break; case PALMAS_REG_SMPS10_OUT1: case PALMAS_REG_SMPS10_OUT2: - if (!PALMAS_PMIC_HAS(palmas, SMPS10_BOOST)) + if (!PALMAS_PMIC_HAS(pmic->palmas, SMPS10_BOOST)) continue; } + rinfo = &ddata->palmas_regs_info[id]; + desc = &pmic->desc[id]; if ((id == PALMAS_REG_SMPS6) || (id == PALMAS_REG_SMPS8)) ramp_delay_support = true; if (ramp_delay_support) { - addr = palmas_regs_info[id].tstep_addr; + addr = rinfo->tstep_addr; ret = palmas_smps_read(pmic->palmas, addr, ®); if (ret < 0) { - dev_err(&pdev->dev, + dev_err(pmic->dev, "reading TSTEP reg failed: %d\n", ret); return ret; } - pmic->desc[id].ramp_delay = - palmas_smps_ramp_delay[reg & 0x3]; - pmic->ramp_delay[id] = pmic->desc[id].ramp_delay; + desc->ramp_delay = palmas_smps_ramp_delay[reg & 0x3]; + pmic->ramp_delay[id] = desc->ramp_delay; } /* Initialise sleep/init values from platform data */ if (pdata && pdata->reg_init[id]) { reg_init = pdata->reg_init[id]; - ret = palmas_smps_init(palmas, id, reg_init); + ret = palmas_smps_init(pmic->palmas, id, reg_init); if (ret) return ret; } else { @@ -897,31 +1145,28 @@ static int palmas_regulators_probe(struct platform_device *pdev) } /* Register the regulators */ - pmic->desc[id].name = palmas_regs_info[id].name; - pmic->desc[id].id = id; + desc->name = rinfo->name; + desc->id = id; switch (id) { case PALMAS_REG_SMPS10_OUT1: case PALMAS_REG_SMPS10_OUT2: - pmic->desc[id].n_voltages = PALMAS_SMPS10_NUM_VOLTAGES; - pmic->desc[id].ops = &palmas_ops_smps10; - pmic->desc[id].vsel_reg = - PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE, - PALMAS_SMPS10_CTRL); - pmic->desc[id].vsel_mask = SMPS10_VSEL; - pmic->desc[id].enable_reg = - PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE, - PALMAS_SMPS10_CTRL); + desc->n_voltages = PALMAS_SMPS10_NUM_VOLTAGES; + desc->ops = &palmas_ops_smps10; + desc->vsel_reg = PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE, + PALMAS_SMPS10_CTRL); + desc->vsel_mask = SMPS10_VSEL; + desc->enable_reg = PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE, + PALMAS_SMPS10_CTRL); if (id == PALMAS_REG_SMPS10_OUT1) - pmic->desc[id].enable_mask = SMPS10_SWITCH_EN; + desc->enable_mask = SMPS10_SWITCH_EN; else - pmic->desc[id].enable_mask = SMPS10_BOOST_EN; - pmic->desc[id].bypass_reg = - PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE, - PALMAS_SMPS10_CTRL); - pmic->desc[id].bypass_mask = SMPS10_BYPASS_EN; - pmic->desc[id].min_uV = 3750000; - pmic->desc[id].uV_step = 1250000; + desc->enable_mask = SMPS10_BOOST_EN; + desc->bypass_reg = PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE, + PALMAS_SMPS10_CTRL); + desc->bypass_mask = SMPS10_BYPASS_EN; + desc->min_uV = 3750000; + desc->uV_step = 1250000; break; default: /* @@ -930,8 +1175,8 @@ static int palmas_regulators_probe(struct platform_device *pdev) * otherwise we error in probe with unsupportable * ranges. Read the current smps mode for later use. */ - addr = palmas_regs_info[id].vsel_addr; - pmic->desc[id].n_linear_ranges = 3; + addr = rinfo->vsel_addr; + desc->n_linear_ranges = 3; ret = palmas_smps_read(pmic->palmas, addr, ®); if (ret) @@ -939,48 +1184,50 @@ static int palmas_regulators_probe(struct platform_device *pdev) if (reg & PALMAS_SMPS12_VOLTAGE_RANGE) pmic->range[id] = 1; if (pmic->range[id]) - pmic->desc[id].linear_ranges = smps_high_ranges; + desc->linear_ranges = smps_high_ranges; else - pmic->desc[id].linear_ranges = smps_low_ranges; + desc->linear_ranges = smps_low_ranges; if (reg_init && reg_init->roof_floor) - pmic->desc[id].ops = - &palmas_ops_ext_control_smps; + desc->ops = &palmas_ops_ext_control_smps; else - pmic->desc[id].ops = &palmas_ops_smps; - pmic->desc[id].n_voltages = PALMAS_SMPS_NUM_VOLTAGES; - pmic->desc[id].vsel_reg = - PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE, - palmas_regs_info[id].vsel_addr); - pmic->desc[id].vsel_mask = - PALMAS_SMPS12_VOLTAGE_VSEL_MASK; + desc->ops = &palmas_ops_smps; + desc->n_voltages = PALMAS_SMPS_NUM_VOLTAGES; + desc->vsel_reg = PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE, + rinfo->vsel_addr); + desc->vsel_mask = PALMAS_SMPS12_VOLTAGE_VSEL_MASK; /* Read the smps mode for later use. */ - addr = palmas_regs_info[id].ctrl_addr; + addr = rinfo->ctrl_addr; ret = palmas_smps_read(pmic->palmas, addr, ®); if (ret) return ret; pmic->current_reg_mode[id] = reg & PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK; + + desc->enable_reg = PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE, + rinfo->ctrl_addr); + desc->enable_mask = PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK; + /* set_mode overrides this value */ + desc->enable_val = SMPS_CTRL_MODE_ON; } - pmic->desc[id].type = REGULATOR_VOLTAGE; - pmic->desc[id].owner = THIS_MODULE; + desc->type = REGULATOR_VOLTAGE; + desc->owner = THIS_MODULE; if (pdata) config.init_data = pdata->reg_data[id]; else config.init_data = NULL; - pmic->desc[id].supply_name = palmas_regs_info[id].sname; - config.of_node = palmas_matches[id].of_node; + desc->supply_name = rinfo->sname; + config.of_node = ddata->palmas_matches[id].of_node; - rdev = devm_regulator_register(&pdev->dev, &pmic->desc[id], - &config); + rdev = devm_regulator_register(pmic->dev, desc, &config); if (IS_ERR(rdev)) { - dev_err(&pdev->dev, + dev_err(pmic->dev, "failed to register %s regulator\n", - pdev->name); + pdev_name); return PTR_ERR(rdev); } @@ -988,123 +1235,378 @@ static int palmas_regulators_probe(struct platform_device *pdev) pmic->rdev[id] = rdev; } - /* Start this loop from the id left from previous loop */ - for (; id < PALMAS_NUM_REGS; id++) { - if (pdata && pdata->reg_init[id]) + return 0; +} + +static int tps65917_smps_registration(struct palmas_pmic *pmic, + struct palmas_pmic_driver_data *ddata, + struct palmas_pmic_platform_data *pdata, + const char *pdev_name, + struct regulator_config config) +{ + int id, ret; + unsigned int addr, reg; + struct regulator_dev *rdev; + struct palmas_reg_init *reg_init; + struct palmas_regs_info *rinfo; + struct regulator_desc *desc; + + for (id = ddata->smps_start; id <= ddata->smps_end; id++) { + /* + * Miss out regulators which are not available due + * to slaving configurations. + */ + desc = &pmic->desc[id]; + desc->n_linear_ranges = 3; + if ((id == TPS65917_REG_SMPS2) && pmic->smps12) + continue; + + /* Initialise sleep/init values from platform data */ + if (pdata && pdata->reg_init[id]) { reg_init = pdata->reg_init[id]; - else + ret = palmas_smps_init(pmic->palmas, id, reg_init); + if (ret) + return ret; + } else { reg_init = NULL; + } + rinfo = &ddata->palmas_regs_info[id]; - /* Miss out regulators which are not available due - * to alternate functions. + /* Register the regulators */ + desc->name = rinfo->name; + desc->id = id; + + /* + * Read and store the RANGE bit for later use + * This must be done before regulator is probed, + * otherwise we error in probe with unsupportable + * ranges. Read the current smps mode for later use. */ + addr = rinfo->vsel_addr; - /* Register the regulators */ - pmic->desc[id].name = palmas_regs_info[id].name; - pmic->desc[id].id = id; - pmic->desc[id].type = REGULATOR_VOLTAGE; - pmic->desc[id].owner = THIS_MODULE; + ret = palmas_smps_read(pmic->palmas, addr, ®); + if (ret) + return ret; + if (reg & TPS65917_SMPS1_VOLTAGE_RANGE) + pmic->range[id] = 1; - if (id < PALMAS_REG_REGEN1) { - pmic->desc[id].n_voltages = PALMAS_LDO_NUM_VOLTAGES; - if (reg_init && reg_init->roof_floor) - pmic->desc[id].ops = - &palmas_ops_ext_control_ldo; - else - pmic->desc[id].ops = &palmas_ops_ldo; - pmic->desc[id].min_uV = 900000; - pmic->desc[id].uV_step = 50000; - pmic->desc[id].linear_min_sel = 1; - pmic->desc[id].enable_time = 500; - pmic->desc[id].vsel_reg = - PALMAS_BASE_TO_REG(PALMAS_LDO_BASE, - palmas_regs_info[id].vsel_addr); - pmic->desc[id].vsel_mask = - PALMAS_LDO1_VOLTAGE_VSEL_MASK; - pmic->desc[id].enable_reg = - PALMAS_BASE_TO_REG(PALMAS_LDO_BASE, - palmas_regs_info[id].ctrl_addr); - pmic->desc[id].enable_mask = - PALMAS_LDO1_CTRL_MODE_ACTIVE; + if (pmic->range[id]) + desc->linear_ranges = smps_high_ranges; + else + desc->linear_ranges = smps_low_ranges; - /* Check if LDO8 is in tracking mode or not */ - if (pdata && (id == PALMAS_REG_LDO8) && - pdata->enable_ldo8_tracking) { - palmas_enable_ldo8_track(palmas); - pmic->desc[id].min_uV = 450000; - pmic->desc[id].uV_step = 25000; - } + if (reg_init && reg_init->roof_floor) + desc->ops = &tps65917_ops_ext_control_smps; + else + desc->ops = &tps65917_ops_smps; + desc->n_voltages = PALMAS_SMPS_NUM_VOLTAGES; + desc->vsel_reg = PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE, + rinfo->vsel_addr); + desc->vsel_mask = PALMAS_SMPS12_VOLTAGE_VSEL_MASK; + desc->ramp_delay = 2500; + + /* Read the smps mode for later use. */ + addr = rinfo->ctrl_addr; + ret = palmas_smps_read(pmic->palmas, addr, ®); + if (ret) + return ret; + pmic->current_reg_mode[id] = reg & + PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK; + desc->enable_reg = PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE, + rinfo->ctrl_addr); + desc->enable_mask = PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK; + /* set_mode overrides this value */ + desc->enable_val = SMPS_CTRL_MODE_ON; - /* LOD6 in vibrator mode will have enable time 2000us */ - if (pdata && pdata->ldo6_vibrator && - (id == PALMAS_REG_LDO6)) - pmic->desc[id].enable_time = 2000; - } else { - pmic->desc[id].n_voltages = 1; - if (reg_init && reg_init->roof_floor) - pmic->desc[id].ops = - &palmas_ops_ext_control_extreg; - else - pmic->desc[id].ops = &palmas_ops_extreg; - pmic->desc[id].enable_reg = - PALMAS_BASE_TO_REG(PALMAS_RESOURCE_BASE, - palmas_regs_info[id].ctrl_addr); - pmic->desc[id].enable_mask = - PALMAS_REGEN1_CTRL_MODE_ACTIVE; - } + desc->type = REGULATOR_VOLTAGE; + desc->owner = THIS_MODULE; if (pdata) config.init_data = pdata->reg_data[id]; else config.init_data = NULL; - pmic->desc[id].supply_name = palmas_regs_info[id].sname; - config.of_node = palmas_matches[id].of_node; + desc->supply_name = rinfo->sname; + config.of_node = ddata->palmas_matches[id].of_node; - rdev = devm_regulator_register(&pdev->dev, &pmic->desc[id], - &config); + rdev = devm_regulator_register(pmic->dev, desc, &config); if (IS_ERR(rdev)) { - dev_err(&pdev->dev, + dev_err(pmic->dev, "failed to register %s regulator\n", - pdev->name); + pdev_name); return PTR_ERR(rdev); } /* Save regulator for cleanup */ pmic->rdev[id] = rdev; + } - /* Initialise sleep/init values from platform data */ - if (pdata) { - reg_init = pdata->reg_init[id]; - if (reg_init) { - if (id < PALMAS_REG_REGEN1) - ret = palmas_ldo_init(palmas, - id, reg_init); - else - ret = palmas_extreg_init(palmas, - id, reg_init); - if (ret) - return ret; + return 0; +} + +static struct of_regulator_match palmas_matches[] = { + { .name = "smps12", }, + { .name = "smps123", }, + { .name = "smps3", }, + { .name = "smps45", }, + { .name = "smps457", }, + { .name = "smps6", }, + { .name = "smps7", }, + { .name = "smps8", }, + { .name = "smps9", }, + { .name = "smps10_out2", }, + { .name = "smps10_out1", }, + { .name = "ldo1", }, + { .name = "ldo2", }, + { .name = "ldo3", }, + { .name = "ldo4", }, + { .name = "ldo5", }, + { .name = "ldo6", }, + { .name = "ldo7", }, + { .name = "ldo8", }, + { .name = "ldo9", }, + { .name = "ldoln", }, + { .name = "ldousb", }, + { .name = "regen1", }, + { .name = "regen2", }, + { .name = "regen3", }, + { .name = "sysen1", }, + { .name = "sysen2", }, +}; + +static struct of_regulator_match tps65917_matches[] = { + { .name = "smps1", }, + { .name = "smps2", }, + { .name = "smps3", }, + { .name = "smps4", }, + { .name = "smps5", }, + { .name = "ldo1", }, + { .name = "ldo2", }, + { .name = "ldo3", }, + { .name = "ldo4", }, + { .name = "ldo5", }, + { .name = "regen1", }, + { .name = "regen2", }, + { .name = "regen3", }, + { .name = "sysen1", }, + { .name = "sysen2", }, +}; + +static struct palmas_pmic_driver_data palmas_ddata = { + .smps_start = PALMAS_REG_SMPS12, + .smps_end = PALMAS_REG_SMPS10_OUT1, + .ldo_begin = PALMAS_REG_LDO1, + .ldo_end = PALMAS_REG_LDOUSB, + .max_reg = PALMAS_NUM_REGS, + .palmas_regs_info = palmas_generic_regs_info, + .palmas_matches = palmas_matches, + .sleep_req_info = palma_sleep_req_info, + .smps_register = palmas_smps_registration, + .ldo_register = palmas_ldo_registration, +}; + +static struct palmas_pmic_driver_data tps65917_ddata = { + .smps_start = TPS65917_REG_SMPS1, + .smps_end = TPS65917_REG_SMPS5, + .ldo_begin = TPS65917_REG_LDO1, + .ldo_end = TPS65917_REG_LDO5, + .max_reg = TPS65917_NUM_REGS, + .palmas_regs_info = tps65917_regs_info, + .palmas_matches = tps65917_matches, + .sleep_req_info = tps65917_sleep_req_info, + .smps_register = tps65917_smps_registration, + .ldo_register = tps65917_ldo_registration, +}; + +static void palmas_dt_to_pdata(struct device *dev, + struct device_node *node, + struct palmas_pmic_platform_data *pdata, + struct palmas_pmic_driver_data *ddata) +{ + struct device_node *regulators; + u32 prop; + int idx, ret; + + node = of_node_get(node); + regulators = of_get_child_by_name(node, "regulators"); + if (!regulators) { + dev_info(dev, "regulator node not found\n"); + return; + } + + ret = of_regulator_match(dev, regulators, ddata->palmas_matches, + ddata->max_reg); + of_node_put(regulators); + if (ret < 0) { + dev_err(dev, "Error parsing regulator init data: %d\n", ret); + return; + } + + for (idx = 0; idx < ddata->max_reg; idx++) { + if (!ddata->palmas_matches[idx].init_data || + !ddata->palmas_matches[idx].of_node) + continue; + + pdata->reg_data[idx] = ddata->palmas_matches[idx].init_data; + + pdata->reg_init[idx] = devm_kzalloc(dev, + sizeof(struct palmas_reg_init), GFP_KERNEL); + + pdata->reg_init[idx]->warm_reset = + of_property_read_bool(ddata->palmas_matches[idx].of_node, + "ti,warm-reset"); + + ret = of_property_read_u32(ddata->palmas_matches[idx].of_node, + "ti,roof-floor", &prop); + /* EINVAL: Property not found */ + if (ret != -EINVAL) { + int econtrol; + + /* use default value, when no value is specified */ + econtrol = PALMAS_EXT_CONTROL_NSLEEP; + if (!ret) { + switch (prop) { + case 1: + econtrol = PALMAS_EXT_CONTROL_ENABLE1; + break; + case 2: + econtrol = PALMAS_EXT_CONTROL_ENABLE2; + break; + case 3: + econtrol = PALMAS_EXT_CONTROL_NSLEEP; + break; + default: + WARN_ON(1); + dev_warn(dev, + "%s: Invalid roof-floor option: %u\n", + palmas_matches[idx].name, prop); + break; + } } + pdata->reg_init[idx]->roof_floor = econtrol; } - } + ret = of_property_read_u32(ddata->palmas_matches[idx].of_node, + "ti,mode-sleep", &prop); + if (!ret) + pdata->reg_init[idx]->mode_sleep = prop; + + ret = of_property_read_bool(ddata->palmas_matches[idx].of_node, + "ti,smps-range"); + if (ret) + pdata->reg_init[idx]->vsel = + PALMAS_SMPS12_VOLTAGE_RANGE; - return 0; + if (idx == PALMAS_REG_LDO8) + pdata->enable_ldo8_tracking = of_property_read_bool( + ddata->palmas_matches[idx].of_node, + "ti,enable-ldo8-tracking"); + } + + pdata->ldo6_vibrator = of_property_read_bool(node, "ti,ldo6-vibrator"); } -static const struct of_device_id of_palmas_match_tbl[] = { - { .compatible = "ti,palmas-pmic", }, - { .compatible = "ti,twl6035-pmic", }, - { .compatible = "ti,twl6036-pmic", }, - { .compatible = "ti,twl6037-pmic", }, - { .compatible = "ti,tps65913-pmic", }, - { .compatible = "ti,tps65914-pmic", }, - { .compatible = "ti,tps80036-pmic", }, - { .compatible = "ti,tps659038-pmic", }, +static struct of_device_id of_palmas_match_tbl[] = { + { + .compatible = "ti,palmas-pmic", + .data = &palmas_ddata, + }, + { + .compatible = "ti,twl6035-pmic", + .data = &palmas_ddata, + }, + { + .compatible = "ti,twl6036-pmic", + .data = &palmas_ddata, + }, + { + .compatible = "ti,twl6037-pmic", + .data = &palmas_ddata, + }, + { + .compatible = "ti,tps65913-pmic", + .data = &palmas_ddata, + }, + { + .compatible = "ti,tps65914-pmic", + .data = &palmas_ddata, + }, + { + .compatible = "ti,tps80036-pmic", + .data = &palmas_ddata, + }, + { + .compatible = "ti,tps659038-pmic", + .data = &palmas_ddata, + }, + { + .compatible = "ti,tps65917-pmic", + .data = &tps65917_ddata, + }, { /* end */ } }; +static int palmas_regulators_probe(struct platform_device *pdev) +{ + struct palmas *palmas = dev_get_drvdata(pdev->dev.parent); + struct palmas_pmic_platform_data *pdata = dev_get_platdata(&pdev->dev); + struct device_node *node = pdev->dev.of_node; + struct palmas_pmic_driver_data *driver_data; + struct regulator_config config = { }; + struct palmas_pmic *pmic; + const char *pdev_name; + const struct of_device_id *match; + int ret = 0; + unsigned int reg; + + match = of_match_device(of_match_ptr(of_palmas_match_tbl), &pdev->dev); + + if (!match) + return -ENODATA; + + driver_data = (struct palmas_pmic_driver_data *)match->data; + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL); + if (!pmic) + return -ENOMEM; + + pmic->dev = &pdev->dev; + pmic->palmas = palmas; + palmas->pmic = pmic; + platform_set_drvdata(pdev, pmic); + pmic->palmas->pmic_ddata = driver_data; + + palmas_dt_to_pdata(&pdev->dev, node, pdata, driver_data); + + ret = palmas_smps_read(palmas, PALMAS_SMPS_CTRL, ®); + if (ret) + return ret; + + if (reg & PALMAS_SMPS_CTRL_SMPS12_SMPS123_EN) + pmic->smps123 = 1; + + if (reg & PALMAS_SMPS_CTRL_SMPS45_SMPS457_EN) + pmic->smps457 = 1; + + config.regmap = palmas->regmap[REGULATOR_SLAVE]; + config.dev = &pdev->dev; + config.driver_data = pmic; + pdev_name = pdev->name; + + ret = driver_data->smps_register(pmic, driver_data, pdata, pdev_name, + config); + if (ret) + return ret; + + ret = driver_data->ldo_register(pmic, driver_data, pdata, pdev_name, + config); + + return ret; +} + static struct platform_driver palmas_driver = { .driver = { .name = "palmas-pmic", diff --git a/drivers/regulator/tps65218-regulator.c b/drivers/regulator/tps65218-regulator.c index 69b4b775041..8b7a0a9ebdf 100644 --- a/drivers/regulator/tps65218-regulator.c +++ b/drivers/regulator/tps65218-regulator.c @@ -68,7 +68,7 @@ static const struct regulator_linear_range ldo1_dcdc3_ranges[] = { static const struct regulator_linear_range dcdc4_ranges[] = { REGULATOR_LINEAR_RANGE(1175000, 0x0, 0xf, 25000), - REGULATOR_LINEAR_RANGE(1550000, 0x10, 0x34, 50000), + REGULATOR_LINEAR_RANGE(1600000, 0x10, 0x34, 50000), }; static struct tps_info tps65218_pmic_regs[] = { @@ -209,7 +209,7 @@ static const struct regulator_desc regulators[] = { 1, -1, -1, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC6_EN, NULL, NULL, 0, 0), TPS65218_REGULATOR("LDO1", TPS65218_LDO_1, tps65218_ldo1_dcdc34_ops, 64, - TPS65218_REG_CONTROL_DCDC4, + TPS65218_REG_CONTROL_LDO1, TPS65218_CONTROL_LDO1_MASK, TPS65218_REG_ENABLE2, TPS65218_ENABLE2_LDO1_EN, NULL, ldo1_dcdc3_ranges, 2, 0), @@ -240,6 +240,7 @@ static int tps65218_regulator_probe(struct platform_device *pdev) config.init_data = init_data; config.driver_data = tps; config.regmap = tps->regmap; + config.of_node = pdev->dev.of_node; rdev = devm_regulator_register(&pdev->dev, ®ulators[id], &config); if (IS_ERR(rdev)) { |