root/drivers/regulator/fixed.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. reg_clock_enable
  2. reg_clock_disable
  3. reg_clock_is_enabled
  4. of_get_fixed_voltage_config
  5. reg_fixed_voltage_probe
  6. regulator_fixed_voltage_init
  7. regulator_fixed_voltage_exit

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

/* [<][>][^][v][top][bottom][index][help] */