| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * fixed.c |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 7 | 8 | * |
|---|
| 8 | 9 | * Copyright (c) 2009 Nokia Corporation |
|---|
| 9 | 10 | * Roger Quadros <ext-roger.quadros@nokia.com> |
|---|
| 10 | | - * |
|---|
| 11 | | - * This program is free software; you can redistribute it and/or |
|---|
| 12 | | - * modify it under the terms of the GNU General Public License as |
|---|
| 13 | | - * published by the Free Software Foundation; either version 2 of the |
|---|
| 14 | | - * License, or (at your option) any later version. |
|---|
| 15 | 11 | * |
|---|
| 16 | 12 | * This is useful for systems with mixed controllable and |
|---|
| 17 | 13 | * non-controllable regulators, as well as for allowing testing on |
|---|
| .. | .. |
|---|
| 24 | 20 | #include <linux/platform_device.h> |
|---|
| 25 | 21 | #include <linux/regulator/driver.h> |
|---|
| 26 | 22 | #include <linux/regulator/fixed.h> |
|---|
| 27 | | -#include <linux/gpio.h> |
|---|
| 23 | +#include <linux/gpio/consumer.h> |
|---|
| 28 | 24 | #include <linux/slab.h> |
|---|
| 29 | 25 | #include <linux/of.h> |
|---|
| 30 | | -#include <linux/of_gpio.h> |
|---|
| 26 | +#include <linux/of_device.h> |
|---|
| 31 | 27 | #include <linux/regulator/of_regulator.h> |
|---|
| 32 | 28 | #include <linux/regulator/machine.h> |
|---|
| 29 | +#include <linux/clk.h> |
|---|
| 30 | + |
|---|
| 33 | 31 | |
|---|
| 34 | 32 | struct fixed_voltage_data { |
|---|
| 35 | 33 | struct regulator_desc desc; |
|---|
| 36 | 34 | struct regulator_dev *dev; |
|---|
| 35 | + |
|---|
| 36 | + struct clk *enable_clock; |
|---|
| 37 | + unsigned int clk_enable_counter; |
|---|
| 37 | 38 | }; |
|---|
| 39 | + |
|---|
| 40 | +struct fixed_dev_type { |
|---|
| 41 | + bool has_enable_clock; |
|---|
| 42 | +}; |
|---|
| 43 | + |
|---|
| 44 | +static 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 | + |
|---|
| 58 | +static 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 | + |
|---|
| 68 | +static 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 | +} |
|---|
| 38 | 74 | |
|---|
| 39 | 75 | |
|---|
| 40 | 76 | /** |
|---|
| .. | .. |
|---|
| 78 | 114 | if (init_data->constraints.boot_on) |
|---|
| 79 | 115 | config->enabled_at_boot = true; |
|---|
| 80 | 116 | |
|---|
| 81 | | - config->gpio = of_get_named_gpio(np, "gpio", 0); |
|---|
| 82 | | - if ((config->gpio < 0) && (config->gpio != -ENOENT)) |
|---|
| 83 | | - return ERR_PTR(config->gpio); |
|---|
| 84 | | - |
|---|
| 85 | 117 | of_property_read_u32(np, "startup-delay-us", &config->startup_delay); |
|---|
| 86 | | - |
|---|
| 87 | | - config->enable_high = of_property_read_bool(np, "enable-active-high"); |
|---|
| 88 | | - config->gpio_is_open_drain = of_property_read_bool(np, |
|---|
| 89 | | - "gpio-open-drain"); |
|---|
| 118 | + of_property_read_u32(np, "off-on-delay-us", &config->off_on_delay); |
|---|
| 90 | 119 | |
|---|
| 91 | 120 | if (of_find_property(np, "vin-supply", NULL)) |
|---|
| 92 | 121 | config->input_supply = "vin"; |
|---|
| .. | .. |
|---|
| 94 | 123 | return config; |
|---|
| 95 | 124 | } |
|---|
| 96 | 125 | |
|---|
| 97 | | -static struct regulator_ops fixed_voltage_ops = { |
|---|
| 126 | +static const struct regulator_ops fixed_voltage_ops = { |
|---|
| 127 | +}; |
|---|
| 128 | + |
|---|
| 129 | +static 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, |
|---|
| 98 | 133 | }; |
|---|
| 99 | 134 | |
|---|
| 100 | 135 | static int reg_fixed_voltage_probe(struct platform_device *pdev) |
|---|
| 101 | 136 | { |
|---|
| 137 | + struct device *dev = &pdev->dev; |
|---|
| 102 | 138 | struct fixed_voltage_config *config; |
|---|
| 103 | 139 | struct fixed_voltage_data *drvdata; |
|---|
| 140 | + const struct fixed_dev_type *drvtype = of_device_get_match_data(dev); |
|---|
| 104 | 141 | struct regulator_config cfg = { }; |
|---|
| 142 | + enum gpiod_flags gflags; |
|---|
| 105 | 143 | int ret; |
|---|
| 106 | 144 | |
|---|
| 107 | 145 | drvdata = devm_kzalloc(&pdev->dev, sizeof(struct fixed_voltage_data), |
|---|
| .. | .. |
|---|
| 130 | 168 | } |
|---|
| 131 | 169 | drvdata->desc.type = REGULATOR_VOLTAGE; |
|---|
| 132 | 170 | drvdata->desc.owner = THIS_MODULE; |
|---|
| 133 | | - drvdata->desc.ops = &fixed_voltage_ops; |
|---|
| 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 | + } |
|---|
| 134 | 183 | |
|---|
| 135 | 184 | drvdata->desc.enable_time = config->startup_delay; |
|---|
| 185 | + drvdata->desc.off_on_delay = config->off_on_delay; |
|---|
| 136 | 186 | |
|---|
| 137 | 187 | if (config->input_supply) { |
|---|
| 138 | 188 | drvdata->desc.supply_name = devm_kstrdup(&pdev->dev, |
|---|
| .. | .. |
|---|
| 150 | 200 | |
|---|
| 151 | 201 | drvdata->desc.fixed_uV = config->microvolts; |
|---|
| 152 | 202 | |
|---|
| 153 | | - if (gpio_is_valid(config->gpio)) { |
|---|
| 154 | | - cfg.ena_gpio = config->gpio; |
|---|
| 155 | | - if (pdev->dev.of_node) |
|---|
| 156 | | - cfg.ena_gpio_initialized = true; |
|---|
| 157 | | - } |
|---|
| 158 | | - cfg.ena_gpio_invert = !config->enable_high; |
|---|
| 159 | | - if (config->enabled_at_boot) { |
|---|
| 160 | | - if (config->enable_high) |
|---|
| 161 | | - cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; |
|---|
| 162 | | - else |
|---|
| 163 | | - cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW; |
|---|
| 164 | | - } else { |
|---|
| 165 | | - if (config->enable_high) |
|---|
| 166 | | - cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW; |
|---|
| 167 | | - else |
|---|
| 168 | | - cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; |
|---|
| 169 | | - } |
|---|
| 170 | | - if (config->gpio_is_open_drain) |
|---|
| 171 | | - cfg.ena_gpio_flags |= GPIOF_OPEN_DRAIN; |
|---|
| 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); |
|---|
| 172 | 232 | |
|---|
| 173 | 233 | cfg.dev = &pdev->dev; |
|---|
| 174 | 234 | cfg.init_data = config->init_data; |
|---|
| .. | .. |
|---|
| 192 | 252 | } |
|---|
| 193 | 253 | |
|---|
| 194 | 254 | #if defined(CONFIG_OF) |
|---|
| 255 | +static const struct fixed_dev_type fixed_voltage_data = { |
|---|
| 256 | + .has_enable_clock = false, |
|---|
| 257 | +}; |
|---|
| 258 | + |
|---|
| 259 | +static const struct fixed_dev_type fixed_clkenable_data = { |
|---|
| 260 | + .has_enable_clock = true, |
|---|
| 261 | +}; |
|---|
| 262 | + |
|---|
| 195 | 263 | static const struct of_device_id fixed_of_match[] = { |
|---|
| 196 | | - { .compatible = "regulator-fixed", }, |
|---|
| 197 | | - {}, |
|---|
| 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 | + }, |
|---|
| 198 | 274 | }; |
|---|
| 199 | 275 | MODULE_DEVICE_TABLE(of, fixed_of_match); |
|---|
| 200 | 276 | #endif |
|---|