18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * gpio-regulator.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2011 Heiko Stuebner <heiko@sntech.de> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * based on fixed.c 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Copyright 2008 Wolfson Microelectronics PLC. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Copyright (c) 2009 Nokia Corporation 148c2ecf20Sopenharmony_ci * Roger Quadros <ext-roger.quadros@nokia.com> 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * This is useful for systems with mixed controllable and 178c2ecf20Sopenharmony_ci * non-controllable regulators, as well as for allowing testing on 188c2ecf20Sopenharmony_ci * systems with no controllable regulators. 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/err.h> 228c2ecf20Sopenharmony_ci#include <linux/mutex.h> 238c2ecf20Sopenharmony_ci#include <linux/module.h> 248c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 258c2ecf20Sopenharmony_ci#include <linux/regulator/driver.h> 268c2ecf20Sopenharmony_ci#include <linux/regulator/machine.h> 278c2ecf20Sopenharmony_ci#include <linux/regulator/of_regulator.h> 288c2ecf20Sopenharmony_ci#include <linux/regulator/gpio-regulator.h> 298c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 308c2ecf20Sopenharmony_ci#include <linux/slab.h> 318c2ecf20Sopenharmony_ci#include <linux/of.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistruct gpio_regulator_data { 348c2ecf20Sopenharmony_ci struct regulator_desc desc; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci struct gpio_desc **gpiods; 378c2ecf20Sopenharmony_ci int nr_gpios; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci struct gpio_regulator_state *states; 408c2ecf20Sopenharmony_ci int nr_states; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci int state; 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic int gpio_regulator_get_value(struct regulator_dev *dev) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci struct gpio_regulator_data *data = rdev_get_drvdata(dev); 488c2ecf20Sopenharmony_ci int ptr; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci for (ptr = 0; ptr < data->nr_states; ptr++) 518c2ecf20Sopenharmony_ci if (data->states[ptr].gpios == data->state) 528c2ecf20Sopenharmony_ci return data->states[ptr].value; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci return -EINVAL; 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic int gpio_regulator_set_voltage(struct regulator_dev *dev, 588c2ecf20Sopenharmony_ci int min_uV, int max_uV, 598c2ecf20Sopenharmony_ci unsigned *selector) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct gpio_regulator_data *data = rdev_get_drvdata(dev); 628c2ecf20Sopenharmony_ci int ptr, target = 0, state, best_val = INT_MAX; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci for (ptr = 0; ptr < data->nr_states; ptr++) 658c2ecf20Sopenharmony_ci if (data->states[ptr].value < best_val && 668c2ecf20Sopenharmony_ci data->states[ptr].value >= min_uV && 678c2ecf20Sopenharmony_ci data->states[ptr].value <= max_uV) { 688c2ecf20Sopenharmony_ci target = data->states[ptr].gpios; 698c2ecf20Sopenharmony_ci best_val = data->states[ptr].value; 708c2ecf20Sopenharmony_ci if (selector) 718c2ecf20Sopenharmony_ci *selector = ptr; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci if (best_val == INT_MAX) 758c2ecf20Sopenharmony_ci return -EINVAL; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci for (ptr = 0; ptr < data->nr_gpios; ptr++) { 788c2ecf20Sopenharmony_ci state = (target & (1 << ptr)) >> ptr; 798c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(data->gpiods[ptr], state); 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci data->state = target; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci return 0; 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic int gpio_regulator_list_voltage(struct regulator_dev *dev, 878c2ecf20Sopenharmony_ci unsigned selector) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci struct gpio_regulator_data *data = rdev_get_drvdata(dev); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci if (selector >= data->nr_states) 928c2ecf20Sopenharmony_ci return -EINVAL; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci return data->states[selector].value; 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic int gpio_regulator_set_current_limit(struct regulator_dev *dev, 988c2ecf20Sopenharmony_ci int min_uA, int max_uA) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci struct gpio_regulator_data *data = rdev_get_drvdata(dev); 1018c2ecf20Sopenharmony_ci int ptr, target = 0, state, best_val = 0; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci for (ptr = 0; ptr < data->nr_states; ptr++) 1048c2ecf20Sopenharmony_ci if (data->states[ptr].value > best_val && 1058c2ecf20Sopenharmony_ci data->states[ptr].value >= min_uA && 1068c2ecf20Sopenharmony_ci data->states[ptr].value <= max_uA) { 1078c2ecf20Sopenharmony_ci target = data->states[ptr].gpios; 1088c2ecf20Sopenharmony_ci best_val = data->states[ptr].value; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (best_val == 0) 1128c2ecf20Sopenharmony_ci return -EINVAL; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci for (ptr = 0; ptr < data->nr_gpios; ptr++) { 1158c2ecf20Sopenharmony_ci state = (target & (1 << ptr)) >> ptr; 1168c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(data->gpiods[ptr], state); 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci data->state = target; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci return 0; 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic const struct regulator_ops gpio_regulator_voltage_ops = { 1248c2ecf20Sopenharmony_ci .get_voltage = gpio_regulator_get_value, 1258c2ecf20Sopenharmony_ci .set_voltage = gpio_regulator_set_voltage, 1268c2ecf20Sopenharmony_ci .list_voltage = gpio_regulator_list_voltage, 1278c2ecf20Sopenharmony_ci}; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic struct gpio_regulator_config * 1308c2ecf20Sopenharmony_ciof_get_gpio_regulator_config(struct device *dev, struct device_node *np, 1318c2ecf20Sopenharmony_ci const struct regulator_desc *desc) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci struct gpio_regulator_config *config; 1348c2ecf20Sopenharmony_ci const char *regtype; 1358c2ecf20Sopenharmony_ci int proplen, i; 1368c2ecf20Sopenharmony_ci int ngpios; 1378c2ecf20Sopenharmony_ci int ret; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci config = devm_kzalloc(dev, 1408c2ecf20Sopenharmony_ci sizeof(struct gpio_regulator_config), 1418c2ecf20Sopenharmony_ci GFP_KERNEL); 1428c2ecf20Sopenharmony_ci if (!config) 1438c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci config->init_data = of_get_regulator_init_data(dev, np, desc); 1468c2ecf20Sopenharmony_ci if (!config->init_data) 1478c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci config->supply_name = config->init_data->constraints.name; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (config->init_data->constraints.boot_on) 1528c2ecf20Sopenharmony_ci config->enabled_at_boot = true; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci /* 1558c2ecf20Sopenharmony_ci * Do not use: undocumented device tree property. 1568c2ecf20Sopenharmony_ci * This is kept around solely for device tree ABI stability. 1578c2ecf20Sopenharmony_ci */ 1588c2ecf20Sopenharmony_ci if (of_property_read_bool(np, "enable-at-boot")) 1598c2ecf20Sopenharmony_ci config->enabled_at_boot = true; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci of_property_read_u32(np, "startup-delay-us", &config->startup_delay); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci /* Fetch GPIO init levels */ 1648c2ecf20Sopenharmony_ci ngpios = gpiod_count(dev, NULL); 1658c2ecf20Sopenharmony_ci if (ngpios > 0) { 1668c2ecf20Sopenharmony_ci config->gflags = devm_kzalloc(dev, 1678c2ecf20Sopenharmony_ci sizeof(enum gpiod_flags) 1688c2ecf20Sopenharmony_ci * ngpios, 1698c2ecf20Sopenharmony_ci GFP_KERNEL); 1708c2ecf20Sopenharmony_ci if (!config->gflags) 1718c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci for (i = 0; i < ngpios; i++) { 1748c2ecf20Sopenharmony_ci u32 val; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci ret = of_property_read_u32_index(np, "gpios-states", i, 1778c2ecf20Sopenharmony_ci &val); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* Default to high per specification */ 1808c2ecf20Sopenharmony_ci if (ret) 1818c2ecf20Sopenharmony_ci config->gflags[i] = GPIOD_OUT_HIGH; 1828c2ecf20Sopenharmony_ci else 1838c2ecf20Sopenharmony_ci config->gflags[i] = 1848c2ecf20Sopenharmony_ci val ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci config->ngpios = ngpios; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci /* Fetch states. */ 1908c2ecf20Sopenharmony_ci proplen = of_property_count_u32_elems(np, "states"); 1918c2ecf20Sopenharmony_ci if (proplen < 0) { 1928c2ecf20Sopenharmony_ci dev_err(dev, "No 'states' property found\n"); 1938c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci config->states = devm_kcalloc(dev, 1978c2ecf20Sopenharmony_ci proplen / 2, 1988c2ecf20Sopenharmony_ci sizeof(struct gpio_regulator_state), 1998c2ecf20Sopenharmony_ci GFP_KERNEL); 2008c2ecf20Sopenharmony_ci if (!config->states) 2018c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci for (i = 0; i < proplen / 2; i++) { 2048c2ecf20Sopenharmony_ci of_property_read_u32_index(np, "states", i * 2, 2058c2ecf20Sopenharmony_ci &config->states[i].value); 2068c2ecf20Sopenharmony_ci of_property_read_u32_index(np, "states", i * 2 + 1, 2078c2ecf20Sopenharmony_ci &config->states[i].gpios); 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci config->nr_states = i; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci config->type = REGULATOR_VOLTAGE; 2128c2ecf20Sopenharmony_ci ret = of_property_read_string(np, "regulator-type", ®type); 2138c2ecf20Sopenharmony_ci if (ret >= 0) { 2148c2ecf20Sopenharmony_ci if (!strncmp("voltage", regtype, 7)) 2158c2ecf20Sopenharmony_ci config->type = REGULATOR_VOLTAGE; 2168c2ecf20Sopenharmony_ci else if (!strncmp("current", regtype, 7)) 2178c2ecf20Sopenharmony_ci config->type = REGULATOR_CURRENT; 2188c2ecf20Sopenharmony_ci else 2198c2ecf20Sopenharmony_ci dev_warn(dev, "Unknown regulator-type '%s'\n", 2208c2ecf20Sopenharmony_ci regtype); 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci return config; 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic const struct regulator_ops gpio_regulator_current_ops = { 2278c2ecf20Sopenharmony_ci .get_current_limit = gpio_regulator_get_value, 2288c2ecf20Sopenharmony_ci .set_current_limit = gpio_regulator_set_current_limit, 2298c2ecf20Sopenharmony_ci}; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic int gpio_regulator_probe(struct platform_device *pdev) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 2348c2ecf20Sopenharmony_ci struct gpio_regulator_config *config = dev_get_platdata(dev); 2358c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 2368c2ecf20Sopenharmony_ci struct gpio_regulator_data *drvdata; 2378c2ecf20Sopenharmony_ci struct regulator_config cfg = { }; 2388c2ecf20Sopenharmony_ci struct regulator_dev *rdev; 2398c2ecf20Sopenharmony_ci enum gpiod_flags gflags; 2408c2ecf20Sopenharmony_ci int ptr, ret, state, i; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci drvdata = devm_kzalloc(dev, sizeof(struct gpio_regulator_data), 2438c2ecf20Sopenharmony_ci GFP_KERNEL); 2448c2ecf20Sopenharmony_ci if (drvdata == NULL) 2458c2ecf20Sopenharmony_ci return -ENOMEM; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (np) { 2488c2ecf20Sopenharmony_ci config = of_get_gpio_regulator_config(dev, np, 2498c2ecf20Sopenharmony_ci &drvdata->desc); 2508c2ecf20Sopenharmony_ci if (IS_ERR(config)) 2518c2ecf20Sopenharmony_ci return PTR_ERR(config); 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci drvdata->desc.name = devm_kstrdup(dev, config->supply_name, GFP_KERNEL); 2558c2ecf20Sopenharmony_ci if (drvdata->desc.name == NULL) { 2568c2ecf20Sopenharmony_ci dev_err(dev, "Failed to allocate supply name\n"); 2578c2ecf20Sopenharmony_ci return -ENOMEM; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci drvdata->gpiods = devm_kzalloc(dev, sizeof(struct gpio_desc *), 2618c2ecf20Sopenharmony_ci GFP_KERNEL); 2628c2ecf20Sopenharmony_ci if (!drvdata->gpiods) 2638c2ecf20Sopenharmony_ci return -ENOMEM; 2648c2ecf20Sopenharmony_ci for (i = 0; i < config->ngpios; i++) { 2658c2ecf20Sopenharmony_ci drvdata->gpiods[i] = devm_gpiod_get_index(dev, 2668c2ecf20Sopenharmony_ci NULL, 2678c2ecf20Sopenharmony_ci i, 2688c2ecf20Sopenharmony_ci config->gflags[i]); 2698c2ecf20Sopenharmony_ci if (IS_ERR(drvdata->gpiods[i])) 2708c2ecf20Sopenharmony_ci return PTR_ERR(drvdata->gpiods[i]); 2718c2ecf20Sopenharmony_ci /* This is good to know */ 2728c2ecf20Sopenharmony_ci gpiod_set_consumer_name(drvdata->gpiods[i], drvdata->desc.name); 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci drvdata->nr_gpios = config->ngpios; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci drvdata->states = devm_kmemdup(dev, 2778c2ecf20Sopenharmony_ci config->states, 2788c2ecf20Sopenharmony_ci config->nr_states * 2798c2ecf20Sopenharmony_ci sizeof(struct gpio_regulator_state), 2808c2ecf20Sopenharmony_ci GFP_KERNEL); 2818c2ecf20Sopenharmony_ci if (drvdata->states == NULL) { 2828c2ecf20Sopenharmony_ci dev_err(dev, "Failed to allocate state data\n"); 2838c2ecf20Sopenharmony_ci return -ENOMEM; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci drvdata->nr_states = config->nr_states; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci drvdata->desc.owner = THIS_MODULE; 2888c2ecf20Sopenharmony_ci drvdata->desc.enable_time = config->startup_delay; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* handle regulator type*/ 2918c2ecf20Sopenharmony_ci switch (config->type) { 2928c2ecf20Sopenharmony_ci case REGULATOR_VOLTAGE: 2938c2ecf20Sopenharmony_ci drvdata->desc.type = REGULATOR_VOLTAGE; 2948c2ecf20Sopenharmony_ci drvdata->desc.ops = &gpio_regulator_voltage_ops; 2958c2ecf20Sopenharmony_ci drvdata->desc.n_voltages = config->nr_states; 2968c2ecf20Sopenharmony_ci break; 2978c2ecf20Sopenharmony_ci case REGULATOR_CURRENT: 2988c2ecf20Sopenharmony_ci drvdata->desc.type = REGULATOR_CURRENT; 2998c2ecf20Sopenharmony_ci drvdata->desc.ops = &gpio_regulator_current_ops; 3008c2ecf20Sopenharmony_ci break; 3018c2ecf20Sopenharmony_ci default: 3028c2ecf20Sopenharmony_ci dev_err(dev, "No regulator type set\n"); 3038c2ecf20Sopenharmony_ci return -EINVAL; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci /* build initial state from gpio init data. */ 3078c2ecf20Sopenharmony_ci state = 0; 3088c2ecf20Sopenharmony_ci for (ptr = 0; ptr < drvdata->nr_gpios; ptr++) { 3098c2ecf20Sopenharmony_ci if (config->gflags[ptr] == GPIOD_OUT_HIGH) 3108c2ecf20Sopenharmony_ci state |= (1 << ptr); 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci drvdata->state = state; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci cfg.dev = dev; 3158c2ecf20Sopenharmony_ci cfg.init_data = config->init_data; 3168c2ecf20Sopenharmony_ci cfg.driver_data = drvdata; 3178c2ecf20Sopenharmony_ci cfg.of_node = np; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci /* 3208c2ecf20Sopenharmony_ci * The signal will be inverted by the GPIO core if flagged so in the 3218c2ecf20Sopenharmony_ci * descriptor. 3228c2ecf20Sopenharmony_ci */ 3238c2ecf20Sopenharmony_ci if (config->enabled_at_boot) 3248c2ecf20Sopenharmony_ci gflags = GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE; 3258c2ecf20Sopenharmony_ci else 3268c2ecf20Sopenharmony_ci gflags = GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci cfg.ena_gpiod = gpiod_get_optional(dev, "enable", gflags); 3298c2ecf20Sopenharmony_ci if (IS_ERR(cfg.ena_gpiod)) 3308c2ecf20Sopenharmony_ci return PTR_ERR(cfg.ena_gpiod); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci rdev = devm_regulator_register(dev, &drvdata->desc, &cfg); 3338c2ecf20Sopenharmony_ci if (IS_ERR(rdev)) { 3348c2ecf20Sopenharmony_ci ret = PTR_ERR(rdev); 3358c2ecf20Sopenharmony_ci dev_err(dev, "Failed to register regulator: %d\n", ret); 3368c2ecf20Sopenharmony_ci return ret; 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, drvdata); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci return 0; 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci#if defined(CONFIG_OF) 3458c2ecf20Sopenharmony_cistatic const struct of_device_id regulator_gpio_of_match[] = { 3468c2ecf20Sopenharmony_ci { .compatible = "regulator-gpio", }, 3478c2ecf20Sopenharmony_ci {}, 3488c2ecf20Sopenharmony_ci}; 3498c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, regulator_gpio_of_match); 3508c2ecf20Sopenharmony_ci#endif 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic struct platform_driver gpio_regulator_driver = { 3538c2ecf20Sopenharmony_ci .probe = gpio_regulator_probe, 3548c2ecf20Sopenharmony_ci .driver = { 3558c2ecf20Sopenharmony_ci .name = "gpio-regulator", 3568c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(regulator_gpio_of_match), 3578c2ecf20Sopenharmony_ci }, 3588c2ecf20Sopenharmony_ci}; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_cistatic int __init gpio_regulator_init(void) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci return platform_driver_register(&gpio_regulator_driver); 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_cisubsys_initcall(gpio_regulator_init); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic void __exit gpio_regulator_exit(void) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci platform_driver_unregister(&gpio_regulator_driver); 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_cimodule_exit(gpio_regulator_exit); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ciMODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>"); 3738c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("gpio voltage regulator"); 3748c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 3758c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:gpio-regulator"); 376