diff options
Diffstat (limited to 'drivers/regulator/lp872x.c')
| -rw-r--r-- | drivers/regulator/lp872x.c | 279 |
1 files changed, 164 insertions, 115 deletions
diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c index 212c38eaba7..2e022aabd95 100644 --- a/drivers/regulator/lp872x.c +++ b/drivers/regulator/lp872x.c @@ -18,6 +18,9 @@ #include <linux/regulator/lp872x.h> #include <linux/regulator/driver.h> #include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/regulator/of_regulator.h> /* Registers : LP8720/8725 shared */ #define LP872X_GENERAL_CFG 0x00 @@ -86,6 +89,10 @@ #define EXTERN_DVS_USED 0 #define MAX_DELAY 6 +/* Default DVS Mode */ +#define LP8720_DEFAULT_DVS 0 +#define LP8725_DEFAULT_DVS BIT(2) + /* dump registers in regmap-debugfs */ #define MAX_REGISTERS 0x0F @@ -177,20 +184,6 @@ static inline int lp872x_update_bits(struct lp872x *lp, u8 addr, return regmap_update_bits(lp->regmap, addr, mask, data); } -static int _rdev_to_offset(struct regulator_dev *rdev) -{ - enum lp872x_regulator_id id = rdev_get_id(rdev); - - switch (id) { - case LP8720_ID_LDO1 ... LP8720_ID_BUCK: - return id; - case LP8725_ID_LDO1 ... LP8725_ID_BUCK2: - return id - LP8725_ID_BASE; - default: - return -EINVAL; - } -} - static int lp872x_get_timestep_usec(struct lp872x *lp) { enum lp872x_id chip = lp->chipid; @@ -218,7 +211,7 @@ static int lp872x_get_timestep_usec(struct lp872x *lp) ret = lp872x_read_byte(lp, LP872X_GENERAL_CFG, &val); if (ret) - return -EINVAL; + return ret; val = (val & mask) >> shift; if (val >= size) @@ -230,28 +223,20 @@ static int lp872x_get_timestep_usec(struct lp872x *lp) static int lp872x_regulator_enable_time(struct regulator_dev *rdev) { struct lp872x *lp = rdev_get_drvdata(rdev); - enum lp872x_regulator_id regulator = rdev_get_id(rdev); + enum lp872x_regulator_id rid = rdev_get_id(rdev); int time_step_us = lp872x_get_timestep_usec(lp); - int ret, offset; + int ret; u8 addr, val; if (time_step_us < 0) - return -EINVAL; - - switch (regulator) { - case LP8720_ID_LDO1 ... LP8720_ID_LDO5: - case LP8725_ID_LDO1 ... LP8725_ID_LILO2: - offset = _rdev_to_offset(rdev); - if (offset < 0) - return -EINVAL; + return time_step_us; - addr = LP872X_LDO1_VOUT + offset; - break; - case LP8720_ID_BUCK: - addr = LP8720_BUCK_VOUT1; + switch (rid) { + case LP8720_ID_LDO1 ... LP8720_ID_BUCK: + addr = LP872X_LDO1_VOUT + rid; break; - case LP8725_ID_BUCK1: - addr = LP8725_BUCK1_VOUT1; + case LP8725_ID_LDO1 ... LP8725_ID_BUCK1: + addr = LP872X_LDO1_VOUT + rid - LP8725_ID_BASE; break; case LP8725_ID_BUCK2: addr = LP8725_BUCK2_VOUT1; @@ -269,9 +254,9 @@ static int lp872x_regulator_enable_time(struct regulator_dev *rdev) return val > MAX_DELAY ? 0 : val * time_step_us; } -static void lp872x_set_dvs(struct lp872x *lp, int gpio) +static void lp872x_set_dvs(struct lp872x *lp, enum lp872x_dvs_sel dvs_sel, + int gpio) { - enum lp872x_dvs_sel dvs_sel = lp->pdata->dvs->vsel; enum lp872x_dvs_state state; state = dvs_sel == SEL_V1 ? DVS_HIGH : DVS_LOW; @@ -339,10 +324,10 @@ static int lp872x_buck_set_voltage_sel(struct regulator_dev *rdev, struct lp872x *lp = rdev_get_drvdata(rdev); enum lp872x_regulator_id buck = rdev_get_id(rdev); u8 addr, mask = LP872X_VOUT_M; - struct lp872x_dvs *dvs = lp->pdata->dvs; + struct lp872x_dvs *dvs = lp->pdata ? lp->pdata->dvs : NULL; if (dvs && gpio_is_valid(dvs->gpio)) - lp872x_set_dvs(lp, dvs->gpio); + lp872x_set_dvs(lp, dvs->vsel, dvs->gpio); addr = lp872x_select_buck_vout_addr(lp, buck); if (!lp872x_is_valid_buck_addr(addr)) @@ -374,8 +359,8 @@ static int lp8725_buck_set_current_limit(struct regulator_dev *rdev, { struct lp872x *lp = rdev_get_drvdata(rdev); enum lp872x_regulator_id buck = rdev_get_id(rdev); - int i, max = ARRAY_SIZE(lp8725_buck_uA); - u8 addr, val; + int i; + u8 addr; switch (buck) { case LP8725_ID_BUCK1: @@ -388,17 +373,15 @@ static int lp8725_buck_set_current_limit(struct regulator_dev *rdev, return -EINVAL; } - for (i = 0 ; i < max ; i++) + for (i = ARRAY_SIZE(lp8725_buck_uA) - 1; i >= 0; i--) { if (lp8725_buck_uA[i] >= min_uA && lp8725_buck_uA[i] <= max_uA) - break; - - if (i == max) - return -EINVAL; - - val = i << LP8725_BUCK_CL_S; + return lp872x_update_bits(lp, addr, + LP8725_BUCK_CL_M, + i << LP8725_BUCK_CL_S); + } - return lp872x_update_bits(lp, addr, LP8725_BUCK_CL_M, val); + return -EINVAL; } static int lp8725_buck_get_current_limit(struct regulator_dev *rdev) @@ -498,6 +481,7 @@ static unsigned int lp872x_buck_get_mode(struct regulator_dev *rdev) static struct regulator_ops lp872x_ldo_ops = { .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .enable = regulator_enable_regmap, @@ -508,6 +492,7 @@ static struct regulator_ops lp872x_ldo_ops = { static struct regulator_ops lp8720_buck_ops = { .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, .set_voltage_sel = lp872x_buck_set_voltage_sel, .get_voltage_sel = lp872x_buck_get_voltage_sel, .enable = regulator_enable_regmap, @@ -520,6 +505,7 @@ static struct regulator_ops lp8720_buck_ops = { static struct regulator_ops lp8725_buck_ops = { .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, .set_voltage_sel = lp872x_buck_set_voltage_sel, .get_voltage_sel = lp872x_buck_get_voltage_sel, .enable = regulator_enable_regmap, @@ -727,44 +713,21 @@ static struct regulator_desc lp8725_regulator_desc[] = { }, }; -static int lp872x_check_dvs_validity(struct lp872x *lp) -{ - struct lp872x_dvs *dvs = lp->pdata->dvs; - u8 val = 0; - int ret; - - ret = lp872x_read_byte(lp, LP872X_GENERAL_CFG, &val); - if (ret) - return ret; - - ret = 0; - if (lp->chipid == LP8720) { - if (val & LP8720_EXT_DVS_M) - ret = dvs ? 0 : -EINVAL; - } else { - if ((val & LP8725_DVS1_M) == EXTERN_DVS_USED) - ret = dvs ? 0 : -EINVAL; - } - - return ret; -} - static int lp872x_init_dvs(struct lp872x *lp) { int ret, gpio; - struct lp872x_dvs *dvs = lp->pdata->dvs; + struct lp872x_dvs *dvs = lp->pdata ? lp->pdata->dvs : NULL; enum lp872x_dvs_state pinstate; + u8 mask[] = { LP8720_EXT_DVS_M, LP8725_DVS1_M | LP8725_DVS2_M }; + u8 default_dvs_mode[] = { LP8720_DEFAULT_DVS, LP8725_DEFAULT_DVS }; - ret = lp872x_check_dvs_validity(lp); - if (ret) { - dev_warn(lp->dev, "invalid dvs data: %d\n", ret); - return ret; - } + if (!dvs) + goto set_default_dvs_mode; gpio = dvs->gpio; if (!gpio_is_valid(gpio)) { - dev_err(lp->dev, "invalid gpio: %d\n", gpio); - return -EINVAL; + dev_warn(lp->dev, "invalid gpio: %d\n", gpio); + goto set_default_dvs_mode; } pinstate = dvs->init_state; @@ -778,6 +741,10 @@ static int lp872x_init_dvs(struct lp872x *lp) lp->dvs_gpio = gpio; return 0; + +set_default_dvs_mode: + return lp872x_update_bits(lp, LP872X_GENERAL_CFG, mask[lp->chipid], + default_dvs_mode[lp->chipid]); } static int lp872x_config(struct lp872x *lp) @@ -785,24 +752,29 @@ static int lp872x_config(struct lp872x *lp) struct lp872x_platform_data *pdata = lp->pdata; int ret; - if (!pdata->update_config) - return 0; + if (!pdata || !pdata->update_config) + goto init_dvs; ret = lp872x_write_byte(lp, LP872X_GENERAL_CFG, pdata->general_config); if (ret) return ret; +init_dvs: return lp872x_init_dvs(lp); } static struct regulator_init_data *lp872x_find_regulator_init_data(int id, struct lp872x *lp) { + struct lp872x_platform_data *pdata = lp->pdata; int i; + if (!pdata) + return NULL; + for (i = 0; i < lp->num_regulators; i++) { - if (lp->pdata->regulator_data[i].id == id) - return lp->pdata->regulator_data[i].init_data; + if (pdata->regulator_data[i].id == id) + return pdata->regulator_data[i].init_data; } return NULL; @@ -813,9 +785,9 @@ static int lp872x_regulator_register(struct lp872x *lp) struct regulator_desc *desc; struct regulator_config cfg = { }; struct regulator_dev *rdev; - int i, ret; + int i; - for (i = 0 ; i < lp->num_regulators ; i++) { + for (i = 0; i < lp->num_regulators; i++) { desc = (lp->chipid == LP8720) ? &lp8720_regulator_desc[i] : &lp8725_regulator_desc[i]; @@ -824,34 +796,16 @@ static int lp872x_regulator_register(struct lp872x *lp) cfg.driver_data = lp; cfg.regmap = lp->regmap; - rdev = regulator_register(desc, &cfg); + rdev = devm_regulator_register(lp->dev, desc, &cfg); if (IS_ERR(rdev)) { dev_err(lp->dev, "regulator register err"); - ret = PTR_ERR(rdev); - goto err; + return PTR_ERR(rdev); } *(lp->regulators + i) = rdev; } return 0; -err: - while (--i >= 0) { - rdev = *(lp->regulators + i); - regulator_unregister(rdev); - } - return ret; -} - -static void lp872x_regulator_unregister(struct lp872x *lp) -{ - struct regulator_dev *rdev; - int i; - - for (i = 0 ; i < lp->num_regulators ; i++) { - rdev = *(lp->regulators + i); - regulator_unregister(rdev); - } } static const struct regmap_config lp872x_regmap_config = { @@ -860,20 +814,116 @@ static const struct regmap_config lp872x_regmap_config = { .max_register = MAX_REGISTERS, }; +#ifdef CONFIG_OF + +#define LP872X_VALID_OPMODE (REGULATOR_MODE_FAST | REGULATOR_MODE_NORMAL) + +static struct of_regulator_match lp8720_matches[] = { + { .name = "ldo1", .driver_data = (void *)LP8720_ID_LDO1, }, + { .name = "ldo2", .driver_data = (void *)LP8720_ID_LDO2, }, + { .name = "ldo3", .driver_data = (void *)LP8720_ID_LDO3, }, + { .name = "ldo4", .driver_data = (void *)LP8720_ID_LDO4, }, + { .name = "ldo5", .driver_data = (void *)LP8720_ID_LDO5, }, + { .name = "buck", .driver_data = (void *)LP8720_ID_BUCK, }, +}; + +static struct of_regulator_match lp8725_matches[] = { + { .name = "ldo1", .driver_data = (void *)LP8725_ID_LDO1, }, + { .name = "ldo2", .driver_data = (void *)LP8725_ID_LDO2, }, + { .name = "ldo3", .driver_data = (void *)LP8725_ID_LDO3, }, + { .name = "ldo4", .driver_data = (void *)LP8725_ID_LDO4, }, + { .name = "ldo5", .driver_data = (void *)LP8725_ID_LDO5, }, + { .name = "lilo1", .driver_data = (void *)LP8725_ID_LILO1, }, + { .name = "lilo2", .driver_data = (void *)LP8725_ID_LILO2, }, + { .name = "buck1", .driver_data = (void *)LP8725_ID_BUCK1, }, + { .name = "buck2", .driver_data = (void *)LP8725_ID_BUCK2, }, +}; + +static struct lp872x_platform_data +*lp872x_populate_pdata_from_dt(struct device *dev, enum lp872x_id which) +{ + 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; + u8 dvs_state; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + goto out; + + of_property_read_u8(np, "ti,general-config", &pdata->general_config); + if (of_find_property(np, "ti,update-config", NULL)) + pdata->update_config = true; + + pdata->dvs = devm_kzalloc(dev, sizeof(struct lp872x_dvs), GFP_KERNEL); + if (!pdata->dvs) + goto out; + + pdata->dvs->gpio = of_get_named_gpio(np, "ti,dvs-gpio", 0); + of_property_read_u8(np, "ti,dvs-vsel", (u8 *)&pdata->dvs->vsel); + of_property_read_u8(np, "ti,dvs-state", &dvs_state); + pdata->dvs->init_state = dvs_state ? DVS_HIGH : DVS_LOW; + + if (of_get_child_count(np) == 0) + goto out; + + switch (which) { + case LP8720: + match = lp8720_matches; + num_matches = ARRAY_SIZE(lp8720_matches); + break; + case LP8725: + match = lp8725_matches; + num_matches = ARRAY_SIZE(lp8725_matches); + break; + default: + goto out; + } + + count = of_regulator_match(dev, np, match, num_matches); + if (count <= 0) + goto out; + + for (i = 0; i < num_matches; i++) { + 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; +} +#else +static struct lp872x_platform_data +*lp872x_populate_pdata_from_dt(struct device *dev, enum lp872x_id which) +{ + return NULL; +} +#endif + static int lp872x_probe(struct i2c_client *cl, const struct i2c_device_id *id) { struct lp872x *lp; - struct lp872x_platform_data *pdata = cl->dev.platform_data; int ret, size, num_regulators; const int lp872x_num_regulators[] = { [LP8720] = LP8720_NUM_REGULATORS, [LP8725] = LP8725_NUM_REGULATORS, }; - if (!pdata) { - dev_err(&cl->dev, "no platform data\n"); - return -EINVAL; - } + if (cl->dev.of_node) + cl->dev.platform_data = lp872x_populate_pdata_from_dt(&cl->dev, + (enum lp872x_id)id->driver_data); lp = devm_kzalloc(&cl->dev, sizeof(struct lp872x), GFP_KERNEL); if (!lp) @@ -894,7 +944,7 @@ static int lp872x_probe(struct i2c_client *cl, const struct i2c_device_id *id) } lp->dev = &cl->dev; - lp->pdata = pdata; + lp->pdata = dev_get_platdata(&cl->dev); lp->chipid = id->driver_data; lp->num_regulators = num_regulators; i2c_set_clientdata(cl, lp); @@ -911,13 +961,12 @@ err_dev: return ret; } -static int __devexit lp872x_remove(struct i2c_client *cl) -{ - struct lp872x *lp = i2c_get_clientdata(cl); - - lp872x_regulator_unregister(lp); - return 0; -} +static const struct of_device_id lp872x_dt_ids[] = { + { .compatible = "ti,lp8720", }, + { .compatible = "ti,lp8725", }, + { } +}; +MODULE_DEVICE_TABLE(of, lp872x_dt_ids); static const struct i2c_device_id lp872x_ids[] = { {"lp8720", LP8720}, @@ -930,9 +979,9 @@ static struct i2c_driver lp872x_driver = { .driver = { .name = "lp872x", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(lp872x_dt_ids), }, .probe = lp872x_probe, - .remove = __devexit_p(lp872x_remove), .id_table = lp872x_ids, }; |
