From 4b75291621830acad2c66a1d21d7840a7ca169d3 Mon Sep 17 00:00:00 2001 From: Harald Geyer Date: Tue, 13 Feb 2018 14:43:08 +0000 Subject: [PATCH 1/9] regulator: dt: regulator-name is required property These two drivers fail to probe if no name is provided. For details see: https://www.spinics.net/lists/kernel/msg2457515.html Signed-off-by: Harald Geyer Acked-by: Rob Herring Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/regulator/fixed-regulator.txt | 1 + Documentation/devicetree/bindings/regulator/gpio-regulator.txt | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/regulator/fixed-regulator.txt b/Documentation/devicetree/bindings/regulator/fixed-regulator.txt index 4fae41d54798..0c2a6c8a1536 100644 --- a/Documentation/devicetree/bindings/regulator/fixed-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/fixed-regulator.txt @@ -2,6 +2,7 @@ Fixed Voltage regulators Required properties: - compatible: Must be "regulator-fixed"; +- regulator-name: Defined in regulator.txt as optional, but required here. Optional properties: - gpio: gpio to use for enable control diff --git a/Documentation/devicetree/bindings/regulator/gpio-regulator.txt b/Documentation/devicetree/bindings/regulator/gpio-regulator.txt index dd1ed789728e..1f496159e2bb 100644 --- a/Documentation/devicetree/bindings/regulator/gpio-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/gpio-regulator.txt @@ -2,6 +2,8 @@ GPIO controlled regulators Required properties: - compatible : Must be "regulator-gpio". +- regulator-name : Defined in regulator.txt as optional, but required + here. - states : Selection of available voltages and GPIO configs. if there are no states, then use a fixed regulator From e45e290a882e2c0dc8ebb7dd21c66a8209d8e3a5 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 12 Feb 2018 14:16:57 +0100 Subject: [PATCH 2/9] regulator: core: Support passing an initialized GPIO enable descriptor We are currently passing a GPIO number from the global GPIO numberspace into the regulator core for handling enable GPIOs. This is not good since it ties into the global GPIO numberspace and uses gpio_to_desc() to overcome this. Start supporting passing an already initialized GPIO descriptor to the core instead: leaf drivers pick their descriptors, associated directly with the device node (or from ACPI or from a board descriptor table) and use that directly without any roundtrip over the global GPIO numberspace. This looks messy since it adds a bunch of extra code in the core, but at the end of the patch series we will delete the handling of the GPIO number and only deal with descriptors so things end up neat. Signed-off-by: Linus Walleij Signed-off-by: Mark Brown --- drivers/regulator/core.c | 25 ++++++++++++++++--------- include/linux/regulator/driver.h | 3 +++ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index dd4708c58480..4549b93b0ff9 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1937,7 +1937,10 @@ static int regulator_ena_gpio_request(struct regulator_dev *rdev, struct gpio_desc *gpiod; int ret; - gpiod = gpio_to_desc(config->ena_gpio); + if (config->ena_gpiod) + gpiod = config->ena_gpiod; + else + gpiod = gpio_to_desc(config->ena_gpio); list_for_each_entry(pin, ®ulator_ena_gpio_list, list) { if (pin->gpiod == gpiod) { @@ -1947,15 +1950,18 @@ static int regulator_ena_gpio_request(struct regulator_dev *rdev, } } - ret = gpio_request_one(config->ena_gpio, - GPIOF_DIR_OUT | config->ena_gpio_flags, - rdev_get_name(rdev)); - if (ret) - return ret; + if (!config->ena_gpiod) { + ret = gpio_request_one(config->ena_gpio, + GPIOF_DIR_OUT | config->ena_gpio_flags, + rdev_get_name(rdev)); + if (ret) + return ret; + } pin = kzalloc(sizeof(struct regulator_enable_gpio), GFP_KERNEL); if (pin == NULL) { - gpio_free(config->ena_gpio); + if (!config->ena_gpiod) + gpio_free(config->ena_gpio); return -ENOMEM; } @@ -4154,8 +4160,9 @@ regulator_register(const struct regulator_desc *regulator_desc, goto clean; } - if ((config->ena_gpio || config->ena_gpio_initialized) && - gpio_is_valid(config->ena_gpio)) { + if (config->ena_gpiod || + ((config->ena_gpio || config->ena_gpio_initialized) && + gpio_is_valid(config->ena_gpio))) { mutex_lock(®ulator_list_mutex); ret = regulator_ena_gpio_request(rdev, config); mutex_unlock(®ulator_list_mutex); diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 4c00486b7a78..4fc96cb8e5d7 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -19,6 +19,7 @@ #include #include +struct gpio_desc; struct regmap; struct regulator_dev; struct regulator_config; @@ -387,6 +388,7 @@ struct regulator_desc { * initialized, meaning that >= 0 is a valid gpio * identifier and < 0 is a non existent gpio. * @ena_gpio: GPIO controlling regulator enable. + * @ena_gpiod: GPIO descriptor controlling regulator enable. * @ena_gpio_invert: Sense for GPIO enable control. * @ena_gpio_flags: Flags to use when calling gpio_request_one() */ @@ -399,6 +401,7 @@ struct regulator_config { bool ena_gpio_initialized; int ena_gpio; + struct gpio_desc *ena_gpiod; unsigned int ena_gpio_invert:1; unsigned int ena_gpio_flags; }; From 8d05560d1d011e5a842556efdbd70cc8a21499bb Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 12 Feb 2018 14:17:00 +0100 Subject: [PATCH 3/9] regulator: da9055: Pass descriptor instead of GPIO number When setting up a fixed regulator on the DA9055, pass a descriptor instead of a global GPIO number. This facility is not used in the kernel so we can easily just say that this should be a descriptor if/when put to use. Signed-off-by: Linus Walleij Acked-by: Lee Jones Signed-off-by: Mark Brown --- drivers/regulator/da9055-regulator.c | 4 ++-- include/linux/mfd/da9055/pdata.h | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/regulator/da9055-regulator.c b/drivers/regulator/da9055-regulator.c index d029c941a1e1..f40c3b8644ae 100644 --- a/drivers/regulator/da9055-regulator.c +++ b/drivers/regulator/da9055-regulator.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -455,8 +456,7 @@ static int da9055_gpio_init(struct da9055_regulator *regulator, char name[18]; int gpio_mux = pdata->gpio_ren[id]; - config->ena_gpio = pdata->ena_gpio[id]; - config->ena_gpio_flags = GPIOF_OUT_INIT_HIGH; + config->ena_gpiod = pdata->ena_gpiods[id]; config->ena_gpio_invert = 1; /* diff --git a/include/linux/mfd/da9055/pdata.h b/include/linux/mfd/da9055/pdata.h index 04e092be4b07..1a94fa2ac309 100644 --- a/include/linux/mfd/da9055/pdata.h +++ b/include/linux/mfd/da9055/pdata.h @@ -12,6 +12,7 @@ #define DA9055_MAX_REGULATORS 8 struct da9055; +struct gpio_desc; enum gpio_select { NO_GPIO = 0, @@ -47,7 +48,7 @@ struct da9055_pdata { * controls the regulator set A/B, 0 if not available. */ enum gpio_select *reg_rsel; - /* GPIOs to enable regulator, 0 if not available */ - int *ena_gpio; + /* GPIO descriptors to enable regulator, NULL if not available */ + struct gpio_desc **ena_gpiods; }; #endif /* __DA9055_PDATA_H */ From 11da04af0d3b4c24ab057dd17f54dbc854d735de Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 12 Feb 2018 14:17:02 +0100 Subject: [PATCH 4/9] regulator: da9211: Pass descriptors instead of GPIO numbers This augments the DA9211 regulator driver to fetch its GPIO descriptors directly from the device tree using the newly exported devm_get_gpiod_from_child(). Signed-off-by: Linus Walleij Signed-off-by: Mark Brown --- drivers/regulator/da9211-regulator.c | 23 +++++++++++------------ include/linux/regulator/da9211.h | 4 +++- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c index 9b8f47617724..6c122b3df5d0 100644 --- a/drivers/regulator/da9211-regulator.c +++ b/drivers/regulator/da9211-regulator.c @@ -15,7 +15,6 @@ */ #include -#include #include #include #include @@ -25,7 +24,7 @@ #include #include #include -#include +#include #include #include #include "da9211-regulator.h" @@ -294,9 +293,12 @@ static struct da9211_pdata *da9211_parse_regulators_dt( pdata->init_data[n] = da9211_matches[i].init_data; pdata->reg_node[n] = da9211_matches[i].of_node; - pdata->gpio_ren[n] = - of_get_named_gpio(da9211_matches[i].of_node, - "enable-gpios", 0); + pdata->gpiod_ren[n] = devm_gpiod_get_from_of_node(dev, + da9211_matches[i].of_node, + "enable", + 0, + GPIOD_OUT_HIGH, + "da9211-enable"); n++; } @@ -382,13 +384,10 @@ static int da9211_regulator_init(struct da9211 *chip) config.regmap = chip->regmap; config.of_node = chip->pdata->reg_node[i]; - if (gpio_is_valid(chip->pdata->gpio_ren[i])) { - config.ena_gpio = chip->pdata->gpio_ren[i]; - config.ena_gpio_initialized = true; - } else { - config.ena_gpio = -EINVAL; - config.ena_gpio_initialized = false; - } + if (chip->pdata->gpiod_ren[i]) + config.ena_gpiod = chip->pdata->gpiod_ren[i]; + else + config.ena_gpiod = NULL; chip->rdev[i] = devm_regulator_register(chip->dev, &da9211_regulators[i], &config); diff --git a/include/linux/regulator/da9211.h b/include/linux/regulator/da9211.h index f2fd2d3bf58f..d1f2073e4d5f 100644 --- a/include/linux/regulator/da9211.h +++ b/include/linux/regulator/da9211.h @@ -21,6 +21,8 @@ #define DA9211_MAX_REGULATORS 2 +struct gpio_desc; + enum da9211_chip_id { DA9211, DA9212, @@ -39,7 +41,7 @@ struct da9211_pdata { * 2 : 2 phase 2 buck */ int num_buck; - int gpio_ren[DA9211_MAX_REGULATORS]; + struct gpio_desc *gpiod_ren[DA9211_MAX_REGULATORS]; struct device_node *reg_node[DA9211_MAX_REGULATORS]; struct regulator_init_data *init_data[DA9211_MAX_REGULATORS]; }; From 2a254de29e995ea58d73f75b69016cf913a5447d Mon Sep 17 00:00:00 2001 From: Alexander Monakov Date: Fri, 9 Mar 2018 01:53:02 +0300 Subject: [PATCH 5/9] regulator: 88pg86x: add DT bindings document The only device-specific node names are "buck1" and "buck2" for the two regulators present on the device. Sleep mode GPIO and per-regulator GPIO enable pins are not exposed (the driver does not support them either). Signed-off-by: Alexander Monakov Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/88pg86x.txt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/88pg86x.txt diff --git a/Documentation/devicetree/bindings/regulator/88pg86x.txt b/Documentation/devicetree/bindings/regulator/88pg86x.txt new file mode 100644 index 000000000000..13b7f49a2ea8 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/88pg86x.txt @@ -0,0 +1,22 @@ +Marvell 88PG867/88PG868 voltage regulators + +Required properties: +- compatible: one of "marvell,88pg867", "marvell,88pg868"; +- reg: I2C slave address. + +Optional subnodes for regulators: "buck1", "buck2", using common regulator +bindings given in . + +Example: + + pg868@19 { + compatible = "marvell,88pg868"; + reg = <0x19>; + + vcpu: buck1 { + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1350000>; + }; + }; From a265b03bd29a745d85237f47739d92cb43d214b9 Mon Sep 17 00:00:00 2001 From: Alexander Monakov Date: Fri, 9 Mar 2018 01:53:03 +0300 Subject: [PATCH 6/9] regulator: 88pg86x: new i2c dual regulator chip This chip is found on Google Chromecast and Valve Steam Link devices. It provides two DC regulators with I2C voltage control, separate GPIO enable pins and one sleep mode pin. This driver does not expose GPIO functionality, but supports voltage control in 1.0-2.2V range, based on I2C register information given in Chromecast kernel driver by Jisheng Zhang. Cc: Jisheng Zhang Signed-off-by: Alexander Monakov Signed-off-by: Mark Brown --- drivers/regulator/88pg86x.c | 114 ++++++++++++++++++++++++++++++++++++ drivers/regulator/Kconfig | 9 +++ drivers/regulator/Makefile | 1 + 3 files changed, 124 insertions(+) create mode 100644 drivers/regulator/88pg86x.c diff --git a/drivers/regulator/88pg86x.c b/drivers/regulator/88pg86x.c new file mode 100644 index 000000000000..d5ef55c81185 --- /dev/null +++ b/drivers/regulator/88pg86x.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include + +static const struct regulator_ops pg86x_ops = { + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear_range, +}; + +static const struct regulator_linear_range pg86x_buck1_ranges[] = { + REGULATOR_LINEAR_RANGE( 0, 0, 10, 0), + REGULATOR_LINEAR_RANGE(1000000, 11, 34, 25000), + REGULATOR_LINEAR_RANGE(1600000, 35, 47, 50000), +}; + +static const struct regulator_linear_range pg86x_buck2_ranges[] = { + REGULATOR_LINEAR_RANGE( 0, 0, 15, 0), + REGULATOR_LINEAR_RANGE(1000000, 16, 39, 25000), + REGULATOR_LINEAR_RANGE(1600000, 40, 52, 50000), +}; + +static const struct regulator_desc pg86x_regulators[] = { + { + .id = 0, + .type = REGULATOR_VOLTAGE, + .name = "buck1", + .of_match = of_match_ptr("buck1"), + .n_voltages = 11 + 24 + 13, + .linear_ranges = pg86x_buck1_ranges, + .n_linear_ranges = 3, + .vsel_reg = 0x24, + .vsel_mask = 0xff, + .ops = &pg86x_ops, + .owner = THIS_MODULE + }, + { + .id = 1, + .type = REGULATOR_VOLTAGE, + .name = "buck2", + .of_match = of_match_ptr("buck2"), + .n_voltages = 16 + 24 + 13, + .linear_ranges = pg86x_buck2_ranges, + .n_linear_ranges = 3, + .vsel_reg = 0x13, + .vsel_mask = 0xff, + .ops = &pg86x_ops, + .owner = THIS_MODULE + }, +}; + +static const struct regmap_config pg86x_regmap = { + .reg_bits = 8, + .val_bits = 8, +}; + +static int pg86x_i2c_probe(struct i2c_client *i2c) +{ + int id, ret; + struct regulator_config config = {.dev = &i2c->dev}; + struct regmap *regmap = devm_regmap_init_i2c(i2c, &pg86x_regmap); + + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + dev_err(&i2c->dev, "regmap init failed: %d\n", ret); + return ret; + } + + for (id = 0; id < ARRAY_SIZE(pg86x_regulators); id++) { + struct regulator_dev *rdev; + rdev = devm_regulator_register(&i2c->dev, + &pg86x_regulators[id], + &config); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); + dev_err(&i2c->dev, "failed to register %s: %d\n", + pg86x_regulators[id].name, ret); + return ret; + } + } + return 0; +} + +static const struct of_device_id pg86x_dt_ids [] = { + { .compatible = "marvell,88pg867" }, + { .compatible = "marvell,88pg868" }, + { } +}; +MODULE_DEVICE_TABLE(of, pg86x_dt_ids); + +static const struct i2c_device_id pg86x_i2c_id[] = { + { "88pg867", }, + { "88pg868", }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pg86x_i2c_id); + +static struct i2c_driver pg86x_regulator_driver = { + .driver = { + .name = "88pg86x", + .of_match_table = of_match_ptr(pg86x_dt_ids), + }, + .probe_new = pg86x_i2c_probe, + .id_table = pg86x_i2c_id, +}; + +module_i2c_driver(pg86x_regulator_driver); + +MODULE_DESCRIPTION("Marvell 88PG86X voltage regulator"); +MODULE_AUTHOR("Alexander Monakov "); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index b27417ca188a..097f61784a7d 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -54,6 +54,15 @@ config REGULATOR_USERSPACE_CONSUMER If unsure, say no. +config REGULATOR_88PG86X + tristate "Marvell 88PG86X voltage regulators" + depends on I2C + select REGMAP_I2C + help + This driver supports Marvell 88PG867 and 88PG868 voltage regulators. + They provide two I2C-controlled DC/DC step-down converters with + sleep mode and separate enable pins. + config REGULATOR_88PM800 tristate "Marvell 88PM800 Power regulators" depends on MFD_88PM800 diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 19fea09ba10a..590674fbecd7 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o +obj-$(CONFIG_REGULATOR_88PG86X) += 88pg86x.o obj-$(CONFIG_REGULATOR_88PM800) += 88pm800.o obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o obj-$(CONFIG_REGULATOR_CPCAP) += cpcap-regulator.o From ed8cffda27dea6fd3dafb3ee881c5a786edac9ca Mon Sep 17 00:00:00 2001 From: Christophe Jaillet Date: Tue, 13 Mar 2018 21:33:11 +0100 Subject: [PATCH 7/9] regulator: gpio: Fix some error handling paths in 'gpio_regulator_probe()' Re-order error handling code and gotos to avoid leaks in error handling paths. Fixes: 9f946099fe19 ("regulator: gpio: fix parsing of gpio list") Signed-off-by: Christophe JAILLET Signed-off-by: Mark Brown --- drivers/regulator/gpio-regulator.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c index 0fce06acfaec..a2eb50719c7b 100644 --- a/drivers/regulator/gpio-regulator.c +++ b/drivers/regulator/gpio-regulator.c @@ -271,8 +271,7 @@ static int gpio_regulator_probe(struct platform_device *pdev) drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL); if (drvdata->desc.name == NULL) { dev_err(&pdev->dev, "Failed to allocate supply name\n"); - ret = -ENOMEM; - goto err; + return -ENOMEM; } if (config->nr_gpios != 0) { @@ -292,7 +291,7 @@ static int gpio_regulator_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Could not obtain regulator setting GPIOs: %d\n", ret); - goto err_memstate; + goto err_memgpio; } } @@ -303,7 +302,7 @@ static int gpio_regulator_probe(struct platform_device *pdev) if (drvdata->states == NULL) { dev_err(&pdev->dev, "Failed to allocate state data\n"); ret = -ENOMEM; - goto err_memgpio; + goto err_stategpio; } drvdata->nr_states = config->nr_states; @@ -324,7 +323,7 @@ static int gpio_regulator_probe(struct platform_device *pdev) default: dev_err(&pdev->dev, "No regulator type set\n"); ret = -EINVAL; - goto err_memgpio; + goto err_memstate; } /* build initial state from gpio init data. */ @@ -361,22 +360,21 @@ static int gpio_regulator_probe(struct platform_device *pdev) if (IS_ERR(drvdata->dev)) { ret = PTR_ERR(drvdata->dev); dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret); - goto err_stategpio; + goto err_memstate; } platform_set_drvdata(pdev, drvdata); return 0; -err_stategpio: - gpio_free_array(drvdata->gpios, drvdata->nr_gpios); err_memstate: kfree(drvdata->states); +err_stategpio: + gpio_free_array(drvdata->gpios, drvdata->nr_gpios); err_memgpio: kfree(drvdata->gpios); err_name: kfree(drvdata->desc.name); -err: return ret; } From 37ad490bab09b7c218e37b570069cf188f2616e7 Mon Sep 17 00:00:00 2001 From: Nicholas Lowell Date: Mon, 19 Mar 2018 09:23:14 -0400 Subject: [PATCH 8/9] regulator: giving regulator controlling gpios a non-empty label when used through the devicetree. When the label is empty, it causes missing information and limits diagnostics for instances such as 'cat /sys/kernel/debug/gpio' Setting the label to the regulator supply_name will point to the device using the gpio(s). Signed-off-by: Nicholas Lowell Signed-off-by: Mark Brown --- drivers/regulator/gpio-regulator.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c index a2eb50719c7b..a86b8997bb54 100644 --- a/drivers/regulator/gpio-regulator.c +++ b/drivers/regulator/gpio-regulator.c @@ -196,6 +196,7 @@ of_get_gpio_regulator_config(struct device *dev, struct device_node *np, break; } config->gpios[i].gpio = gpio; + config->gpios[i].label = config->supply_name; if (proplen > 0) { of_property_read_u32_index(np, "gpios-states", i, &ret); From d3e4eccbb8ddd2bcf906a9c2a43980b00a568eb4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 22 Mar 2018 15:23:35 +0800 Subject: [PATCH 9/9] regulator: core: Add missing blank line between functions Signed-off-by: Mark Brown --- drivers/regulator/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index dd4708c58480..bdd947083924 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -4301,6 +4301,7 @@ static int regulator_suspend_late(struct device *dev) return class_for_each_device(®ulator_class, NULL, &state, _regulator_suspend_late); } + static int _regulator_resume_early(struct device *dev, void *data) { int ret = 0;