From 2c652a98ca556cca7749c184f0246315367bfad4 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 2 Sep 2015 15:46:51 -0700 Subject: regulator: qcom_smd: Handle big endian CPUs The smd rpm structures are always in little endian, but this driver is not capable of being used on big endian CPUs. Annotate the little endian data members and update the code to do the proper byte swapping. Signed-off-by: Stephen Boyd Signed-off-by: Mark Brown --- drivers/regulator/qcom_smd-regulator.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c index 9c6167dd2c8b..b72c693e29ff 100644 --- a/drivers/regulator/qcom_smd-regulator.c +++ b/drivers/regulator/qcom_smd-regulator.c @@ -36,9 +36,9 @@ struct qcom_rpm_reg { }; struct rpm_regulator_req { - u32 key; - u32 nbytes; - u32 value; + __le32 key; + __le32 nbytes; + __le32 value; }; #define RPM_KEY_SWEN 0x6e657773 /* "swen" */ @@ -62,9 +62,9 @@ static int rpm_reg_enable(struct regulator_dev *rdev) struct rpm_regulator_req req; int ret; - req.key = RPM_KEY_SWEN; - req.nbytes = sizeof(u32); - req.value = 1; + req.key = cpu_to_le32(RPM_KEY_SWEN); + req.nbytes = cpu_to_le32(sizeof(u32)); + req.value = cpu_to_le32(1); ret = rpm_reg_write_active(vreg, &req, sizeof(req)); if (!ret) @@ -86,8 +86,8 @@ static int rpm_reg_disable(struct regulator_dev *rdev) struct rpm_regulator_req req; int ret; - req.key = RPM_KEY_SWEN; - req.nbytes = sizeof(u32); + req.key = cpu_to_le32(RPM_KEY_SWEN); + req.nbytes = cpu_to_le32(sizeof(u32)); req.value = 0; ret = rpm_reg_write_active(vreg, &req, sizeof(req)); @@ -113,9 +113,9 @@ static int rpm_reg_set_voltage(struct regulator_dev *rdev, struct rpm_regulator_req req; int ret = 0; - req.key = RPM_KEY_UV; - req.nbytes = sizeof(u32); - req.value = min_uV; + req.key = cpu_to_le32(RPM_KEY_UV); + req.nbytes = cpu_to_le32(sizeof(u32)); + req.value = cpu_to_le32(min_uV); ret = rpm_reg_write_active(vreg, &req, sizeof(req)); if (!ret) @@ -129,9 +129,9 @@ static int rpm_reg_set_load(struct regulator_dev *rdev, int load_uA) struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); struct rpm_regulator_req req; - req.key = RPM_KEY_MA; - req.nbytes = sizeof(u32); - req.value = load_uA; + req.key = cpu_to_le32(RPM_KEY_MA); + req.nbytes = cpu_to_le32(sizeof(u32)); + req.value = cpu_to_le32(load_uA); return rpm_reg_write_active(vreg, &req, sizeof(req)); } -- cgit v1.2.3 From f3f400e760303b8542bf91c8372fecf19cf07fab Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 11 Sep 2015 04:26:56 +0200 Subject: regulator: bcm590xx: Remove unneeded semicolon It's clearly a typo error that just creates a null statement so remove it. Signed-off-by: Javier Martinez Canillas Signed-off-by: Mark Brown --- drivers/regulator/bcm590xx-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/bcm590xx-regulator.c b/drivers/regulator/bcm590xx-regulator.c index 628430bdc312..76b01835dcb4 100644 --- a/drivers/regulator/bcm590xx-regulator.c +++ b/drivers/regulator/bcm590xx-regulator.c @@ -244,7 +244,7 @@ static int bcm590xx_get_enable_register(int id) break; case BCM590XX_REG_VBUS: reg = BCM590XX_OTG_CTRL; - }; + } return reg; -- cgit v1.2.3 From 424fb281d6dff1c0fef2a402de3b3819b7a91a87 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 11 Sep 2015 04:26:57 +0200 Subject: regulator: da9063: Remove unneeded semicolon It's clearly a typo error that just creates a null statement so remove it. Signed-off-by: Javier Martinez Canillas Signed-off-by: Mark Brown --- drivers/regulator/da9063-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/da9063-regulator.c b/drivers/regulator/da9063-regulator.c index aed1ad3dc964..536e931eb921 100644 --- a/drivers/regulator/da9063-regulator.c +++ b/drivers/regulator/da9063-regulator.c @@ -698,7 +698,7 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt( rdata->initdata = da9063_matches[i].init_data; n++; - }; + } *da9063_reg_matches = da9063_matches; return pdata; -- cgit v1.2.3 From 7ebcf26c39205ca8d61c178dcd3f5be4f25b1309 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 16 Sep 2015 12:10:26 -0700 Subject: regulator: core: Make error messages more informative The same error print exists 4 times in the regulator core : operation not allowed Unfortunately, seeing this in the dmesg is not very informative. Add what type of operation is not allowed to the message so that these errors are unique, hopefully pointing developers in the right direction : drms operation not allowed : voltage operation not allowed : current operation not allowed : mode operation not allowed Signed-off-by: Stephen Boyd Signed-off-by: Mark Brown --- drivers/regulator/core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 7a85ac9e32c5..065fe877dcf5 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -180,7 +180,7 @@ static int regulator_check_voltage(struct regulator_dev *rdev, return -ENODEV; } if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) { - rdev_err(rdev, "operation not allowed\n"); + rdev_err(rdev, "voltage operation not allowed\n"); return -EPERM; } @@ -240,7 +240,7 @@ static int regulator_check_current_limit(struct regulator_dev *rdev, return -ENODEV; } if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_CURRENT)) { - rdev_err(rdev, "operation not allowed\n"); + rdev_err(rdev, "current operation not allowed\n"); return -EPERM; } @@ -277,7 +277,7 @@ static int regulator_mode_constrain(struct regulator_dev *rdev, int *mode) return -ENODEV; } if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_MODE)) { - rdev_err(rdev, "operation not allowed\n"); + rdev_err(rdev, "mode operation not allowed\n"); return -EPERM; } @@ -301,7 +301,7 @@ static int regulator_check_drms(struct regulator_dev *rdev) return -ENODEV; } if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) { - rdev_dbg(rdev, "operation not allowed\n"); + rdev_dbg(rdev, "drms operation not allowed\n"); return -EPERM; } return 0; -- cgit v1.2.3 From b263d20373d7726dd3ac0cd5e32f123e69a02847 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Tue, 18 Aug 2015 15:14:06 -0700 Subject: regulator: Introduce property to flag set-load support Introduce "regulator-allow-set-load" property to make it possible to flag in the board configuration that a regulator is allowed to have the load requirements changed. Signed-off-by: Bjorn Andersson Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/regulator/regulator.txt | 1 + drivers/regulator/of_regulator.c | 3 +++ 2 files changed, 4 insertions(+) (limited to 'drivers/regulator') diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt index 24bd422cecd5..1d112fc456aa 100644 --- a/Documentation/devicetree/bindings/regulator/regulator.txt +++ b/Documentation/devicetree/bindings/regulator/regulator.txt @@ -11,6 +11,7 @@ Optional properties: - regulator-always-on: boolean, regulator should never be disabled - regulator-boot-on: bootloader/firmware enabled regulator - regulator-allow-bypass: allow the regulator to go into bypass mode +- regulator-allow-set-load: allow the regulator performance level to be configured - -supply: phandle to the parent supply/regulator node - regulator-ramp-delay: ramp delay for regulator(in uV/uS) For hardware which supports disabling ramp rate, it should be explicitly diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 250700c853bf..499e437c7e91 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -76,6 +76,9 @@ static void of_get_regulation_constraints(struct device_node *np, if (of_property_read_bool(np, "regulator-allow-bypass")) constraints->valid_ops_mask |= REGULATOR_CHANGE_BYPASS; + if (of_property_read_bool(np, "regulator-allow-set-load")) + constraints->valid_ops_mask |= REGULATOR_CHANGE_DRMS; + ret = of_property_read_u32(np, "regulator-ramp-delay", &pval); if (!ret) { if (pval) -- cgit v1.2.3 From 2d3eda67dd2a02087a2ae6916c92ee1966945b88 Mon Sep 17 00:00:00 2001 From: Thomas Elste Date: Mon, 21 Sep 2015 16:30:47 +0200 Subject: regulator: tps65023: add device tree support Add device tree based initialization support for tps65023 regulators. Therefore add macros for regulator definition setting of_match and regulators_node members. Add initialization of regulator_desc data using these macros. Remove old regulator_desc initialization. Add device tree binding document for tps65023 regulators. Signed-off-by: Thomas Elste Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/tps65023.txt | 60 +++++ drivers/regulator/tps65023-regulator.c | 282 ++++++++------------- 2 files changed, 168 insertions(+), 174 deletions(-) create mode 100644 Documentation/devicetree/bindings/regulator/tps65023.txt (limited to 'drivers/regulator') diff --git a/Documentation/devicetree/bindings/regulator/tps65023.txt b/Documentation/devicetree/bindings/regulator/tps65023.txt new file mode 100644 index 000000000000..a4714e4da370 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/tps65023.txt @@ -0,0 +1,60 @@ +TPS65023 family of regulators + +Required properties: +- compatible: Must be one of the following. + "ti,tps65020", + "ti,tps65021", + "ti,tps65023", +- reg: I2C slave address +- regulators: list of regulators provided by this controller, must be named + after their hardware counterparts: VDCDC[1-3] and LDO[1-2] +- regulators: This is the list of child nodes that specify the regulator + initialization data for defined regulators. The definition for each of + these nodes is defined using the standard binding for regulators found at + Documentation/devicetree/bindings/regulator/regulator.txt. + +Each regulator is defined using the standard binding for regulators. + +Example: + + tps65023@48 { + compatible = "ti,tps65023"; + reg = <0x48>; + + regulators { + VDCDC1 { + regulator-name = "vdd_mpu"; + regulator-always-on; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + VDCDC2 { + regulator-name = "vdd_core"; + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + VDCDC3 { + regulator-name = "vdd_io"; + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + LDO1 { + regulator-name = "vdd_usb18"; + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + LDO2 { + regulator-name = "vdd_usb33"; + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + }; + }; diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c index 5cc19b44974a..d2c3d7cc35f5 100644 --- a/drivers/regulator/tps65023-regulator.c +++ b/drivers/regulator/tps65023-regulator.c @@ -86,6 +86,42 @@ #define TPS65023_MAX_REG_ID TPS65023_LDO_2 +#define TPS65023_REGULATOR_DCDC(_num, _t, _em) \ + { \ + .name = "VDCDC"#_num, \ + .of_match = of_match_ptr("VDCDC"#_num), \ + .regulators_node = of_match_ptr("regulators"), \ + .id = TPS65023_DCDC_##_num, \ + .n_voltages = ARRAY_SIZE(_t), \ + .ops = &tps65023_dcdc_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .volt_table = _t, \ + .vsel_reg = TPS65023_REG_DEF_CORE, \ + .vsel_mask = ARRAY_SIZE(_t) - 1, \ + .enable_mask = _em, \ + .enable_reg = TPS65023_REG_REG_CTRL, \ + .apply_reg = TPS65023_REG_CON_CTRL2, \ + .apply_bit = TPS65023_REG_CTRL2_GO, \ + } \ + +#define TPS65023_REGULATOR_LDO(_num, _t, _vm) \ + { \ + .name = "LDO"#_num, \ + .of_match = of_match_ptr("LDO"#_num), \ + .regulators_node = of_match_ptr("regulators"), \ + .id = TPS65023_LDO_##_num, \ + .n_voltages = ARRAY_SIZE(_t), \ + .ops = &tps65023_ldo_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .volt_table = _t, \ + .vsel_reg = TPS65023_REG_LDO_CTRL, \ + .vsel_mask = _vm, \ + .enable_mask = 1 << (_num), \ + .enable_reg = TPS65023_REG_REG_CTRL, \ + } \ + /* Supported voltage values for regulators */ static const unsigned int VCORE_VSEL_table[] = { 800000, 825000, 850000, 875000, @@ -124,25 +160,16 @@ static const unsigned int TPS65023_LDO2_VSEL_table[] = { 2500000, 2800000, 3000000, 3300000, }; -/* Regulator specific details */ -struct tps_info { - const char *name; - u8 table_len; - const unsigned int *table; -}; - /* PMIC details */ struct tps_pmic { - struct regulator_desc desc[TPS65023_NUM_REGULATOR]; struct regulator_dev *rdev[TPS65023_NUM_REGULATOR]; - const struct tps_info *info[TPS65023_NUM_REGULATOR]; + const struct tps_driver_data *driver_data; struct regmap *regmap; - u8 core_regulator; }; /* Struct passed as driver data */ struct tps_driver_data { - const struct tps_info *info; + const struct regulator_desc *desc; u8 core_regulator; }; @@ -154,7 +181,7 @@ static int tps65023_dcdc_get_voltage_sel(struct regulator_dev *dev) if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3) return -EINVAL; - if (dcdc != tps->core_regulator) + if (dcdc != tps->driver_data->core_regulator) return 0; return regulator_get_voltage_sel_regmap(dev); @@ -166,7 +193,7 @@ static int tps65023_dcdc_set_voltage_sel(struct regulator_dev *dev, struct tps_pmic *tps = rdev_get_drvdata(dev); int dcdc = rdev_get_id(dev); - if (dcdc != tps->core_regulator) + if (dcdc != tps->driver_data->core_regulator) return -EINVAL; return regulator_set_voltage_sel_regmap(dev, selector); @@ -199,30 +226,60 @@ static const struct regmap_config tps65023_regmap_config = { .val_bits = 8, }; +static const struct regulator_desc tps65020_regulators[] = { + TPS65023_REGULATOR_DCDC(1, DCDC_FIXED_3300000_VSEL_table, 0x20), + TPS65023_REGULATOR_DCDC(2, DCDC_FIXED_1800000_VSEL_table, 0x10), + TPS65023_REGULATOR_DCDC(3, VCORE_VSEL_table, 0x08), + TPS65023_REGULATOR_LDO(1, TPS65020_LDO_VSEL_table, 0x07), + TPS65023_REGULATOR_LDO(2, TPS65020_LDO_VSEL_table, 0x70), +}; + +static const struct regulator_desc tps65021_regulators[] = { + TPS65023_REGULATOR_DCDC(1, DCDC_FIXED_3300000_VSEL_table, 0x20), + TPS65023_REGULATOR_DCDC(2, DCDC_FIXED_1800000_VSEL_table, 0x10), + TPS65023_REGULATOR_DCDC(3, VCORE_VSEL_table, 0x08), + TPS65023_REGULATOR_LDO(1, TPS65023_LDO1_VSEL_table, 0x07), + TPS65023_REGULATOR_LDO(2, TPS65023_LDO2_VSEL_table, 0x70), +}; + +static const struct regulator_desc tps65023_regulators[] = { + TPS65023_REGULATOR_DCDC(1, VCORE_VSEL_table, 0x20), + TPS65023_REGULATOR_DCDC(2, DCDC_FIXED_3300000_VSEL_table, 0x10), + TPS65023_REGULATOR_DCDC(3, DCDC_FIXED_1800000_VSEL_table, 0x08), + TPS65023_REGULATOR_LDO(1, TPS65023_LDO1_VSEL_table, 0x07), + TPS65023_REGULATOR_LDO(2, TPS65023_LDO2_VSEL_table, 0x70), +}; + +static struct tps_driver_data tps65020_drv_data = { + .desc = tps65020_regulators, + .core_regulator = TPS65023_DCDC_3, +}; + +static struct tps_driver_data tps65021_drv_data = { + .desc = tps65021_regulators, + .core_regulator = TPS65023_DCDC_3, +}; + +static struct tps_driver_data tps65023_drv_data = { + .desc = tps65023_regulators, + .core_regulator = TPS65023_DCDC_1, +}; + static int tps_65023_probe(struct i2c_client *client, const struct i2c_device_id *id) { - const struct tps_driver_data *drv_data = (void *)id->driver_data; - const struct tps_info *info = drv_data->info; + struct regulator_init_data *init_data = dev_get_platdata(&client->dev); struct regulator_config config = { }; - struct regulator_init_data *init_data; - struct regulator_dev *rdev; struct tps_pmic *tps; int i; int error; - /** - * init_data points to array of regulator_init structures - * coming from the board-evm file. - */ - init_data = dev_get_platdata(&client->dev); - if (!init_data) - return -EIO; - tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); if (!tps) return -ENOMEM; + tps->driver_data = (struct tps_driver_data *)id->driver_data; + tps->regmap = devm_regmap_init_i2c(client, &tps65023_regmap_config); if (IS_ERR(tps->regmap)) { error = PTR_ERR(tps->regmap); @@ -232,58 +289,22 @@ static int tps_65023_probe(struct i2c_client *client, } /* common for all regulators */ - tps->core_regulator = drv_data->core_regulator; - - for (i = 0; i < TPS65023_NUM_REGULATOR; i++, info++, init_data++) { - /* Store regulator specific information */ - tps->info[i] = info; - - tps->desc[i].name = info->name; - tps->desc[i].id = i; - tps->desc[i].n_voltages = info->table_len; - tps->desc[i].volt_table = info->table; - tps->desc[i].ops = (i > TPS65023_DCDC_3 ? - &tps65023_ldo_ops : &tps65023_dcdc_ops); - tps->desc[i].type = REGULATOR_VOLTAGE; - tps->desc[i].owner = THIS_MODULE; - - tps->desc[i].enable_reg = TPS65023_REG_REG_CTRL; - switch (i) { - case TPS65023_LDO_1: - tps->desc[i].vsel_reg = TPS65023_REG_LDO_CTRL; - tps->desc[i].vsel_mask = 0x07; - tps->desc[i].enable_mask = 1 << 1; - break; - case TPS65023_LDO_2: - tps->desc[i].vsel_reg = TPS65023_REG_LDO_CTRL; - tps->desc[i].vsel_mask = 0x70; - tps->desc[i].enable_mask = 1 << 2; - break; - default: /* DCDCx */ - tps->desc[i].enable_mask = - 1 << (TPS65023_NUM_REGULATOR - i); - tps->desc[i].vsel_reg = TPS65023_REG_DEF_CORE; - tps->desc[i].vsel_mask = info->table_len - 1; - tps->desc[i].apply_reg = TPS65023_REG_CON_CTRL2; - tps->desc[i].apply_bit = TPS65023_REG_CTRL2_GO; - } + config.dev = &client->dev; + config.driver_data = tps; + config.regmap = tps->regmap; - config.dev = &client->dev; - config.init_data = init_data; - config.driver_data = tps; - config.regmap = tps->regmap; + for (i = 0; i < TPS65023_NUM_REGULATOR; i++) { + if (init_data) + config.init_data = &init_data[i]; /* Register the regulators */ - rdev = devm_regulator_register(&client->dev, &tps->desc[i], - &config); - if (IS_ERR(rdev)) { + tps->rdev[i] = devm_regulator_register(&client->dev, + &tps->driver_data->desc[i], &config); + if (IS_ERR(tps->rdev[i])) { dev_err(&client->dev, "failed to register %s\n", id->name); - return PTR_ERR(rdev); + return PTR_ERR(tps->rdev[i]); } - - /* Save regulator for cleanup */ - tps->rdev[i] = rdev; } i2c_set_clientdata(client, tps); @@ -296,120 +317,33 @@ static int tps_65023_probe(struct i2c_client *client, return 0; } -static const struct tps_info tps65020_regs[] = { - { - .name = "VDCDC1", - .table_len = ARRAY_SIZE(DCDC_FIXED_3300000_VSEL_table), - .table = DCDC_FIXED_3300000_VSEL_table, - }, - { - .name = "VDCDC2", - .table_len = ARRAY_SIZE(DCDC_FIXED_1800000_VSEL_table), - .table = DCDC_FIXED_1800000_VSEL_table, - }, - { - .name = "VDCDC3", - .table_len = ARRAY_SIZE(VCORE_VSEL_table), - .table = VCORE_VSEL_table, - }, - { - .name = "LDO1", - .table_len = ARRAY_SIZE(TPS65020_LDO_VSEL_table), - .table = TPS65020_LDO_VSEL_table, - }, - { - .name = "LDO2", - .table_len = ARRAY_SIZE(TPS65020_LDO_VSEL_table), - .table = TPS65020_LDO_VSEL_table, - }, -}; - -static const struct tps_info tps65021_regs[] = { - { - .name = "VDCDC1", - .table_len = ARRAY_SIZE(DCDC_FIXED_3300000_VSEL_table), - .table = DCDC_FIXED_3300000_VSEL_table, - }, - { - .name = "VDCDC2", - .table_len = ARRAY_SIZE(DCDC_FIXED_1800000_VSEL_table), - .table = DCDC_FIXED_1800000_VSEL_table, - }, - { - .name = "VDCDC3", - .table_len = ARRAY_SIZE(VCORE_VSEL_table), - .table = VCORE_VSEL_table, - }, - { - .name = "LDO1", - .table_len = ARRAY_SIZE(TPS65023_LDO1_VSEL_table), - .table = TPS65023_LDO1_VSEL_table, - }, - { - .name = "LDO2", - .table_len = ARRAY_SIZE(TPS65023_LDO2_VSEL_table), - .table = TPS65023_LDO2_VSEL_table, - }, +static const struct of_device_id tps65023_of_match[] = { + { .compatible = "ti,tps65020", .data = &tps65020_drv_data}, + { .compatible = "ti,tps65021", .data = &tps65021_drv_data}, + { .compatible = "ti,tps65023", .data = &tps65023_drv_data}, + {}, }; +MODULE_DEVICE_TABLE(of, tps65023_of_match); -static const struct tps_info tps65023_regs[] = { - { - .name = "VDCDC1", - .table_len = ARRAY_SIZE(VCORE_VSEL_table), - .table = VCORE_VSEL_table, - }, - { - .name = "VDCDC2", - .table_len = ARRAY_SIZE(DCDC_FIXED_3300000_VSEL_table), - .table = DCDC_FIXED_3300000_VSEL_table, - }, - { - .name = "VDCDC3", - .table_len = ARRAY_SIZE(DCDC_FIXED_1800000_VSEL_table), - .table = DCDC_FIXED_1800000_VSEL_table, - }, - { - .name = "LDO1", - .table_len = ARRAY_SIZE(TPS65023_LDO1_VSEL_table), - .table = TPS65023_LDO1_VSEL_table, - }, +static const struct i2c_device_id tps_65023_id[] = { { - .name = "LDO2", - .table_len = ARRAY_SIZE(TPS65023_LDO2_VSEL_table), - .table = TPS65023_LDO2_VSEL_table, + .name = "tps65023", + .driver_data = (kernel_ulong_t)&tps65023_drv_data + }, { + .name = "tps65021", + .driver_data = (kernel_ulong_t)&tps65021_drv_data + }, { + .name = "tps65020", + .driver_data = (kernel_ulong_t)&tps65020_drv_data }, -}; - -static struct tps_driver_data tps65020_drv_data = { - .info = tps65020_regs, - .core_regulator = TPS65023_DCDC_3, -}; - -static struct tps_driver_data tps65021_drv_data = { - .info = tps65021_regs, - .core_regulator = TPS65023_DCDC_3, -}; - -static struct tps_driver_data tps65023_drv_data = { - .info = tps65023_regs, - .core_regulator = TPS65023_DCDC_1, -}; - -static const struct i2c_device_id tps_65023_id[] = { - {.name = "tps65023", - .driver_data = (unsigned long) &tps65023_drv_data}, - {.name = "tps65021", - .driver_data = (unsigned long) &tps65021_drv_data,}, - {.name = "tps65020", - .driver_data = (unsigned long) &tps65020_drv_data}, { }, }; - MODULE_DEVICE_TABLE(i2c, tps_65023_id); static struct i2c_driver tps_65023_i2c_driver = { .driver = { .name = "tps65023", + .of_match_table = of_match_ptr(tps65023_of_match), }, .probe = tps_65023_probe, .id_table = tps_65023_id, -- cgit v1.2.3 From 85f3b4311629defd68eb2b9779fda593d8fb7728 Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Mon, 21 Sep 2015 16:02:47 +0200 Subject: regulator: core: Remove regulator_list As we are already registering a device with regulator_class for each regulator device, regulator_list is redundant and can be replaced with calls to class_find_device() and class_for_each_device(). Signed-off-by: Tomeu Vizoso Signed-off-by: Mark Brown --- drivers/regulator/core.c | 255 ++++++++++++++++++++++++++++++----------------- 1 file changed, 164 insertions(+), 91 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 7a85ac9e32c5..57a5deb6a949 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -51,7 +51,6 @@ pr_debug("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) static DEFINE_MUTEX(regulator_list_mutex); -static LIST_HEAD(regulator_list); static LIST_HEAD(regulator_map_list); static LIST_HEAD(regulator_ena_gpio_list); static LIST_HEAD(regulator_supply_alias_list); @@ -59,6 +58,8 @@ static bool has_full_constraints; static struct dentry *debugfs_root; +static struct class regulator_class; + /* * struct regulator_map * @@ -1325,6 +1326,47 @@ static void regulator_supply_alias(struct device **dev, const char **supply) } } +static int of_node_match(struct device *dev, const void *data) +{ + return dev->of_node == data; +} + +static struct regulator_dev *of_find_regulator_by_node(struct device_node *np) +{ + struct device *dev; + + dev = class_find_device(®ulator_class, NULL, np, of_node_match); + + return dev ? dev_to_rdev(dev) : NULL; +} + +static int regulator_match(struct device *dev, const void *data) +{ + struct regulator_dev *r = dev_to_rdev(dev); + + return strcmp(rdev_get_name(r), data) == 0; +} + +static struct regulator_dev *regulator_lookup_by_name(const char *name) +{ + struct device *dev; + + dev = class_find_device(®ulator_class, NULL, name, regulator_match); + + return dev ? dev_to_rdev(dev) : NULL; +} + +/** + * regulator_dev_lookup - lookup a regulator device. + * @dev: device for regulator "consumer". + * @supply: Supply name or regulator ID. + * @ret: 0 on success, -ENODEV if lookup fails permanently, -EPROBE_DEFER if + * lookup could succeed in the future. + * + * If successful, returns a struct regulator_dev that corresponds to the name + * @supply and with the embedded struct device refcount incremented by one, + * or NULL on failure. The refcount must be dropped by calling put_device(). + */ static struct regulator_dev *regulator_dev_lookup(struct device *dev, const char *supply, int *ret) @@ -1340,10 +1382,9 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev, if (dev && dev->of_node) { node = of_get_regulator(dev, supply); if (node) { - list_for_each_entry(r, ®ulator_list, list) - if (r->dev.parent && - node == r->dev.of_node) - return r; + r = of_find_regulator_by_node(node); + if (r) + return r; *ret = -EPROBE_DEFER; return NULL; } else { @@ -1361,20 +1402,24 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev, if (dev) devname = dev_name(dev); - list_for_each_entry(r, ®ulator_list, list) - if (strcmp(rdev_get_name(r), supply) == 0) - return r; + r = regulator_lookup_by_name(supply); + if (r) + return r; + mutex_lock(®ulator_list_mutex); list_for_each_entry(map, ®ulator_map_list, list) { /* If the mapping has a device set up it must match */ if (map->dev_name && (!devname || strcmp(map->dev_name, devname))) continue; - if (strcmp(map->supply, supply) == 0) + if (strcmp(map->supply, supply) == 0 && + get_device(&map->regulator->dev)) { + mutex_unlock(®ulator_list_mutex); return map->regulator; + } } - + mutex_unlock(®ulator_list_mutex); return NULL; } @@ -1405,6 +1450,7 @@ static int regulator_resolve_supply(struct regulator_dev *rdev) if (!r) { if (have_full_constraints()) { r = dummy_regulator_rdev; + get_device(&r->dev); } else { dev_err(dev, "Failed to resolve %s-supply for %s\n", rdev->supply_name, rdev->desc->name); @@ -1414,12 +1460,16 @@ static int regulator_resolve_supply(struct regulator_dev *rdev) /* Recursively resolve the supply of the supply */ ret = regulator_resolve_supply(r); - if (ret < 0) + if (ret < 0) { + put_device(&r->dev); return ret; + } ret = set_supply(rdev, r); - if (ret < 0) + if (ret < 0) { + put_device(&r->dev); return ret; + } /* Cascade always-on state to supply */ if (_regulator_is_enabled(rdev)) { @@ -1456,8 +1506,6 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, else ret = -EPROBE_DEFER; - mutex_lock(®ulator_list_mutex); - rdev = regulator_dev_lookup(dev, id, &ret); if (rdev) goto found; @@ -1469,7 +1517,7 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, * succeed, so, quit with appropriate error value */ if (ret && ret != -ENODEV) - goto out; + return regulator; if (!devname) devname = "deviceless"; @@ -1483,40 +1531,46 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, devname, id); rdev = dummy_regulator_rdev; + get_device(&rdev->dev); goto found; /* Don't log an error when called from regulator_get_optional() */ } else if (!have_full_constraints() || exclusive) { dev_warn(dev, "dummy supplies not allowed\n"); } - mutex_unlock(®ulator_list_mutex); return regulator; found: if (rdev->exclusive) { regulator = ERR_PTR(-EPERM); - goto out; + put_device(&rdev->dev); + return regulator; } if (exclusive && rdev->open_count) { regulator = ERR_PTR(-EBUSY); - goto out; + put_device(&rdev->dev); + return regulator; } ret = regulator_resolve_supply(rdev); if (ret < 0) { regulator = ERR_PTR(ret); - goto out; + put_device(&rdev->dev); + return regulator; } - if (!try_module_get(rdev->owner)) - goto out; + if (!try_module_get(rdev->owner)) { + put_device(&rdev->dev); + return regulator; + } regulator = create_regulator(rdev, dev, id); if (regulator == NULL) { regulator = ERR_PTR(-ENOMEM); + put_device(&rdev->dev); module_put(rdev->owner); - goto out; + return regulator; } rdev->open_count++; @@ -1530,9 +1584,6 @@ found: rdev->use_count = 0; } -out: - mutex_unlock(®ulator_list_mutex); - return regulator; } @@ -1630,6 +1681,7 @@ static void _regulator_put(struct regulator *regulator) rdev->open_count--; rdev->exclusive = 0; + put_device(&rdev->dev); mutex_unlock(&rdev->mutex); kfree(regulator->supply_name); @@ -3807,8 +3859,6 @@ regulator_register(const struct regulator_desc *regulator_desc, } } - list_add(&rdev->list, ®ulator_list); - rdev_init_debugfs(rdev); out: mutex_unlock(®ulator_list_mutex); @@ -3862,6 +3912,19 @@ void regulator_unregister(struct regulator_dev *rdev) } EXPORT_SYMBOL_GPL(regulator_unregister); +static int _regulator_suspend_prepare(struct device *dev, void *data) +{ + struct regulator_dev *rdev = dev_to_rdev(dev); + const suspend_state_t *state = data; + int ret; + + mutex_lock(&rdev->mutex); + ret = suspend_prepare(rdev, *state); + mutex_unlock(&rdev->mutex); + + return ret; +} + /** * regulator_suspend_prepare - prepare regulators for system wide suspend * @state: system suspend state @@ -3871,30 +3934,45 @@ EXPORT_SYMBOL_GPL(regulator_unregister); */ int regulator_suspend_prepare(suspend_state_t state) { - struct regulator_dev *rdev; - int ret = 0; - /* ON is handled by regulator active state */ if (state == PM_SUSPEND_ON) return -EINVAL; - mutex_lock(®ulator_list_mutex); - list_for_each_entry(rdev, ®ulator_list, list) { + return class_for_each_device(®ulator_class, NULL, &state, + _regulator_suspend_prepare); +} +EXPORT_SYMBOL_GPL(regulator_suspend_prepare); - mutex_lock(&rdev->mutex); - ret = suspend_prepare(rdev, state); - mutex_unlock(&rdev->mutex); +static int _regulator_suspend_finish(struct device *dev, void *data) +{ + struct regulator_dev *rdev = dev_to_rdev(dev); + int ret; - if (ret < 0) { - rdev_err(rdev, "failed to prepare\n"); - goto out; + mutex_lock(&rdev->mutex); + if (rdev->use_count > 0 || rdev->constraints->always_on) { + if (!_regulator_is_enabled(rdev)) { + ret = _regulator_do_enable(rdev); + if (ret) + dev_err(dev, + "Failed to resume regulator %d\n", + ret); } + } else { + if (!have_full_constraints()) + goto unlock; + if (!_regulator_is_enabled(rdev)) + goto unlock; + + ret = _regulator_do_disable(rdev); + if (ret) + dev_err(dev, "Failed to suspend regulator %d\n", ret); } -out: - mutex_unlock(®ulator_list_mutex); - return ret; +unlock: + mutex_unlock(&rdev->mutex); + + /* Keep processing regulators in spite of any errors */ + return 0; } -EXPORT_SYMBOL_GPL(regulator_suspend_prepare); /** * regulator_suspend_finish - resume regulators from system wide suspend @@ -3904,33 +3982,8 @@ EXPORT_SYMBOL_GPL(regulator_suspend_prepare); */ int regulator_suspend_finish(void) { - struct regulator_dev *rdev; - int ret = 0, error; - - mutex_lock(®ulator_list_mutex); - list_for_each_entry(rdev, ®ulator_list, list) { - mutex_lock(&rdev->mutex); - if (rdev->use_count > 0 || rdev->constraints->always_on) { - if (!_regulator_is_enabled(rdev)) { - error = _regulator_do_enable(rdev); - if (error) - ret = error; - } - } else { - if (!have_full_constraints()) - goto unlock; - if (!_regulator_is_enabled(rdev)) - goto unlock; - - error = _regulator_do_disable(rdev); - if (error) - ret = error; - } -unlock: - mutex_unlock(&rdev->mutex); - } - mutex_unlock(®ulator_list_mutex); - return ret; + return class_for_each_device(®ulator_class, NULL, NULL, + _regulator_suspend_finish); } EXPORT_SYMBOL_GPL(regulator_suspend_finish); @@ -4050,14 +4103,35 @@ static const struct file_operations supply_map_fops = { }; #ifdef CONFIG_DEBUG_FS +struct summary_data { + struct seq_file *s; + struct regulator_dev *parent; + int level; +}; + +static void regulator_summary_show_subtree(struct seq_file *s, + struct regulator_dev *rdev, + int level); + +static int regulator_summary_show_children(struct device *dev, void *data) +{ + struct regulator_dev *rdev = dev_to_rdev(dev); + struct summary_data *summary_data = data; + + if (rdev->supply && rdev->supply->rdev == summary_data->parent) + regulator_summary_show_subtree(summary_data->s, rdev, + summary_data->level + 1); + + return 0; +} + static void regulator_summary_show_subtree(struct seq_file *s, struct regulator_dev *rdev, int level) { - struct list_head *list = s->private; - struct regulator_dev *child; struct regulation_constraints *c; struct regulator *consumer; + struct summary_data summary_data; if (!rdev) return; @@ -4107,33 +4181,32 @@ static void regulator_summary_show_subtree(struct seq_file *s, seq_puts(s, "\n"); } - list_for_each_entry(child, list, list) { - /* handle only non-root regulators supplied by current rdev */ - if (!child->supply || child->supply->rdev != rdev) - continue; + summary_data.s = s; + summary_data.level = level; + summary_data.parent = rdev; - regulator_summary_show_subtree(s, child, level + 1); - } + class_for_each_device(®ulator_class, NULL, &summary_data, + regulator_summary_show_children); } -static int regulator_summary_show(struct seq_file *s, void *data) +static int regulator_summary_show_roots(struct device *dev, void *data) { - struct list_head *list = s->private; - struct regulator_dev *rdev; - - seq_puts(s, " regulator use open bypass voltage current min max\n"); - seq_puts(s, "-------------------------------------------------------------------------------\n"); + struct regulator_dev *rdev = dev_to_rdev(dev); + struct seq_file *s = data; - mutex_lock(®ulator_list_mutex); + if (!rdev->supply) + regulator_summary_show_subtree(s, rdev, 0); - list_for_each_entry(rdev, list, list) { - if (rdev->supply) - continue; + return 0; +} - regulator_summary_show_subtree(s, rdev, 0); - } +static int regulator_summary_show(struct seq_file *s, void *data) +{ + seq_puts(s, " regulator use open bypass voltage current min max\n"); + seq_puts(s, "-------------------------------------------------------------------------------\n"); - mutex_unlock(®ulator_list_mutex); + class_for_each_device(®ulator_class, NULL, s, + regulator_summary_show_roots); return 0; } @@ -4167,7 +4240,7 @@ static int __init regulator_init(void) &supply_map_fops); debugfs_create_file("regulator_summary", 0444, debugfs_root, - ®ulator_list, ®ulator_summary_fops); + NULL, ®ulator_summary_fops); regulator_dummy_init(); -- cgit v1.2.3 From 1de7d80246a047edaa4ea7de225437571a3aec34 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 21 Sep 2015 11:33:28 +0200 Subject: regulator: pwm: implement ->enable(), ->disable() and ->is_enabled methods Implement the ->enable(), ->disable() and ->is_enabled methods and remove the PWM call in ->set_voltage_sel(). This is particularly important for critical regulators tagged as always-on, because not claiming the PWM (and its dependencies) might lead to unpredictable behavior (like a system hang because the PWM clk is only claimed when the PWM device is enabled). Signed-off-by: Boris Brezillon Signed-off-by: Mark Brown --- drivers/regulator/pwm-regulator.c | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index fc3166dfcbfa..3aca067b9901 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -69,12 +69,6 @@ static int pwm_regulator_set_voltage_sel(struct regulator_dev *rdev, drvdata->state = selector; - ret = pwm_enable(drvdata->pwm); - if (ret) { - dev_err(&rdev->dev, "Failed to enable PWM\n"); - return ret; - } - return 0; } @@ -89,6 +83,29 @@ static int pwm_regulator_list_voltage(struct regulator_dev *rdev, return drvdata->duty_cycle_table[selector].uV; } +static int pwm_regulator_enable(struct regulator_dev *dev) +{ + struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev); + + return pwm_enable(drvdata->pwm); +} + +static int pwm_regulator_disable(struct regulator_dev *dev) +{ + struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev); + + pwm_disable(drvdata->pwm); + + return 0; +} + +static int pwm_regulator_is_enabled(struct regulator_dev *dev) +{ + struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev); + + return pwm_is_enabled(drvdata->pwm); +} + /** * Continuous voltage call-backs */ @@ -144,11 +161,17 @@ static struct regulator_ops pwm_regulator_voltage_table_ops = { .get_voltage_sel = pwm_regulator_get_voltage_sel, .list_voltage = pwm_regulator_list_voltage, .map_voltage = regulator_map_voltage_iterate, + .enable = pwm_regulator_enable, + .disable = pwm_regulator_disable, + .is_enabled = pwm_regulator_is_enabled, }; static struct regulator_ops pwm_regulator_voltage_continuous_ops = { .get_voltage = pwm_regulator_get_voltage, .set_voltage = pwm_regulator_set_voltage, + .enable = pwm_regulator_enable, + .disable = pwm_regulator_disable, + .is_enabled = pwm_regulator_is_enabled, }; static struct regulator_desc pwm_regulator_desc = { -- cgit v1.2.3 From 9f01cd4a915e13dda6a61b989229015687ffd58f Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 30 Sep 2015 16:05:42 +0200 Subject: regulator: core: introduce function to lock regulators and its supplies Each regulator_dev is locked with its own mutex. This is fine as long as only one regulator_dev is locked, but makes lockdep unhappy when we have to walk up the supply chain like it can happen in regulator_get_voltage: regulator_get_voltage -> mutex_lock(®ulator->rdev->mutex) -> _regulator_get_voltage(regulator->rdev) -> regulator_get_voltage(rdev->supply) -> mutex_lock(®ulator->rdev->mutex); This causes lockdep to issue a possible deadlock warning. There are at least two ways to work around this: - We can always lock the whole supply chain using the functions introduced with this patch. - We could store the current voltage in struct regulator_rdev so that we do not have to walk up the supply chain for the _regulator_get_voltage case. Anyway, regulator_lock_supply/regulator_unlock_supply will be needed once we allow regulator_set_voltage to optimize the supply voltages. Signed-off-by: Sascha Hauer Signed-off-by: Mark Brown --- drivers/regulator/core.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'drivers/regulator') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 7a85ac9e32c5..1f9ff55b3620 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -131,6 +131,45 @@ static bool have_full_constraints(void) return has_full_constraints || of_have_populated_dt(); } +/** + * regulator_lock_supply - lock a regulator and its supplies + * @rdev: regulator source + */ +static void regulator_lock_supply(struct regulator_dev *rdev) +{ + struct regulator *supply; + int i = 0; + + while (1) { + mutex_lock_nested(&rdev->mutex, i++); + supply = rdev->supply; + + if (!rdev->supply) + return; + + rdev = supply->rdev; + } +} + +/** + * regulator_unlock_supply - unlock a regulator and its supplies + * @rdev: regulator source + */ +static void regulator_unlock_supply(struct regulator_dev *rdev) +{ + struct regulator *supply; + + while (1) { + mutex_unlock(&rdev->mutex); + supply = rdev->supply; + + if (!rdev->supply) + return; + + rdev = supply->rdev; + } +} + /** * of_get_regulator - get a regulator device node based on supply name * @dev: Device pointer for the consumer (of regulator) device -- cgit v1.2.3 From 3a40cfc36bb3d2e25c9af31e56863ea7144c5324 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 30 Sep 2015 16:05:43 +0200 Subject: regulator: core: create unlocked version of regulator_list_voltage The unlocked version will be needed when we start propagating voltage changes to the supply regulators. Signed-off-by: Sascha Hauer Signed-off-by: Mark Brown --- drivers/regulator/core.c | 62 +++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 27 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 1f9ff55b3620..f28c133693ad 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2348,6 +2348,40 @@ static int _regulator_is_enabled(struct regulator_dev *rdev) return rdev->desc->ops->is_enabled(rdev); } +static int _regulator_list_voltage(struct regulator *regulator, + unsigned selector, int lock) +{ + struct regulator_dev *rdev = regulator->rdev; + const struct regulator_ops *ops = rdev->desc->ops; + int ret; + + if (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1 && !selector) + return rdev->desc->fixed_uV; + + if (ops->list_voltage) { + if (selector >= rdev->desc->n_voltages) + return -EINVAL; + if (lock) + mutex_lock(&rdev->mutex); + ret = ops->list_voltage(rdev, selector); + if (lock) + mutex_unlock(&rdev->mutex); + } else if (rdev->supply) { + ret = _regulator_list_voltage(rdev->supply, selector, lock); + } else { + return -EINVAL; + } + + if (ret > 0) { + if (ret < rdev->constraints->min_uV) + ret = 0; + else if (ret > rdev->constraints->max_uV) + ret = 0; + } + + return ret; +} + /** * regulator_is_enabled - is the regulator output enabled * @regulator: regulator source @@ -2437,33 +2471,7 @@ EXPORT_SYMBOL_GPL(regulator_count_voltages); */ int regulator_list_voltage(struct regulator *regulator, unsigned selector) { - struct regulator_dev *rdev = regulator->rdev; - const struct regulator_ops *ops = rdev->desc->ops; - int ret; - - if (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1 && !selector) - return rdev->desc->fixed_uV; - - 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; - } - - if (ret > 0) { - if (ret < rdev->constraints->min_uV) - ret = 0; - else if (ret > rdev->constraints->max_uV) - ret = 0; - } - - return ret; + return _regulator_list_voltage(regulator, selector, 1); } EXPORT_SYMBOL_GPL(regulator_list_voltage); -- cgit v1.2.3 From 33aa380006776850872914d83fe0dbeee42fc95d Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 28 Sep 2015 14:01:07 +0100 Subject: regulator: arizona: add support for WM8998 and WM1814 Signed-off-by: Richard Fitzgerald Acked-by: Mark Brown Signed-off-by: Mark Brown --- drivers/regulator/arizona-ldo1.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/regulator') diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c index 5e947a8ddb84..e3c5982a66a0 100644 --- a/drivers/regulator/arizona-ldo1.c +++ b/drivers/regulator/arizona-ldo1.c @@ -245,6 +245,8 @@ static int arizona_ldo1_probe(struct platform_device *pdev) switch (arizona->type) { case WM5102: case WM8997: + case WM8998: + case WM1814: desc = &arizona_ldo1_hc; ldo1->init_data = arizona_ldo1_dvfs; break; -- cgit v1.2.3 From c86dc03e54ce15aac623125d92faac005f94267b Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Wed, 30 Sep 2015 15:25:49 +0800 Subject: regulator: act8865: support output voltage by VSET2[] bits For the step-down DC/DC regulators, the output voltage is selectable by setting VSEL pin that when VSEL is low, output voltage is programmed by VSET1[] bits, and when VSEL is high, output voltage is programmed by VSET2[] bits. The DT property "active-semi,vsel-high" is used to specify the VSEL pin at high on the board. Signed-off-by: Wenyou Yang Reviewed-by: Ludovic Desroches Signed-off-by: Mark Brown --- drivers/regulator/act8865-regulator.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/act8865-regulator.c b/drivers/regulator/act8865-regulator.c index 896db168e4bd..f8d4cd3d1397 100644 --- a/drivers/regulator/act8865-regulator.c +++ b/drivers/regulator/act8865-regulator.c @@ -261,6 +261,16 @@ static const struct regulator_desc act8865_regulators[] = { ACT88xx_REG("LDO_REG4", ACT8865, LDO4, VSET, "inl67"), }; +static const struct regulator_desc act8865_alt_regulators[] = { + ACT88xx_REG("DCDC_REG1", ACT8865, DCDC1, VSET2, "vp1"), + ACT88xx_REG("DCDC_REG2", ACT8865, DCDC2, VSET2, "vp2"), + ACT88xx_REG("DCDC_REG3", ACT8865, DCDC3, VSET2, "vp3"), + ACT88xx_REG("LDO_REG1", ACT8865, LDO1, VSET, "inl45"), + ACT88xx_REG("LDO_REG2", ACT8865, LDO2, VSET, "inl45"), + ACT88xx_REG("LDO_REG3", ACT8865, LDO3, VSET, "inl67"), + ACT88xx_REG("LDO_REG4", ACT8865, LDO4, VSET, "inl67"), +}; + #ifdef CONFIG_OF static const struct of_device_id act8865_dt_ids[] = { { .compatible = "active-semi,act8600", .data = (void *)ACT8600 }, @@ -413,6 +423,7 @@ static int act8865_pmic_probe(struct i2c_client *client, struct act8865 *act8865; unsigned long type; int off_reg, off_mask; + int voltage_select = 0; pdata = dev_get_platdata(dev); @@ -424,6 +435,10 @@ static int act8865_pmic_probe(struct i2c_client *client, return -ENODEV; type = (unsigned long) id->data; + + voltage_select = !!of_get_property(dev->of_node, + "active-semi,vsel-high", + NULL); } else { type = i2c_id->driver_data; } @@ -442,8 +457,13 @@ static int act8865_pmic_probe(struct i2c_client *client, off_mask = ACT8846_OFF_SYSMASK; break; case ACT8865: - regulators = act8865_regulators; - num_regulators = ARRAY_SIZE(act8865_regulators); + if (voltage_select) { + regulators = act8865_alt_regulators; + num_regulators = ARRAY_SIZE(act8865_alt_regulators); + } else { + regulators = act8865_regulators; + num_regulators = ARRAY_SIZE(act8865_regulators); + } off_reg = ACT8865_SYS_CTRL; off_mask = ACT8865_MSTROFF; break; -- cgit v1.2.3 From 7e50711993552800644a4667daa0f569a7665eca Mon Sep 17 00:00:00 2001 From: Grigoryev Denis Date: Fri, 2 Oct 2015 16:14:41 +0000 Subject: mfd: tps6105x: Use i2c regmap to access registers This patch modifies tps6105x and associated function driver to use regmap instead of operating directly on i2c. Signed-off-by: Denis Grigoryev Signed-off-by: Lee Jones --- drivers/mfd/tps6105x.c | 78 ++++++---------------------------- drivers/regulator/tps6105x-regulator.c | 16 +++---- include/linux/mfd/tps6105x.h | 10 ++--- 3 files changed, 24 insertions(+), 80 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/mfd/tps6105x.c b/drivers/mfd/tps6105x.c index 5de95c265c1a..4a174cdb50b6 100644 --- a/drivers/mfd/tps6105x.c +++ b/drivers/mfd/tps6105x.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include @@ -25,73 +25,18 @@ #include #include -int tps6105x_set(struct tps6105x *tps6105x, u8 reg, u8 value) -{ - int ret; - - ret = mutex_lock_interruptible(&tps6105x->lock); - if (ret) - return ret; - ret = i2c_smbus_write_byte_data(tps6105x->client, reg, value); - mutex_unlock(&tps6105x->lock); - if (ret < 0) - return ret; - - return 0; -} -EXPORT_SYMBOL(tps6105x_set); - -int tps6105x_get(struct tps6105x *tps6105x, u8 reg, u8 *buf) -{ - int ret; - - ret = mutex_lock_interruptible(&tps6105x->lock); - if (ret) - return ret; - ret = i2c_smbus_read_byte_data(tps6105x->client, reg); - mutex_unlock(&tps6105x->lock); - if (ret < 0) - return ret; - - *buf = ret; - return 0; -} -EXPORT_SYMBOL(tps6105x_get); - -/* - * Masks off the bits in the mask and sets the bits in the bitvalues - * parameter in one atomic operation - */ -int tps6105x_mask_and_set(struct tps6105x *tps6105x, u8 reg, - u8 bitmask, u8 bitvalues) -{ - int ret; - u8 regval; - - ret = mutex_lock_interruptible(&tps6105x->lock); - if (ret) - return ret; - ret = i2c_smbus_read_byte_data(tps6105x->client, reg); - if (ret < 0) - goto fail; - regval = ret; - regval = (~bitmask & regval) | (bitmask & bitvalues); - ret = i2c_smbus_write_byte_data(tps6105x->client, reg, regval); -fail: - mutex_unlock(&tps6105x->lock); - if (ret < 0) - return ret; - - return 0; -} -EXPORT_SYMBOL(tps6105x_mask_and_set); +static struct regmap_config tps6105x_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = TPS6105X_REG_3, +}; static int tps6105x_startup(struct tps6105x *tps6105x) { int ret; - u8 regval; + unsigned int regval; - ret = tps6105x_get(tps6105x, TPS6105X_REG_0, ®val); + ret = regmap_read(tps6105x->regmap, TPS6105X_REG_0, ®val); if (ret) return ret; switch (regval >> TPS6105X_REG0_MODE_SHIFT) { @@ -145,11 +90,14 @@ static int tps6105x_probe(struct i2c_client *client, if (!tps6105x) return -ENOMEM; + tps6105x->regmap = devm_regmap_init_i2c(client, &tps6105x_regmap_config); + if (IS_ERR(tps6105x->regmap)) + return PTR_ERR(tps6105x->regmap); + i2c_set_clientdata(client, tps6105x); tps6105x->client = client; pdata = dev_get_platdata(&client->dev); tps6105x->pdata = pdata; - mutex_init(&tps6105x->lock); ret = tps6105x_startup(tps6105x); if (ret) { @@ -198,7 +146,7 @@ static int tps6105x_remove(struct i2c_client *client) mfd_remove_devices(&client->dev); /* Put chip in shutdown mode */ - tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0, + regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0, TPS6105X_REG0_MODE_MASK, TPS6105X_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT); diff --git a/drivers/regulator/tps6105x-regulator.c b/drivers/regulator/tps6105x-regulator.c index 3510b3e7330a..ddc4f10e268a 100644 --- a/drivers/regulator/tps6105x-regulator.c +++ b/drivers/regulator/tps6105x-regulator.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -33,7 +33,7 @@ static int tps6105x_regulator_enable(struct regulator_dev *rdev) int ret; /* Activate voltage mode */ - ret = tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0, + ret = regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0, TPS6105X_REG0_MODE_MASK, TPS6105X_REG0_MODE_VOLTAGE << TPS6105X_REG0_MODE_SHIFT); if (ret) @@ -48,7 +48,7 @@ static int tps6105x_regulator_disable(struct regulator_dev *rdev) int ret; /* Set into shutdown mode */ - ret = tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0, + ret = regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0, TPS6105X_REG0_MODE_MASK, TPS6105X_REG0_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT); if (ret) @@ -60,10 +60,10 @@ static int tps6105x_regulator_disable(struct regulator_dev *rdev) static int tps6105x_regulator_is_enabled(struct regulator_dev *rdev) { struct tps6105x *tps6105x = rdev_get_drvdata(rdev); - u8 regval; + unsigned int regval; int ret; - ret = tps6105x_get(tps6105x, TPS6105X_REG_0, ®val); + ret = regmap_read(tps6105x->regmap, TPS6105X_REG_0, ®val); if (ret) return ret; regval &= TPS6105X_REG0_MODE_MASK; @@ -78,10 +78,10 @@ static int tps6105x_regulator_is_enabled(struct regulator_dev *rdev) static int tps6105x_regulator_get_voltage_sel(struct regulator_dev *rdev) { struct tps6105x *tps6105x = rdev_get_drvdata(rdev); - u8 regval; + unsigned int regval; int ret; - ret = tps6105x_get(tps6105x, TPS6105X_REG_0, ®val); + ret = regmap_read(tps6105x->regmap, TPS6105X_REG_0, ®val); if (ret) return ret; @@ -96,7 +96,7 @@ static int tps6105x_regulator_set_voltage_sel(struct regulator_dev *rdev, struct tps6105x *tps6105x = rdev_get_drvdata(rdev); int ret; - ret = tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0, + ret = regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0, TPS6105X_REG0_VOLTAGE_MASK, selector << TPS6105X_REG0_VOLTAGE_SHIFT); if (ret) diff --git a/include/linux/mfd/tps6105x.h b/include/linux/mfd/tps6105x.h index 386743dd931c..8bc51180800a 100644 --- a/include/linux/mfd/tps6105x.h +++ b/include/linux/mfd/tps6105x.h @@ -10,6 +10,7 @@ #define MFD_TPS6105X_H #include +#include #include /* @@ -82,20 +83,15 @@ struct tps6105x_platform_data { /** * struct tps6105x - state holder for the TPS6105x drivers - * @mutex: mutex to serialize I2C accesses * @i2c_client: corresponding I2C client * @regulator: regulator device if used in voltage mode + * @regmap: used for i2c communcation on accessing registers */ struct tps6105x { struct tps6105x_platform_data *pdata; - struct mutex lock; struct i2c_client *client; struct regulator_dev *regulator; + struct regmap *regmap; }; -extern int tps6105x_set(struct tps6105x *tps6105x, u8 reg, u8 value); -extern int tps6105x_get(struct tps6105x *tps6105x, u8 reg, u8 *buf); -extern int tps6105x_mask_and_set(struct tps6105x *tps6105x, u8 reg, - u8 bitmask, u8 bitvalues); - #endif -- cgit v1.2.3 From 7118f19c4c7cc95ad1513729b83f9db789970152 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 30 Sep 2015 14:39:46 +0800 Subject: regulator: axp20x: set supply names for AXP22X DC1SW/DC5LDO internally The DC1SW and DC5LDO regulators in the AXP22X are internally chained to DCDC1 and DCDC5, hence the names. The original bindings used the parent regulator names for the supply regulator property. Since they are internally connected, the relationship should not be represented in the device tree, but handled internally by the driver. This patch has the driver remember the regulator names for the parent DCDC1/DCDC5, and use them as supply names for DC1SW/DC5LDO. Signed-off-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- drivers/regulator/axp20x-regulator.c | 54 +++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 4 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c index 01bf3476a791..56a0805e6494 100644 --- a/drivers/regulator/axp20x-regulator.c +++ b/drivers/regulator/axp20x-regulator.c @@ -196,10 +196,10 @@ static const struct regulator_desc axp22x_regulators[] = { AXP_DESC(AXP22X, DCDC5, "dcdc5", "vin5", 1000, 2550, 50, AXP22X_DCDC5_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(4)), /* secondary switchable output of DCDC1 */ - AXP_DESC_SW(AXP22X, DC1SW, "dc1sw", "dcdc1", 1600, 3400, 100, + AXP_DESC_SW(AXP22X, DC1SW, "dc1sw", NULL, 1600, 3400, 100, AXP22X_DCDC1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(7)), /* LDO regulator internally chained to DCDC5 */ - AXP_DESC(AXP22X, DC5LDO, "dc5ldo", "dcdc5", 700, 1400, 100, + AXP_DESC(AXP22X, DC5LDO, "dc5ldo", NULL, 700, 1400, 100, AXP22X_DC5LDO_V_OUT, 0x7, AXP22X_PWR_OUT_CTRL1, BIT(0)), AXP_DESC(AXP22X, ALDO1, "aldo1", "aldoin", 700, 3300, 100, AXP22X_ALDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(6)), @@ -350,6 +350,8 @@ static int axp20x_regulator_probe(struct platform_device *pdev) }; int ret, i, nregulators; u32 workmode; + const char *axp22x_dc1_name = axp22x_regulators[AXP22X_DCDC1].name; + const char *axp22x_dc5_name = axp22x_regulators[AXP22X_DCDC5].name; switch (axp20x->variant) { case AXP202_ID: @@ -371,8 +373,37 @@ static int axp20x_regulator_probe(struct platform_device *pdev) axp20x_regulator_parse_dt(pdev); for (i = 0; i < nregulators; i++) { - rdev = devm_regulator_register(&pdev->dev, ®ulators[i], - &config); + const struct regulator_desc *desc = ®ulators[i]; + struct regulator_desc *new_desc; + + /* + * Regulators DC1SW and DC5LDO are connected internally, + * so we have to handle their supply names separately. + * + * We always register the regulators in proper sequence, + * so the supply names are correctly read. See the last + * part of this loop to see where we save the DT defined + * name. + */ + if (regulators == axp22x_regulators) { + if (i == AXP22X_DC1SW) { + new_desc = devm_kzalloc(&pdev->dev, + sizeof(*desc), + GFP_KERNEL); + *new_desc = regulators[i]; + new_desc->supply_name = axp22x_dc1_name; + desc = new_desc; + } else if (i == AXP22X_DC5LDO) { + new_desc = devm_kzalloc(&pdev->dev, + sizeof(*desc), + GFP_KERNEL); + *new_desc = regulators[i]; + new_desc->supply_name = axp22x_dc5_name; + desc = new_desc; + } + } + + rdev = devm_regulator_register(&pdev->dev, desc, &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "Failed to register %s\n", regulators[i].name); @@ -388,6 +419,21 @@ static int axp20x_regulator_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Failed to set workmode on %s\n", rdev->desc->name); } + + /* + * Save AXP22X DCDC1 / DCDC5 regulator names for later. + */ + if (regulators == axp22x_regulators) { + /* Can we use rdev->constraints->name instead? */ + if (i == AXP22X_DCDC1) + of_property_read_string(rdev->dev.of_node, + "regulator-name", + &axp22x_dc1_name); + else if (i == AXP22X_DCDC5) + of_property_read_string(rdev->dev.of_node, + "regulator-name", + &axp22x_dc5_name); + } } return 0; -- cgit v1.2.3 From 8b7081442ee29b0de0bede6fcf7752b97159b581 Mon Sep 17 00:00:00 2001 From: Steve Twiss Date: Fri, 16 Oct 2015 09:55:54 +0100 Subject: regulator: da9053: Update regulator for DA9053 BC silicon support Provide an additional case entry for DA9053_BC in the find_regulator_info() function in order to support BC type silicon for the DA9053 device. Signed-off-by: Steve Twiss Signed-off-by: Mark Brown --- drivers/regulator/da9052-regulator.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/regulator') diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c index e628d4c2f2ae..12a25b40e473 100644 --- a/drivers/regulator/da9052-regulator.c +++ b/drivers/regulator/da9052-regulator.c @@ -381,6 +381,7 @@ static inline struct da9052_regulator_info *find_regulator_info(u8 chip_id, case DA9053_AA: case DA9053_BA: case DA9053_BB: + case DA9053_BC: for (i = 0; i < ARRAY_SIZE(da9053_regulator_info); i++) { info = &da9053_regulator_info[i]; if (info->reg_desc.id == id) -- cgit v1.2.3 From ce938001c08c6580a8da38dc226fa605512afab6 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 15 Oct 2015 10:37:12 +0100 Subject: regulator: arizona-ldo1: Fix handling of GPIO 0 The LDO1 driver is using the arizona_of_get_named_gpio helper function which will return 0 if an error was encountered whilst parsing the GPIO, as under the pdata scheme 0 was not being treated as a valid GPIO. However, since the regulator framework was expanded to allow the use of GPIO 0 this causes us to attempt to register GPIO 0 when we encountered an error parsing the device tree. This patch uses of_get_named_gpio directly and sets the ena_gpio_initialized flag based on the return value. Fixes: 1de3821ace82 ("regulator: Set ena_gpio_initialized in regulator drivers") Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- drivers/regulator/arizona-ldo1.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c index e3c5982a66a0..f7c88ff90c43 100644 --- a/drivers/regulator/arizona-ldo1.c +++ b/drivers/regulator/arizona-ldo1.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -189,13 +190,22 @@ static int arizona_ldo1_of_get_pdata(struct arizona *arizona, { struct arizona_pdata *pdata = &arizona->pdata; struct arizona_ldo1 *ldo1 = config->driver_data; + struct device_node *np = arizona->dev->of_node; struct device_node *init_node, *dcvdd_node; struct regulator_init_data *init_data; - pdata->ldoena = arizona_of_get_named_gpio(arizona, "wlf,ldoena", true); + pdata->ldoena = of_get_named_gpio(np, "wlf,ldoena", 0); + if (pdata->ldoena < 0) { + dev_warn(arizona->dev, + "LDOENA GPIO property missing/malformed: %d\n", + pdata->ldoena); + pdata->ldoena = 0; + } else { + config->ena_gpio_initialized = true; + } - init_node = of_get_child_by_name(arizona->dev->of_node, "ldo1"); - dcvdd_node = of_parse_phandle(arizona->dev->of_node, "DCVDD-supply", 0); + init_node = of_get_child_by_name(np, "ldo1"); + dcvdd_node = of_parse_phandle(np, "DCVDD-supply", 0); if (init_node) { config->of_node = init_node; @@ -274,8 +284,6 @@ static int arizona_ldo1_probe(struct platform_device *pdev) ret = arizona_ldo1_of_get_pdata(arizona, &config, desc); if (ret < 0) return ret; - - config.ena_gpio_initialized = true; } } -- cgit v1.2.3 From a9f226bcd9bb1941e581806e83d2c03d4043c367 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 13 Oct 2015 12:45:25 +0200 Subject: regulator: core: create unlocked version of regulator_set_voltage The unlocked version will be needed when we start propagating voltage changes to the supply regulators. Signed-off-by: Sascha Hauer Signed-off-by: Mark Brown --- drivers/regulator/core.c | 57 +++++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 23 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index f28c133693ad..5d161e11d5e6 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2761,33 +2761,14 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, return ret; } -/** - * regulator_set_voltage - set regulator output voltage - * @regulator: regulator source - * @min_uV: Minimum required voltage in uV - * @max_uV: Maximum acceptable voltage in uV - * - * Sets a voltage regulator to the desired output voltage. This can be set - * during any regulator state. IOW, regulator can be disabled or enabled. - * - * If the regulator is enabled then the voltage will change to the new value - * immediately otherwise if the regulator is disabled the regulator will - * output at the new voltage when enabled. - * - * NOTE: If the regulator is shared between several devices then the lowest - * request voltage that meets the system constraints will be used. - * Regulator system constraints must be set for this regulator before - * calling this function otherwise this call will fail. - */ -int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) +static int regulator_set_voltage_unlocked(struct regulator *regulator, + int min_uV, int max_uV) { struct regulator_dev *rdev = regulator->rdev; int ret = 0; int old_min_uV, old_max_uV; int current_uV; - mutex_lock(&rdev->mutex); - /* If we're setting the same range as last time the change * should be a noop (some cpufreq implementations use the same * voltage for multiple frequencies, for example). @@ -2835,12 +2816,42 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) goto out2; out: - mutex_unlock(&rdev->mutex); return ret; out2: regulator->min_uV = old_min_uV; regulator->max_uV = old_max_uV; - mutex_unlock(&rdev->mutex); + + return ret; +} + +/** + * regulator_set_voltage - set regulator output voltage + * @regulator: regulator source + * @min_uV: Minimum required voltage in uV + * @max_uV: Maximum acceptable voltage in uV + * + * Sets a voltage regulator to the desired output voltage. This can be set + * during any regulator state. IOW, regulator can be disabled or enabled. + * + * If the regulator is enabled then the voltage will change to the new value + * immediately otherwise if the regulator is disabled the regulator will + * output at the new voltage when enabled. + * + * NOTE: If the regulator is shared between several devices then the lowest + * request voltage that meets the system constraints will be used. + * Regulator system constraints must be set for this regulator before + * calling this function otherwise this call will fail. + */ +int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) +{ + int ret = 0; + + mutex_lock(®ulator->rdev->mutex); + + ret = regulator_set_voltage_unlocked(regulator, min_uV, max_uV); + + mutex_unlock(®ulator->rdev->mutex); + return ret; } EXPORT_SYMBOL_GPL(regulator_set_voltage); -- cgit v1.2.3 From 0d19208e70b3a65144c7a0b6368f849c57818242 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 13 Oct 2015 12:45:30 +0200 Subject: regulator: i.MX anatop: Allow supply regulator The anatop regulators are SoC internal LDO regulators usually supplied by an external PMIC. This patch adds support for specifying the supply from the device tree using the vin-supply property. Signed-off-by: Sascha Hauer Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/regulator/anatop-regulator.txt | 1 + drivers/regulator/anatop-regulator.c | 3 +++ 2 files changed, 4 insertions(+) (limited to 'drivers/regulator') diff --git a/Documentation/devicetree/bindings/regulator/anatop-regulator.txt b/Documentation/devicetree/bindings/regulator/anatop-regulator.txt index 758eae24082a..37c4ea076f88 100644 --- a/Documentation/devicetree/bindings/regulator/anatop-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/anatop-regulator.txt @@ -13,6 +13,7 @@ Optional properties: - anatop-delay-reg-offset: Anatop MFD step time register offset - anatop-delay-bit-shift: Bit shift for the step time register - anatop-delay-bit-width: Number of bits used in the step time register +- vin-supply: The supply for this regulator Any property defined as part of the core regulator binding, defined in regulator.txt, can also be used. diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c index 738adfa5332b..7d99f2c8cef3 100644 --- a/drivers/regulator/anatop-regulator.c +++ b/drivers/regulator/anatop-regulator.c @@ -30,6 +30,7 @@ #include #include #include +#include #define LDO_RAMP_UP_UNIT_IN_CYCLES 64 /* 64 cycles per step */ #define LDO_RAMP_UP_FREQ_IN_MHZ 24 /* cycle based on 24M OSC */ @@ -199,6 +200,7 @@ static int anatop_regulator_probe(struct platform_device *pdev) rdesc->owner = THIS_MODULE; initdata = of_get_regulator_init_data(dev, np, rdesc); + initdata->supply_regulator = "vin"; sreg->initdata = initdata; anatop_np = of_get_parent(np); @@ -262,6 +264,7 @@ static int anatop_regulator_probe(struct platform_device *pdev) rdesc->vsel_reg = sreg->control_reg; rdesc->vsel_mask = ((1 << sreg->vol_bit_width) - 1) << sreg->vol_bit_shift; + rdesc->min_dropout_uV = 125000; config.dev = &pdev->dev; config.init_data = initdata; -- cgit v1.2.3 From a204f41e2d670c07c4dbd382d5bd8f6db8347ac2 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 20 Oct 2015 14:37:27 +0200 Subject: regulator: core: Factor out regulator_map_voltage _regulator_call_set_voltage has code to translate a minimum/maximum voltage pair into a selector. This code is useful for others aswell, so create a regulator_map_voltage function. Signed-off-by: Sascha Hauer Signed-off-by: Mark Brown --- drivers/regulator/core.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 5d161e11d5e6..f15b04548715 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2606,6 +2606,23 @@ int regulator_is_supported_voltage(struct regulator *regulator, } EXPORT_SYMBOL_GPL(regulator_is_supported_voltage); +static int regulator_map_voltage(struct regulator_dev *rdev, int min_uV, + int max_uV) +{ + const struct regulator_desc *desc = rdev->desc; + + if (desc->ops->map_voltage) + return desc->ops->map_voltage(rdev, min_uV, max_uV); + + if (desc->ops->list_voltage == regulator_list_voltage_linear) + return regulator_map_voltage_linear(rdev, min_uV, max_uV); + + if (desc->ops->list_voltage == regulator_list_voltage_linear_range) + return regulator_map_voltage_linear_range(rdev, min_uV, max_uV); + + return regulator_map_voltage_iterate(rdev, min_uV, max_uV); +} + static int _regulator_call_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, unsigned *selector) @@ -2694,23 +2711,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, } } else if (rdev->desc->ops->set_voltage_sel) { - if (rdev->desc->ops->map_voltage) { - ret = rdev->desc->ops->map_voltage(rdev, min_uV, - max_uV); - } else { - if (rdev->desc->ops->list_voltage == - regulator_list_voltage_linear) - ret = regulator_map_voltage_linear(rdev, - min_uV, max_uV); - else if (rdev->desc->ops->list_voltage == - regulator_list_voltage_linear_range) - ret = regulator_map_voltage_linear_range(rdev, - min_uV, max_uV); - else - ret = regulator_map_voltage_iterate(rdev, - min_uV, max_uV); - } - + ret = regulator_map_voltage(rdev, min_uV, max_uV); if (ret >= 0) { best_val = rdev->desc->ops->list_voltage(rdev, ret); if (min_uV <= best_val && max_uV >= best_val) { -- cgit v1.2.3 From fc42112c0eaa6fc7c7fe61f8c6fb91b204b4d31d Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 20 Oct 2015 14:37:28 +0200 Subject: regulator: core: Propagate voltage changes to supply regulators Until now changing the voltage of a regulator only ever effected the regulator itself, but never its supplies. It's a common pattern though to put LDO regulators behind switching regulators. The switching regulators efficiently drop the input voltage but have a high ripple on their output. The output is then cleaned up by the LDOs. For higher energy efficiency the voltage drop at the LDOs should be minimized. For this scenario we need to propagate the voltage change to the supply regulators. Another scenario where voltage propagation is desired is a regulator which only consists of a switch and thus cannot regulate voltages itself. In this case we can pass setting voltages to the supply. This patch adds support for voltage propagation. We do voltage propagation when the current regulator has a minimum dropout voltage specified or if the current regulator lacks a get_voltage operation (indicating it's a switch and not a regulator). Changing the supply voltage must be done carefully. When we are increasing the current regulators output we must first increase the supply voltage and then the regulator itself. When we are decreasing the current regulators voltage we must decrease the supply voltage after changing the current regulators voltage. Signed-off-by: Sascha Hauer Signed-off-by: Mark Brown --- drivers/regulator/core.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index f15b04548715..771c6235cced 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2769,6 +2769,8 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator, int ret = 0; int old_min_uV, old_max_uV; int current_uV; + int best_supply_uV = 0; + int supply_change_uV = 0; /* If we're setting the same range as last time the change * should be a noop (some cpufreq implementations use the same @@ -2812,10 +2814,58 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator, if (ret < 0) goto out2; + if (rdev->supply && (rdev->desc->min_dropout_uV || + !rdev->desc->ops->get_voltage)) { + int current_supply_uV; + int selector; + + selector = regulator_map_voltage(rdev, min_uV, max_uV); + if (selector < 0) { + ret = selector; + goto out2; + } + + best_supply_uV = _regulator_list_voltage(regulator, selector, 0); + if (best_supply_uV < 0) { + ret = best_supply_uV; + goto out2; + } + + best_supply_uV += rdev->desc->min_dropout_uV; + + current_supply_uV = _regulator_get_voltage(rdev->supply->rdev); + if (current_supply_uV < 0) { + ret = current_supply_uV; + goto out2; + } + + supply_change_uV = best_supply_uV - current_supply_uV; + } + + if (supply_change_uV > 0) { + ret = regulator_set_voltage_unlocked(rdev->supply, + best_supply_uV, INT_MAX); + if (ret) { + dev_err(&rdev->dev, "Failed to increase supply voltage: %d\n", + ret); + goto out2; + } + } + ret = _regulator_do_set_voltage(rdev, min_uV, max_uV); if (ret < 0) goto out2; + if (supply_change_uV < 0) { + ret = regulator_set_voltage_unlocked(rdev->supply, + best_supply_uV, INT_MAX); + if (ret) + dev_warn(&rdev->dev, "Failed to decrease supply voltage: %d\n", + ret); + /* No need to fail here */ + ret = 0; + } + out: return ret; out2: @@ -2847,11 +2897,11 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) { int ret = 0; - mutex_lock(®ulator->rdev->mutex); + regulator_lock_supply(regulator->rdev); ret = regulator_set_voltage_unlocked(regulator, min_uV, max_uV); - mutex_unlock(®ulator->rdev->mutex); + regulator_unlock_supply(regulator->rdev); return ret; } -- cgit v1.2.3 From a3e123c1c4dc97b52bfcf57213eefbee9443a9bd Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 12 Oct 2015 17:49:52 -0700 Subject: regulator: qcom-smd: Correct set_load() unit The set_load() op deals with uA while the SMD packets used mA, so convert as we're building the packet. Signed-off-by: Bjorn Andersson Signed-off-by: Mark Brown --- drivers/regulator/qcom_smd-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c index b72c693e29ff..6fa0c7d13290 100644 --- a/drivers/regulator/qcom_smd-regulator.c +++ b/drivers/regulator/qcom_smd-regulator.c @@ -131,7 +131,7 @@ static int rpm_reg_set_load(struct regulator_dev *rdev, int load_uA) req.key = cpu_to_le32(RPM_KEY_MA); req.nbytes = cpu_to_le32(sizeof(u32)); - req.value = cpu_to_le32(load_uA); + req.value = cpu_to_le32(load_uA / 1000); return rpm_reg_write_active(vreg, &req, sizeof(req)); } -- cgit v1.2.3 From 4049dc1a43d1530eb462ec42201335e7b0439a80 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Mon, 12 Oct 2015 17:27:08 +0100 Subject: regulator: stw481x: compile on COMPILE_TEST The driver depends on MFD_STW481X but there isn't a build dependency so it's a good idea to allow the driver to always be built when the COMPILE_TEST option is enabled. That way, the driver can be built with a config generated by make allyesconfig and check if a patch would break the build. Signed-off-by: Luis de Bethencourt Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 64bccff557be..8df0b0e62976 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -627,7 +627,7 @@ config REGULATOR_TI_ABB config REGULATOR_STW481X_VMMC bool "ST Microelectronics STW481X VMMC regulator" - depends on MFD_STW481X + depends on MFD_STW481X || COMPILE_TEST default y if MFD_STW481X help This driver supports the internal VMMC regulator in the STw481x -- cgit v1.2.3 From d9b96d35d2521342fdbcbc7468a0f7dcfaba4147 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 3 Nov 2015 05:58:14 +0000 Subject: regulator: Use regulator_lock_supply() for get_voltage() too Since we need to read voltages of parents as part of setting supply voltages we need to be able to do get_voltage() internally without taking locks so reorganize the locking to take locks on the full tree on entry rather than as we recurse when called externally. Reported-by: John Stultz Tested-by: John Stultz Signed-off-by: Mark Brown --- drivers/regulator/core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 771c6235cced..b4970eb85357 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -3055,7 +3055,7 @@ static int _regulator_get_voltage(struct regulator_dev *rdev) } 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); + ret = _regulator_get_voltage(rdev->supply->rdev); } else { return -EINVAL; } @@ -3078,11 +3078,11 @@ int regulator_get_voltage(struct regulator *regulator) { int ret; - mutex_lock(®ulator->rdev->mutex); + regulator_lock_supply(regulator->rdev); ret = _regulator_get_voltage(regulator->rdev); - mutex_unlock(®ulator->rdev->mutex); + regulator_unlock_supply(regulator->rdev); return ret; } -- cgit v1.2.3