xref: /optee_os/core/drivers/regulator/regulator_fixed.c (revision 39d1e320ec639a05e1c04b4fe1729904a0399f2b)
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 = &regu->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