linux/drivers/regulator/fixed.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * fixed.c
   4 *
   5 * Copyright 2008 Wolfson Microelectronics PLC.
   6 *
   7 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
   8 *
   9 * Copyright (c) 2009 Nokia Corporation
  10 * Roger Quadros <ext-roger.quadros@nokia.com>
  11 *
  12 * This is useful for systems with mixed controllable and
  13 * non-controllable regulators, as well as for allowing testing on
  14 * systems with no controllable regulators.
  15 */
  16
  17#include <linux/err.h>
  18#include <linux/mutex.h>
  19#include <linux/module.h>
  20#include <linux/platform_device.h>
  21#include <linux/pm_domain.h>
  22#include <linux/pm_opp.h>
  23#include <linux/regulator/driver.h>
  24#include <linux/regulator/fixed.h>
  25#include <linux/gpio/consumer.h>
  26#include <linux/slab.h>
  27#include <linux/of.h>
  28#include <linux/of_device.h>
  29#include <linux/regulator/of_regulator.h>
  30#include <linux/regulator/machine.h>
  31#include <linux/clk.h>
  32
  33
  34struct fixed_voltage_data {
  35        struct regulator_desc desc;
  36        struct regulator_dev *dev;
  37
  38        struct clk *enable_clock;
  39        unsigned int enable_counter;
  40        int performance_state;
  41};
  42
  43struct fixed_dev_type {
  44        bool has_enable_clock;
  45        bool has_performance_state;
  46};
  47
  48static int reg_clock_enable(struct regulator_dev *rdev)
  49{
  50        struct fixed_voltage_data *priv = rdev_get_drvdata(rdev);
  51        int ret = 0;
  52
  53        ret = clk_prepare_enable(priv->enable_clock);
  54        if (ret)
  55                return ret;
  56
  57        priv->enable_counter++;
  58
  59        return ret;
  60}
  61
  62static int reg_clock_disable(struct regulator_dev *rdev)
  63{
  64        struct fixed_voltage_data *priv = rdev_get_drvdata(rdev);
  65
  66        clk_disable_unprepare(priv->enable_clock);
  67        priv->enable_counter--;
  68
  69        return 0;
  70}
  71
  72static int reg_domain_enable(struct regulator_dev *rdev)
  73{
  74        struct fixed_voltage_data *priv = rdev_get_drvdata(rdev);
  75        struct device *dev = rdev->dev.parent;
  76        int ret;
  77
  78        ret = dev_pm_genpd_set_performance_state(dev, priv->performance_state);
  79        if (ret)
  80                return ret;
  81
  82        priv->enable_counter++;
  83
  84        return ret;
  85}
  86
  87static int reg_domain_disable(struct regulator_dev *rdev)
  88{
  89        struct fixed_voltage_data *priv = rdev_get_drvdata(rdev);
  90        struct device *dev = rdev->dev.parent;
  91        int ret;
  92
  93        ret = dev_pm_genpd_set_performance_state(dev, 0);
  94        if (ret)
  95                return ret;
  96
  97        priv->enable_counter--;
  98
  99        return 0;
 100}
 101
 102static int reg_is_enabled(struct regulator_dev *rdev)
 103{
 104        struct fixed_voltage_data *priv = rdev_get_drvdata(rdev);
 105
 106        return priv->enable_counter > 0;
 107}
 108
 109
 110/**
 111 * of_get_fixed_voltage_config - extract fixed_voltage_config structure info
 112 * @dev: device requesting for fixed_voltage_config
 113 * @desc: regulator description
 114 *
 115 * Populates fixed_voltage_config structure by extracting data from device
 116 * tree node, returns a pointer to the populated structure of NULL if memory
 117 * alloc fails.
 118 */
 119static struct fixed_voltage_config *
 120of_get_fixed_voltage_config(struct device *dev,
 121                            const struct regulator_desc *desc)
 122{
 123        struct fixed_voltage_config *config;
 124        struct device_node *np = dev->of_node;
 125        struct regulator_init_data *init_data;
 126
 127        config = devm_kzalloc(dev, sizeof(struct fixed_voltage_config),
 128                                                                 GFP_KERNEL);
 129        if (!config)
 130                return ERR_PTR(-ENOMEM);
 131
 132        config->init_data = of_get_regulator_init_data(dev, dev->of_node, desc);
 133        if (!config->init_data)
 134                return ERR_PTR(-EINVAL);
 135
 136        init_data = config->init_data;
 137        init_data->constraints.apply_uV = 0;
 138
 139        config->supply_name = init_data->constraints.name;
 140        if (init_data->constraints.min_uV == init_data->constraints.max_uV) {
 141                config->microvolts = init_data->constraints.min_uV;
 142        } else {
 143                dev_err(dev,
 144                         "Fixed regulator specified with variable voltages\n");
 145                return ERR_PTR(-EINVAL);
 146        }
 147
 148        if (init_data->constraints.boot_on)
 149                config->enabled_at_boot = true;
 150
 151        of_property_read_u32(np, "startup-delay-us", &config->startup_delay);
 152        of_property_read_u32(np, "off-on-delay-us", &config->off_on_delay);
 153
 154        if (of_find_property(np, "vin-supply", NULL))
 155                config->input_supply = "vin";
 156
 157        return config;
 158}
 159
 160static const struct regulator_ops fixed_voltage_ops = {
 161};
 162
 163static const struct regulator_ops fixed_voltage_clkenabled_ops = {
 164        .enable = reg_clock_enable,
 165        .disable = reg_clock_disable,
 166        .is_enabled = reg_is_enabled,
 167};
 168
 169static const struct regulator_ops fixed_voltage_domain_ops = {
 170        .enable = reg_domain_enable,
 171        .disable = reg_domain_disable,
 172        .is_enabled = reg_is_enabled,
 173};
 174
 175static int reg_fixed_voltage_probe(struct platform_device *pdev)
 176{
 177        struct device *dev = &pdev->dev;
 178        struct fixed_voltage_config *config;
 179        struct fixed_voltage_data *drvdata;
 180        const struct fixed_dev_type *drvtype = of_device_get_match_data(dev);
 181        struct regulator_config cfg = { };
 182        enum gpiod_flags gflags;
 183        int ret;
 184
 185        drvdata = devm_kzalloc(&pdev->dev, sizeof(struct fixed_voltage_data),
 186                               GFP_KERNEL);
 187        if (!drvdata)
 188                return -ENOMEM;
 189
 190        if (pdev->dev.of_node) {
 191                config = of_get_fixed_voltage_config(&pdev->dev,
 192                                                     &drvdata->desc);
 193                if (IS_ERR(config))
 194                        return PTR_ERR(config);
 195        } else {
 196                config = dev_get_platdata(&pdev->dev);
 197        }
 198
 199        if (!config)
 200                return -ENOMEM;
 201
 202        drvdata->desc.name = devm_kstrdup(&pdev->dev,
 203                                          config->supply_name,
 204                                          GFP_KERNEL);
 205        if (drvdata->desc.name == NULL) {
 206                dev_err(&pdev->dev, "Failed to allocate supply name\n");
 207                return -ENOMEM;
 208        }
 209        drvdata->desc.type = REGULATOR_VOLTAGE;
 210        drvdata->desc.owner = THIS_MODULE;
 211
 212        if (drvtype && drvtype->has_enable_clock) {
 213                drvdata->desc.ops = &fixed_voltage_clkenabled_ops;
 214
 215                drvdata->enable_clock = devm_clk_get(dev, NULL);
 216                if (IS_ERR(drvdata->enable_clock)) {
 217                        dev_err(dev, "Can't get enable-clock from devicetree\n");
 218                        return -ENOENT;
 219                }
 220        } else if (drvtype && drvtype->has_performance_state) {
 221                drvdata->desc.ops = &fixed_voltage_domain_ops;
 222
 223                drvdata->performance_state = of_get_required_opp_performance_state(dev->of_node, 0);
 224                if (drvdata->performance_state < 0) {
 225                        dev_err(dev, "Can't get performance state from devicetree\n");
 226                        return drvdata->performance_state;
 227                }
 228        } else {
 229                drvdata->desc.ops = &fixed_voltage_ops;
 230        }
 231
 232        drvdata->desc.enable_time = config->startup_delay;
 233        drvdata->desc.off_on_delay = config->off_on_delay;
 234
 235        if (config->input_supply) {
 236                drvdata->desc.supply_name = devm_kstrdup(&pdev->dev,
 237                                            config->input_supply,
 238                                            GFP_KERNEL);
 239                if (!drvdata->desc.supply_name) {
 240                        dev_err(&pdev->dev,
 241                                "Failed to allocate input supply\n");
 242                        return -ENOMEM;
 243                }
 244        }
 245
 246        if (config->microvolts)
 247                drvdata->desc.n_voltages = 1;
 248
 249        drvdata->desc.fixed_uV = config->microvolts;
 250
 251        /*
 252         * The signal will be inverted by the GPIO core if flagged so in the
 253         * descriptor.
 254         */
 255        if (config->enabled_at_boot)
 256                gflags = GPIOD_OUT_HIGH;
 257        else
 258                gflags = GPIOD_OUT_LOW;
 259
 260        /*
 261         * Some fixed regulators share the enable line between two
 262         * regulators which makes it necessary to get a handle on the
 263         * same descriptor for two different consumers. This will get
 264         * the GPIO descriptor, but only the first call will initialize
 265         * it so any flags such as inversion or open drain will only
 266         * be set up by the first caller and assumed identical on the
 267         * next caller.
 268         *
 269         * FIXME: find a better way to deal with this.
 270         */
 271        gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE;
 272
 273        /*
 274         * Do not use devm* here: the regulator core takes over the
 275         * lifecycle management of the GPIO descriptor.
 276         */
 277        cfg.ena_gpiod = gpiod_get_optional(&pdev->dev, NULL, gflags);
 278        if (IS_ERR(cfg.ena_gpiod))
 279                return dev_err_probe(&pdev->dev, PTR_ERR(cfg.ena_gpiod),
 280                                     "can't get GPIO\n");
 281
 282        cfg.dev = &pdev->dev;
 283        cfg.init_data = config->init_data;
 284        cfg.driver_data = drvdata;
 285        cfg.of_node = pdev->dev.of_node;
 286
 287        drvdata->dev = devm_regulator_register(&pdev->dev, &drvdata->desc,
 288                                               &cfg);
 289        if (IS_ERR(drvdata->dev)) {
 290                ret = dev_err_probe(&pdev->dev, PTR_ERR(drvdata->dev),
 291                                    "Failed to register regulator: %ld\n",
 292                                    PTR_ERR(drvdata->dev));
 293                return ret;
 294        }
 295
 296        platform_set_drvdata(pdev, drvdata);
 297
 298        dev_dbg(&pdev->dev, "%s supplying %duV\n", drvdata->desc.name,
 299                drvdata->desc.fixed_uV);
 300
 301        return 0;
 302}
 303
 304#if defined(CONFIG_OF)
 305static const struct fixed_dev_type fixed_voltage_data = {
 306        .has_enable_clock = false,
 307};
 308
 309static const struct fixed_dev_type fixed_clkenable_data = {
 310        .has_enable_clock = true,
 311};
 312
 313static const struct fixed_dev_type fixed_domain_data = {
 314        .has_performance_state = true,
 315};
 316
 317static const struct of_device_id fixed_of_match[] = {
 318        {
 319                .compatible = "regulator-fixed",
 320                .data = &fixed_voltage_data,
 321        },
 322        {
 323                .compatible = "regulator-fixed-clock",
 324                .data = &fixed_clkenable_data,
 325        },
 326        {
 327                .compatible = "regulator-fixed-domain",
 328                .data = &fixed_domain_data,
 329        },
 330        {
 331        },
 332};
 333MODULE_DEVICE_TABLE(of, fixed_of_match);
 334#endif
 335
 336static struct platform_driver regulator_fixed_voltage_driver = {
 337        .probe          = reg_fixed_voltage_probe,
 338        .driver         = {
 339                .name           = "reg-fixed-voltage",
 340                .of_match_table = of_match_ptr(fixed_of_match),
 341        },
 342};
 343
 344static int __init regulator_fixed_voltage_init(void)
 345{
 346        return platform_driver_register(&regulator_fixed_voltage_driver);
 347}
 348subsys_initcall(regulator_fixed_voltage_init);
 349
 350static void __exit regulator_fixed_voltage_exit(void)
 351{
 352        platform_driver_unregister(&regulator_fixed_voltage_driver);
 353}
 354module_exit(regulator_fixed_voltage_exit);
 355
 356MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
 357MODULE_DESCRIPTION("Fixed voltage regulator");
 358MODULE_LICENSE("GPL");
 359MODULE_ALIAS("platform:reg-fixed-voltage");
 360