1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2022-2023, STMicroelectronics
4 */
5
6 #include <compiler.h>
7 #include <drivers/gpio.h>
8 #include <drivers/regulator.h>
9 #include <dt-bindings/gpio/gpio.h>
10 #include <kernel/delay.h>
11 #include <kernel/dt_driver.h>
12 #include <libfdt.h>
13 #include <tee_api_types.h>
14 #include <trace.h>
15
16 static_assert(GPIO_LEVEL_HIGH == 1 && GPIO_LEVEL_LOW == 0);
17
18 /*
19 * struct regulator_gpio - GPIO controlled regulator
20 * @regulator: Preallocated regulator instance
21 * @enable_gpio: GPIO for the enable state of the regulator or NULL if always on
22 * @enable_delay: Time (in microsecond) for the regulator to get enabled
23 * @off_on_delay: Min time (in microsecond) between enable and disable request
24 * @off_on_us: Timestamp of the last disable request
25 */
26 struct regulator_fixed {
27 struct regulator regulator;
28 struct gpio *enable_gpio;
29 unsigned int enable_delay;
30 unsigned int off_on_delay;
31 uint64_t off_on_us;
32 };
33
regulator_priv(struct regulator * regulator)34 static struct regulator_fixed *regulator_priv(struct regulator *regulator)
35 {
36 return container_of(regulator, struct regulator_fixed, regulator);
37 }
38
fixed_set_state(struct regulator * regulator,bool enabled)39 static TEE_Result fixed_set_state(struct regulator *regulator, bool enabled)
40 {
41 struct regulator_fixed *regu = regulator_priv(regulator);
42
43 if (regu->enable_gpio) {
44 if (enabled) {
45 while (!timeout_elapsed(regu->off_on_us))
46 udelay(1);
47 gpio_set_value(regu->enable_gpio, GPIO_LEVEL_HIGH);
48 udelay(regu->enable_delay);
49 } else {
50 regu->off_on_us = timeout_init_us(regu->off_on_delay);
51 gpio_set_value(regu->enable_gpio, GPIO_LEVEL_LOW);
52 }
53 }
54
55 return TEE_SUCCESS;
56 }
57
fixed_get_state(struct regulator * regulator,bool * enabled)58 static TEE_Result fixed_get_state(struct regulator *regulator, bool *enabled)
59 {
60 struct regulator_fixed *regu = regulator_priv(regulator);
61
62 if (regu->enable_gpio)
63 *enabled = gpio_get_value(regu->enable_gpio);
64 else
65 *enabled = true;
66
67 return TEE_SUCCESS;
68 }
69
70 static const struct regulator_ops fixed_regulator_ops = {
71 .set_state = fixed_set_state,
72 .get_state = fixed_get_state,
73 };
74
get_enable_gpio(const void * fdt,int node,struct regulator_fixed * regu)75 static TEE_Result get_enable_gpio(const void *fdt, int node,
76 struct regulator_fixed *regu)
77 {
78 TEE_Result res = TEE_ERROR_GENERIC;
79 const fdt32_t *cuint = NULL;
80 struct gpio *gpio = NULL;
81
82 res = gpio_dt_get_by_index(fdt, node, 0, NULL, &gpio);
83 if (res == TEE_ERROR_ITEM_NOT_FOUND) {
84 regu->enable_gpio = NULL;
85
86 return TEE_SUCCESS;
87 }
88 if (res)
89 return res;
90
91 /* Override active level phandle flag, as per DT bindings */
92 if (dt_have_prop(fdt, node, "enable-active-high"))
93 gpio->dt_flags &= ~GPIO_ACTIVE_LOW;
94 else
95 gpio->dt_flags |= GPIO_ACTIVE_LOW;
96
97 /* Override open drain/open source phandle flag, as per DT bindings */
98 if (dt_have_prop(fdt, node, "gpio-open-drain"))
99 gpio->dt_flags |= GPIO_LINE_OPEN_DRAIN;
100 else
101 gpio->dt_flags &= ~GPIO_LINE_OPEN_DRAIN;
102
103 cuint = fdt_getprop(fdt, node, "startup-delay-us", NULL);
104 if (cuint)
105 regu->enable_delay = fdt32_to_cpu(*cuint);
106
107 cuint = fdt_getprop(fdt, node, "off-on-delay-us", NULL);
108 if (cuint)
109 regu->off_on_delay = fdt32_to_cpu(*cuint);
110
111 /* Low level initialisation with updated dt_flags */
112 res = gpio_configure(gpio, GPIO_ASIS);
113 if (res)
114 return res;
115
116 /* Configure output, don't change level */
117 gpio_set_direction(gpio, GPIO_DIR_OUT);
118
119 regu->enable_gpio = gpio;
120
121 return TEE_SUCCESS;
122 }
123
fixed_regulator_probe(const void * fdt,int node,const void * compat_data __unused)124 static TEE_Result fixed_regulator_probe(const void *fdt, int node,
125 const void *compat_data __unused)
126 {
127 struct regulator_fixed *regu = NULL;
128 TEE_Result res = TEE_ERROR_GENERIC;
129 struct regu_dt_desc desc = { };
130 const char *supply_name = NULL;
131 const char *type = NULL;
132 char *regu_name = NULL;
133
134 regu_name = (char *)fdt_get_name(fdt, node, NULL);
135
136 type = fdt_getprop(fdt, node, "regulator-type", NULL);
137 if (type && strcmp(type, "voltage")) {
138 EMSG("Regulator gpio node %s: type %s not supported",
139 regu_name, type);
140 return TEE_ERROR_GENERIC;
141 }
142
143 regu = calloc(1, sizeof(*regu));
144 if (!regu)
145 return TEE_ERROR_OUT_OF_MEMORY;
146
147 res = get_enable_gpio(fdt, node, regu);
148 if (res)
149 goto err;
150
151 if (fdt_getprop(fdt, node, "vin-supply", NULL))
152 supply_name = "vin";
153
154 desc = (struct regu_dt_desc){
155 .name = regu_name,
156 .ops = &fixed_regulator_ops,
157 .supply_name = supply_name,
158 .regulator = ®u->regulator,
159 };
160
161 res = regulator_dt_register(fdt, node, node, &desc);
162 if (res) {
163 EMSG("Can't register regulator %s: %#"PRIx32, regu_name, res);
164 goto err;
165 }
166
167 return TEE_SUCCESS;
168
169 err:
170 free(regu);
171
172 return res;
173 }
174
175 static const struct dt_device_match regulator_match_table[] = {
176 { .compatible = "regulator-fixed" },
177 { }
178 };
179
180 DEFINE_DT_DRIVER(fixed_regulator_dt_driver) = {
181 .name = "regulator-fixed",
182 .match_table = regulator_match_table,
183 .probe = fixed_regulator_probe,
184 };
185