diff options
author | Philippe Schenker <philippe.schenker@toradex.com> | 2019-09-10 06:21:15 +0000 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2019-09-10 11:03:47 +0100 |
commit | 8959e5324485ace9bedc33ce1e760b759d4dd2ac (patch) | |
tree | f36cc0f0d34646da882287c8e7386dd19363905b | |
parent | d57d90f4443bd725b3facdc6130a1940af4560c4 (diff) |
regulator: fixed: add possibility to enable by clock
This commit adds the possibility to choose the compatible
"regulator-fixed-clock" in devicetree.
This is a special regulator-fixed that has to have a clock, from which
the regulator gets switched on and off.
Signed-off-by: Philippe Schenker <philippe.schenker@toradex.com>
Link: https://lore.kernel.org/r/20190910062103.39641-2-philippe.schenker@toradex.com
Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r-- | drivers/regulator/fixed.c | 83 |
1 files changed, 80 insertions, 3 deletions
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index 999547dde99d..d90a6fd8cbc7 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -23,14 +23,63 @@ #include <linux/gpio/consumer.h> #include <linux/slab.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/regulator/of_regulator.h> #include <linux/regulator/machine.h> +#include <linux/clk.h> + struct fixed_voltage_data { struct regulator_desc desc; struct regulator_dev *dev; + + struct clk *enable_clock; + unsigned int clk_enable_counter; }; +struct fixed_dev_type { + bool has_enable_clock; +}; + +static const struct fixed_dev_type fixed_voltage_data = { + .has_enable_clock = false, +}; + +static const struct fixed_dev_type fixed_clkenable_data = { + .has_enable_clock = true, +}; + +static int reg_clock_enable(struct regulator_dev *rdev) +{ + struct fixed_voltage_data *priv = rdev_get_drvdata(rdev); + int ret = 0; + + ret = clk_prepare_enable(priv->enable_clock); + if (ret) + return ret; + + priv->clk_enable_counter++; + + return ret; +} + +static int reg_clock_disable(struct regulator_dev *rdev) +{ + struct fixed_voltage_data *priv = rdev_get_drvdata(rdev); + + clk_disable_unprepare(priv->enable_clock); + priv->clk_enable_counter--; + + return 0; +} + +static int reg_clock_is_enabled(struct regulator_dev *rdev) +{ + struct fixed_voltage_data *priv = rdev_get_drvdata(rdev); + + return priv->clk_enable_counter > 0; +} + /** * of_get_fixed_voltage_config - extract fixed_voltage_config structure info @@ -84,10 +133,19 @@ of_get_fixed_voltage_config(struct device *dev, static struct regulator_ops fixed_voltage_ops = { }; +static struct regulator_ops fixed_voltage_clkenabled_ops = { + .enable = reg_clock_enable, + .disable = reg_clock_disable, + .is_enabled = reg_clock_is_enabled, +}; + static int reg_fixed_voltage_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct fixed_voltage_config *config; struct fixed_voltage_data *drvdata; + const struct fixed_dev_type *drvtype = + of_match_device(dev->driver->of_match_table, dev)->data; struct regulator_config cfg = { }; enum gpiod_flags gflags; int ret; @@ -118,7 +176,18 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) } drvdata->desc.type = REGULATOR_VOLTAGE; drvdata->desc.owner = THIS_MODULE; - drvdata->desc.ops = &fixed_voltage_ops; + + if (drvtype->has_enable_clock) { + drvdata->desc.ops = &fixed_voltage_clkenabled_ops; + + drvdata->enable_clock = devm_clk_get(dev, NULL); + if (IS_ERR(drvdata->enable_clock)) { + dev_err(dev, "Cant get enable-clock from devicetree\n"); + return -ENOENT; + } + } else { + drvdata->desc.ops = &fixed_voltage_ops; + } drvdata->desc.enable_time = config->startup_delay; @@ -191,8 +260,16 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) #if defined(CONFIG_OF) static const struct of_device_id fixed_of_match[] = { - { .compatible = "regulator-fixed", }, - {}, + { + .compatible = "regulator-fixed", + .data = &fixed_voltage_data, + }, + { + .compatible = "regulator-fixed-clock", + .data = &fixed_clkenable_data, + }, + { + }, }; MODULE_DEVICE_TABLE(of, fixed_of_match); #endif |