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