Branch data Line data Source code
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 : 0 : static int reg_clock_enable(struct regulator_dev *rdev) 53 : : { 54 : 0 : struct fixed_voltage_data *priv = rdev_get_drvdata(rdev); 55 : : int ret = 0; 56 : : 57 : 0 : ret = clk_prepare_enable(priv->enable_clock); 58 : 0 : if (ret) 59 : : return ret; 60 : : 61 : 0 : priv->clk_enable_counter++; 62 : : 63 : 0 : return ret; 64 : : } 65 : : 66 : 0 : static int reg_clock_disable(struct regulator_dev *rdev) 67 : : { 68 : 0 : struct fixed_voltage_data *priv = rdev_get_drvdata(rdev); 69 : : 70 : 0 : clk_disable_unprepare(priv->enable_clock); 71 : 0 : priv->clk_enable_counter--; 72 : : 73 : 0 : return 0; 74 : : } 75 : : 76 : 0 : static int reg_clock_is_enabled(struct regulator_dev *rdev) 77 : : { 78 : 0 : struct fixed_voltage_data *priv = rdev_get_drvdata(rdev); 79 : : 80 : 0 : 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 : 3 : of_get_fixed_voltage_config(struct device *dev, 95 : : const struct regulator_desc *desc) 96 : : { 97 : : struct fixed_voltage_config *config; 98 : 3 : 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 : 3 : if (!config) 104 : : return ERR_PTR(-ENOMEM); 105 : : 106 : 3 : config->init_data = of_get_regulator_init_data(dev, dev->of_node, desc); 107 : 3 : if (!config->init_data) 108 : : return ERR_PTR(-EINVAL); 109 : : 110 : : init_data = config->init_data; 111 : 3 : init_data->constraints.apply_uV = 0; 112 : : 113 : 3 : config->supply_name = init_data->constraints.name; 114 : 3 : if (init_data->constraints.min_uV == init_data->constraints.max_uV) { 115 : 3 : config->microvolts = init_data->constraints.min_uV; 116 : : } else { 117 : 0 : dev_err(dev, 118 : : "Fixed regulator specified with variable voltages\n"); 119 : 0 : return ERR_PTR(-EINVAL); 120 : : } 121 : : 122 : 3 : if (init_data->constraints.boot_on) 123 : 0 : config->enabled_at_boot = true; 124 : : 125 : 3 : of_property_read_u32(np, "startup-delay-us", &config->startup_delay); 126 : : 127 : 3 : if (of_find_property(np, "vin-supply", NULL)) 128 : 0 : config->input_supply = "vin"; 129 : : 130 : 3 : 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 : 3 : static int reg_fixed_voltage_probe(struct platform_device *pdev) 143 : : { 144 : 3 : struct device *dev = &pdev->dev; 145 : : struct fixed_voltage_config *config; 146 : : struct fixed_voltage_data *drvdata; 147 : 3 : const struct fixed_dev_type *drvtype = of_device_get_match_data(dev); 148 : 3 : 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 : 3 : if (!drvdata) 155 : : return -ENOMEM; 156 : : 157 : 3 : if (pdev->dev.of_node) { 158 : 3 : config = of_get_fixed_voltage_config(&pdev->dev, 159 : 3 : &drvdata->desc); 160 : 3 : if (IS_ERR(config)) 161 : 0 : return PTR_ERR(config); 162 : : } else { 163 : : config = dev_get_platdata(&pdev->dev); 164 : : } 165 : : 166 : 3 : if (!config) 167 : : return -ENOMEM; 168 : : 169 : 3 : drvdata->desc.name = devm_kstrdup(&pdev->dev, 170 : : config->supply_name, 171 : : GFP_KERNEL); 172 : 3 : if (drvdata->desc.name == NULL) { 173 : 0 : dev_err(&pdev->dev, "Failed to allocate supply name\n"); 174 : 0 : return -ENOMEM; 175 : : } 176 : 3 : drvdata->desc.type = REGULATOR_VOLTAGE; 177 : 3 : drvdata->desc.owner = THIS_MODULE; 178 : : 179 : 3 : if (drvtype && drvtype->has_enable_clock) { 180 : 0 : drvdata->desc.ops = &fixed_voltage_clkenabled_ops; 181 : : 182 : 0 : drvdata->enable_clock = devm_clk_get(dev, NULL); 183 : 0 : if (IS_ERR(drvdata->enable_clock)) { 184 : 0 : dev_err(dev, "Cant get enable-clock from devicetree\n"); 185 : 0 : return -ENOENT; 186 : : } 187 : : } else { 188 : 3 : drvdata->desc.ops = &fixed_voltage_ops; 189 : : } 190 : : 191 : 3 : drvdata->desc.enable_time = config->startup_delay; 192 : : 193 : 3 : if (config->input_supply) { 194 : 0 : drvdata->desc.supply_name = devm_kstrdup(&pdev->dev, 195 : : config->input_supply, 196 : : GFP_KERNEL); 197 : 0 : if (!drvdata->desc.supply_name) { 198 : 0 : dev_err(&pdev->dev, 199 : : "Failed to allocate input supply\n"); 200 : 0 : return -ENOMEM; 201 : : } 202 : : } 203 : : 204 : 3 : if (config->microvolts) 205 : 3 : drvdata->desc.n_voltages = 1; 206 : : 207 : 3 : 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 : 3 : 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 : 3 : 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 : 3 : cfg.ena_gpiod = gpiod_get_optional(&pdev->dev, NULL, gflags); 236 : 3 : if (IS_ERR(cfg.ena_gpiod)) 237 : 0 : return PTR_ERR(cfg.ena_gpiod); 238 : : 239 : 3 : cfg.dev = &pdev->dev; 240 : 3 : cfg.init_data = config->init_data; 241 : 3 : cfg.driver_data = drvdata; 242 : 3 : cfg.of_node = pdev->dev.of_node; 243 : : 244 : 3 : drvdata->dev = devm_regulator_register(&pdev->dev, &drvdata->desc, 245 : : &cfg); 246 : 3 : if (IS_ERR(drvdata->dev)) { 247 : : ret = PTR_ERR(drvdata->dev); 248 : 0 : dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret); 249 : 0 : 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 : 3 : 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 : 3 : static int __init regulator_fixed_voltage_init(void) 285 : : { 286 : 3 : return platform_driver_register(®ulator_fixed_voltage_driver); 287 : : } 288 : : subsys_initcall(regulator_fixed_voltage_init); 289 : : 290 : 0 : static void __exit regulator_fixed_voltage_exit(void) 291 : : { 292 : 0 : platform_driver_unregister(®ulator_fixed_voltage_driver); 293 : 0 : } 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");