|
6 | 6 | */
|
7 | 7 |
|
8 | 8 | #include <linux/cleanup.h>
|
| 9 | +#include <linux/delay.h> |
9 | 10 | #include <linux/device.h>
|
10 | 11 | #include <linux/dev_printk.h>
|
11 | 12 | #include <linux/err.h>
|
12 | 13 | #include <linux/i2c.h>
|
13 | 14 | #include <linux/i2c-of-prober.h>
|
14 | 15 | #include <linux/module.h>
|
15 | 16 | #include <linux/of.h>
|
| 17 | +#include <linux/regulator/consumer.h> |
16 | 18 | #include <linux/slab.h>
|
17 | 19 | #include <linux/stddef.h>
|
18 | 20 |
|
|
29 | 31 | * address responds.
|
30 | 32 | *
|
31 | 33 | * TODO:
|
32 |
| - * - Support handling common regulators. |
33 | 34 | * - Support handling common GPIOs.
|
34 | 35 | * - Support I2C muxes
|
35 | 36 | */
|
@@ -181,3 +182,138 @@ int i2c_of_probe_component(struct device *dev, const struct i2c_of_probe_cfg *cf
|
181 | 182 | return ret;
|
182 | 183 | }
|
183 | 184 | EXPORT_SYMBOL_NS_GPL(i2c_of_probe_component, I2C_OF_PROBER);
|
| 185 | + |
| 186 | +static int i2c_of_probe_simple_get_supply(struct device *dev, struct device_node *node, |
| 187 | + struct i2c_of_probe_simple_ctx *ctx) |
| 188 | +{ |
| 189 | + const char *supply_name; |
| 190 | + struct regulator *supply; |
| 191 | + |
| 192 | + /* |
| 193 | + * It's entirely possible for the component's device node to not have the |
| 194 | + * regulator supplies. While it does not make sense from a hardware perspective, |
| 195 | + * the supplies could be always on or otherwise not modeled in the device tree, |
| 196 | + * but the device would still work. |
| 197 | + */ |
| 198 | + supply_name = ctx->opts->supply_name; |
| 199 | + if (!supply_name) |
| 200 | + return 0; |
| 201 | + |
| 202 | + supply = of_regulator_get_optional(dev, node, supply_name); |
| 203 | + if (IS_ERR(supply)) { |
| 204 | + return dev_err_probe(dev, PTR_ERR(supply), |
| 205 | + "Failed to get regulator supply \"%s\" from %pOF\n", |
| 206 | + supply_name, node); |
| 207 | + } |
| 208 | + |
| 209 | + ctx->supply = supply; |
| 210 | + |
| 211 | + return 0; |
| 212 | +} |
| 213 | + |
| 214 | +static void i2c_of_probe_simple_put_supply(struct i2c_of_probe_simple_ctx *ctx) |
| 215 | +{ |
| 216 | + regulator_put(ctx->supply); |
| 217 | + ctx->supply = NULL; |
| 218 | +} |
| 219 | + |
| 220 | +static int i2c_of_probe_simple_enable_regulator(struct device *dev, struct i2c_of_probe_simple_ctx *ctx) |
| 221 | +{ |
| 222 | + int ret; |
| 223 | + |
| 224 | + if (!ctx->supply) |
| 225 | + return 0; |
| 226 | + |
| 227 | + dev_dbg(dev, "Enabling regulator supply \"%s\"\n", ctx->opts->supply_name); |
| 228 | + |
| 229 | + ret = regulator_enable(ctx->supply); |
| 230 | + if (ret) |
| 231 | + return ret; |
| 232 | + |
| 233 | + if (ctx->opts->post_power_on_delay_ms) |
| 234 | + msleep(ctx->opts->post_power_on_delay_ms); |
| 235 | + |
| 236 | + return 0; |
| 237 | +} |
| 238 | + |
| 239 | +static void i2c_of_probe_simple_disable_regulator(struct device *dev, struct i2c_of_probe_simple_ctx *ctx) |
| 240 | +{ |
| 241 | + if (!ctx->supply) |
| 242 | + return; |
| 243 | + |
| 244 | + dev_dbg(dev, "Disabling regulator supply \"%s\"\n", ctx->opts->supply_name); |
| 245 | + |
| 246 | + regulator_disable(ctx->supply); |
| 247 | +} |
| 248 | + |
| 249 | +/** |
| 250 | + * i2c_of_probe_simple_enable - Simple helper for I2C OF prober to get and enable resources |
| 251 | + * @dev: Pointer to the &struct device of the caller, only used for dev_printk() messages |
| 252 | + * @bus_node: Pointer to the &struct device_node of the I2C adapter. |
| 253 | + * @data: Pointer to &struct i2c_of_probe_simple_ctx helper context. |
| 254 | + * |
| 255 | + * If &i2c_of_probe_simple_opts->supply_name is given, request the named regulator supply. |
| 256 | + * If a regulator supply was found, enable that regulator. |
| 257 | + * |
| 258 | + * Return: %0 on success or no-op, or a negative error number on failure. |
| 259 | + */ |
| 260 | +int i2c_of_probe_simple_enable(struct device *dev, struct device_node *bus_node, void *data) |
| 261 | +{ |
| 262 | + struct i2c_of_probe_simple_ctx *ctx = data; |
| 263 | + struct device_node *node; |
| 264 | + const char *compat; |
| 265 | + int ret; |
| 266 | + |
| 267 | + dev_dbg(dev, "Requesting resources for components under I2C bus %pOF\n", bus_node); |
| 268 | + |
| 269 | + if (!ctx || !ctx->opts) |
| 270 | + return -EINVAL; |
| 271 | + |
| 272 | + compat = ctx->opts->res_node_compatible; |
| 273 | + if (!compat) |
| 274 | + return -EINVAL; |
| 275 | + |
| 276 | + node = of_get_compatible_child(bus_node, compat); |
| 277 | + if (!node) |
| 278 | + return dev_err_probe(dev, -ENODEV, "No device compatible with \"%s\" found\n", |
| 279 | + compat); |
| 280 | + |
| 281 | + ret = i2c_of_probe_simple_get_supply(dev, node, ctx); |
| 282 | + if (ret) |
| 283 | + goto out_put_node; |
| 284 | + |
| 285 | + ret = i2c_of_probe_simple_enable_regulator(dev, ctx); |
| 286 | + if (ret) |
| 287 | + goto out_put_supply; |
| 288 | + |
| 289 | + return 0; |
| 290 | + |
| 291 | +out_put_supply: |
| 292 | + i2c_of_probe_simple_put_supply(ctx); |
| 293 | +out_put_node: |
| 294 | + of_node_put(node); |
| 295 | + return ret; |
| 296 | +} |
| 297 | +EXPORT_SYMBOL_NS_GPL(i2c_of_probe_simple_enable, I2C_OF_PROBER); |
| 298 | + |
| 299 | +/** |
| 300 | + * i2c_of_probe_simple_cleanup - Clean up and release resources for I2C OF prober simple helpers |
| 301 | + * @dev: Pointer to the &struct device of the caller, only used for dev_printk() messages |
| 302 | + * @data: Pointer to &struct i2c_of_probe_simple_ctx helper context. |
| 303 | + * |
| 304 | + * * If a regulator supply was found, disable that regulator and release it. |
| 305 | + */ |
| 306 | +void i2c_of_probe_simple_cleanup(struct device *dev, void *data) |
| 307 | +{ |
| 308 | + struct i2c_of_probe_simple_ctx *ctx = data; |
| 309 | + |
| 310 | + i2c_of_probe_simple_disable_regulator(dev, ctx); |
| 311 | + i2c_of_probe_simple_put_supply(ctx); |
| 312 | +} |
| 313 | +EXPORT_SYMBOL_NS_GPL(i2c_of_probe_simple_cleanup, I2C_OF_PROBER); |
| 314 | + |
| 315 | +struct i2c_of_probe_ops i2c_of_probe_simple_ops = { |
| 316 | + .enable = i2c_of_probe_simple_enable, |
| 317 | + .cleanup = i2c_of_probe_simple_cleanup, |
| 318 | +}; |
| 319 | +EXPORT_SYMBOL_NS_GPL(i2c_of_probe_simple_ops, I2C_OF_PROBER); |
0 commit comments