1477dfe2fSKeerthy /*
2477dfe2fSKeerthy * (C) Copyright 2016 Texas Instruments Incorporated, <www.ti.com>
3477dfe2fSKeerthy * Keerthy <j-keerthy@ti.com>
4477dfe2fSKeerthy *
5477dfe2fSKeerthy * SPDX-License-Identifier: GPL-2.0+
6477dfe2fSKeerthy */
7477dfe2fSKeerthy
8477dfe2fSKeerthy #include <common.h>
9477dfe2fSKeerthy #include <fdtdec.h>
10477dfe2fSKeerthy #include <errno.h>
11477dfe2fSKeerthy #include <dm.h>
12477dfe2fSKeerthy #include <i2c.h>
13477dfe2fSKeerthy #include <asm/gpio.h>
14477dfe2fSKeerthy #include <power/pmic.h>
15477dfe2fSKeerthy #include <power/regulator.h>
16477dfe2fSKeerthy
17477dfe2fSKeerthy #define GPIO_REGULATOR_MAX_STATES 2
18477dfe2fSKeerthy
19477dfe2fSKeerthy DECLARE_GLOBAL_DATA_PTR;
20477dfe2fSKeerthy
21477dfe2fSKeerthy struct gpio_regulator_platdata {
22477dfe2fSKeerthy struct gpio_desc gpio; /* GPIO for regulator voltage control */
23477dfe2fSKeerthy int states[GPIO_REGULATOR_MAX_STATES];
24477dfe2fSKeerthy int voltages[GPIO_REGULATOR_MAX_STATES];
25477dfe2fSKeerthy };
26477dfe2fSKeerthy
gpio_regulator_ofdata_to_platdata(struct udevice * dev)27477dfe2fSKeerthy static int gpio_regulator_ofdata_to_platdata(struct udevice *dev)
28477dfe2fSKeerthy {
29477dfe2fSKeerthy struct dm_regulator_uclass_platdata *uc_pdata;
30477dfe2fSKeerthy struct gpio_regulator_platdata *dev_pdata;
31477dfe2fSKeerthy struct gpio_desc *gpio;
32*fae486e4SShawn Lin int ret, len, i, j;
33477dfe2fSKeerthy u32 states_array[8];
34477dfe2fSKeerthy
35477dfe2fSKeerthy dev_pdata = dev_get_platdata(dev);
36477dfe2fSKeerthy uc_pdata = dev_get_uclass_platdata(dev);
37477dfe2fSKeerthy if (!uc_pdata)
38477dfe2fSKeerthy return -ENXIO;
39477dfe2fSKeerthy
40477dfe2fSKeerthy /* Set type to gpio */
41477dfe2fSKeerthy uc_pdata->type = REGULATOR_TYPE_GPIO;
42477dfe2fSKeerthy
43477dfe2fSKeerthy /*
44477dfe2fSKeerthy * Get gpio regulator gpio desc
45477dfe2fSKeerthy * Assuming one GPIO per regulator.
46477dfe2fSKeerthy * Can be extended later to multiple GPIOs
47477dfe2fSKeerthy * per gpio-regulator. As of now no instance with multiple
48477dfe2fSKeerthy * gpios is presnt
49477dfe2fSKeerthy */
50477dfe2fSKeerthy gpio = &dev_pdata->gpio;
51477dfe2fSKeerthy ret = gpio_request_by_name(dev, "gpios", 0, gpio, GPIOD_IS_OUT);
52477dfe2fSKeerthy if (ret)
53477dfe2fSKeerthy debug("regulator gpio - not found! Error: %d", ret);
54477dfe2fSKeerthy
55*fae486e4SShawn Lin len = dev_read_size(dev, "states");
56*fae486e4SShawn Lin if (len < 0)
57*fae486e4SShawn Lin return len;
58477dfe2fSKeerthy
59*fae486e4SShawn Lin len /= sizeof(fdt32_t);
60*fae486e4SShawn Lin
61*fae486e4SShawn Lin ret = dev_read_u32_array(dev, "states", states_array, len);
62cd282fabSShawn Lin if (ret)
63cd282fabSShawn Lin return -EINVAL;
64cd282fabSShawn Lin
65*fae486e4SShawn Lin for (i = 0, j = 0; i < len; i += 2) {
66477dfe2fSKeerthy dev_pdata->voltages[j] = states_array[i];
67477dfe2fSKeerthy dev_pdata->states[j] = states_array[i + 1];
68477dfe2fSKeerthy j++;
69477dfe2fSKeerthy }
70477dfe2fSKeerthy
71477dfe2fSKeerthy return 0;
72477dfe2fSKeerthy }
73477dfe2fSKeerthy
gpio_regulator_get_value(struct udevice * dev)74477dfe2fSKeerthy static int gpio_regulator_get_value(struct udevice *dev)
75477dfe2fSKeerthy {
76477dfe2fSKeerthy struct dm_regulator_uclass_platdata *uc_pdata;
77477dfe2fSKeerthy struct gpio_regulator_platdata *dev_pdata = dev_get_platdata(dev);
78477dfe2fSKeerthy int enable;
79477dfe2fSKeerthy
80477dfe2fSKeerthy if (!dev_pdata->gpio.dev)
81477dfe2fSKeerthy return -ENOSYS;
82477dfe2fSKeerthy
83477dfe2fSKeerthy uc_pdata = dev_get_uclass_platdata(dev);
84477dfe2fSKeerthy if (uc_pdata->min_uV > uc_pdata->max_uV) {
85477dfe2fSKeerthy debug("Invalid constraints for: %s\n", uc_pdata->name);
86477dfe2fSKeerthy return -EINVAL;
87477dfe2fSKeerthy }
88477dfe2fSKeerthy
89477dfe2fSKeerthy enable = dm_gpio_get_value(&dev_pdata->gpio);
90477dfe2fSKeerthy if (enable == dev_pdata->states[0])
91477dfe2fSKeerthy return dev_pdata->voltages[0];
92477dfe2fSKeerthy else
93477dfe2fSKeerthy return dev_pdata->voltages[1];
94477dfe2fSKeerthy }
95477dfe2fSKeerthy
gpio_regulator_set_value(struct udevice * dev,int uV)96477dfe2fSKeerthy static int gpio_regulator_set_value(struct udevice *dev, int uV)
97477dfe2fSKeerthy {
98477dfe2fSKeerthy struct gpio_regulator_platdata *dev_pdata = dev_get_platdata(dev);
99477dfe2fSKeerthy int ret;
100477dfe2fSKeerthy bool enable;
101477dfe2fSKeerthy
102477dfe2fSKeerthy if (!dev_pdata->gpio.dev)
103477dfe2fSKeerthy return -ENOSYS;
104477dfe2fSKeerthy
105477dfe2fSKeerthy if (uV == dev_pdata->voltages[0])
106477dfe2fSKeerthy enable = dev_pdata->states[0];
107477dfe2fSKeerthy else if (uV == dev_pdata->voltages[1])
108477dfe2fSKeerthy enable = dev_pdata->states[1];
109477dfe2fSKeerthy else
110477dfe2fSKeerthy return -EINVAL;
111477dfe2fSKeerthy
112477dfe2fSKeerthy ret = dm_gpio_set_value(&dev_pdata->gpio, enable);
113477dfe2fSKeerthy if (ret) {
11490aa625cSMasahiro Yamada pr_err("Can't set regulator : %s gpio to: %d\n", dev->name,
115477dfe2fSKeerthy enable);
116477dfe2fSKeerthy return ret;
117477dfe2fSKeerthy }
118477dfe2fSKeerthy
119477dfe2fSKeerthy return 0;
120477dfe2fSKeerthy }
121477dfe2fSKeerthy
122477dfe2fSKeerthy static const struct dm_regulator_ops gpio_regulator_ops = {
123477dfe2fSKeerthy .get_value = gpio_regulator_get_value,
124477dfe2fSKeerthy .set_value = gpio_regulator_set_value,
125477dfe2fSKeerthy };
126477dfe2fSKeerthy
127477dfe2fSKeerthy static const struct udevice_id gpio_regulator_ids[] = {
128477dfe2fSKeerthy { .compatible = "regulator-gpio" },
129477dfe2fSKeerthy { },
130477dfe2fSKeerthy };
131477dfe2fSKeerthy
132477dfe2fSKeerthy U_BOOT_DRIVER(gpio_regulator) = {
133477dfe2fSKeerthy .name = "gpio regulator",
134477dfe2fSKeerthy .id = UCLASS_REGULATOR,
135477dfe2fSKeerthy .ops = &gpio_regulator_ops,
136477dfe2fSKeerthy .of_match = gpio_regulator_ids,
137477dfe2fSKeerthy .ofdata_to_platdata = gpio_regulator_ofdata_to_platdata,
138477dfe2fSKeerthy .platdata_auto_alloc_size = sizeof(struct gpio_regulator_platdata),
139477dfe2fSKeerthy };
140