xref: /openbmc/u-boot/drivers/gpio/gpio-uclass.c (revision b3f4ca11)
1 /*
2  * Copyright (c) 2013 Google, Inc
3  *
4  * SPDX-License-Identifier:	GPL-2.0+
5  */
6 
7 #include <common.h>
8 #include <dm.h>
9 #include <errno.h>
10 #include <asm/gpio.h>
11 #include <linux/ctype.h>
12 
13 /**
14  * gpio_to_device() - Convert global GPIO number to device, number
15  * gpio:	The numeric representation of the GPIO
16  *
17  * Convert the GPIO number to an entry in the list of GPIOs
18  * or GPIO blocks registered with the GPIO controller. Returns
19  * entry on success, NULL on error.
20  */
21 static int gpio_to_device(unsigned int gpio, struct udevice **devp,
22 			  unsigned int *offset)
23 {
24 	struct gpio_dev_priv *uc_priv;
25 	struct udevice *dev;
26 	int ret;
27 
28 	for (ret = uclass_first_device(UCLASS_GPIO, &dev);
29 	     dev;
30 	     ret = uclass_next_device(&dev)) {
31 		uc_priv = dev->uclass_priv;
32 		if (gpio >= uc_priv->gpio_base &&
33 		    gpio < uc_priv->gpio_base + uc_priv->gpio_count) {
34 			*devp = dev;
35 			*offset = gpio - uc_priv->gpio_base;
36 			return 0;
37 		}
38 	}
39 
40 	/* No such GPIO */
41 	return ret ? ret : -EINVAL;
42 }
43 
44 int gpio_lookup_name(const char *name, struct udevice **devp,
45 		     unsigned int *offsetp, unsigned int *gpiop)
46 {
47 	struct gpio_dev_priv *uc_priv = NULL;
48 	struct udevice *dev;
49 	ulong offset;
50 	int numeric;
51 	int ret;
52 
53 	if (devp)
54 		*devp = NULL;
55 	numeric = isdigit(*name) ? simple_strtoul(name, NULL, 10) : -1;
56 	for (ret = uclass_first_device(UCLASS_GPIO, &dev);
57 	     dev;
58 	     ret = uclass_next_device(&dev)) {
59 		int len;
60 
61 		uc_priv = dev->uclass_priv;
62 		if (numeric != -1) {
63 			offset = numeric - uc_priv->gpio_base;
64 			/* Allow GPIOs to be numbered from 0 */
65 			if (offset >= 0 && offset < uc_priv->gpio_count)
66 				break;
67 		}
68 
69 		len = uc_priv->bank_name ? strlen(uc_priv->bank_name) : 0;
70 
71 		if (!strncasecmp(name, uc_priv->bank_name, len)) {
72 			if (!strict_strtoul(name + len, 10, &offset))
73 				break;
74 		}
75 	}
76 
77 	if (!dev)
78 		return ret ? ret : -EINVAL;
79 
80 	if (devp)
81 		*devp = dev;
82 	if (offsetp)
83 		*offsetp = offset;
84 	if (gpiop)
85 		*gpiop = uc_priv->gpio_base + offset;
86 
87 	return 0;
88 }
89 
90 /**
91  * gpio_request() - [COMPAT] Request GPIO
92  * gpio:	GPIO number
93  * label:	Name for the requested GPIO
94  *
95  * This function implements the API that's compatible with current
96  * GPIO API used in U-Boot. The request is forwarded to particular
97  * GPIO driver. Returns 0 on success, negative value on error.
98  */
99 int gpio_request(unsigned gpio, const char *label)
100 {
101 	unsigned int offset;
102 	struct udevice *dev;
103 	int ret;
104 
105 	ret = gpio_to_device(gpio, &dev, &offset);
106 	if (ret)
107 		return ret;
108 
109 	if (!gpio_get_ops(dev)->request)
110 		return 0;
111 
112 	return gpio_get_ops(dev)->request(dev, offset, label);
113 }
114 
115 /**
116  * gpio_free() - [COMPAT] Relinquish GPIO
117  * gpio:	GPIO number
118  *
119  * This function implements the API that's compatible with current
120  * GPIO API used in U-Boot. The request is forwarded to particular
121  * GPIO driver. Returns 0 on success, negative value on error.
122  */
123 int gpio_free(unsigned gpio)
124 {
125 	unsigned int offset;
126 	struct udevice *dev;
127 	int ret;
128 
129 	ret = gpio_to_device(gpio, &dev, &offset);
130 	if (ret)
131 		return ret;
132 
133 	if (!gpio_get_ops(dev)->free)
134 		return 0;
135 	return gpio_get_ops(dev)->free(dev, offset);
136 }
137 
138 /**
139  * gpio_direction_input() - [COMPAT] Set GPIO direction to input
140  * gpio:	GPIO number
141  *
142  * This function implements the API that's compatible with current
143  * GPIO API used in U-Boot. The request is forwarded to particular
144  * GPIO driver. Returns 0 on success, negative value on error.
145  */
146 int gpio_direction_input(unsigned gpio)
147 {
148 	unsigned int offset;
149 	struct udevice *dev;
150 	int ret;
151 
152 	ret = gpio_to_device(gpio, &dev, &offset);
153 	if (ret)
154 		return ret;
155 
156 	return gpio_get_ops(dev)->direction_input(dev, offset);
157 }
158 
159 /**
160  * gpio_direction_output() - [COMPAT] Set GPIO direction to output and set value
161  * gpio:	GPIO number
162  * value:	Logical value to be set on the GPIO pin
163  *
164  * This function implements the API that's compatible with current
165  * GPIO API used in U-Boot. The request is forwarded to particular
166  * GPIO driver. Returns 0 on success, negative value on error.
167  */
168 int gpio_direction_output(unsigned gpio, int value)
169 {
170 	unsigned int offset;
171 	struct udevice *dev;
172 	int ret;
173 
174 	ret = gpio_to_device(gpio, &dev, &offset);
175 	if (ret)
176 		return ret;
177 
178 	return gpio_get_ops(dev)->direction_output(dev, offset, value);
179 }
180 
181 /**
182  * gpio_get_value() - [COMPAT] Sample GPIO pin and return it's value
183  * gpio:	GPIO number
184  *
185  * This function implements the API that's compatible with current
186  * GPIO API used in U-Boot. The request is forwarded to particular
187  * GPIO driver. Returns the value of the GPIO pin, or negative value
188  * on error.
189  */
190 int gpio_get_value(unsigned gpio)
191 {
192 	unsigned int offset;
193 	struct udevice *dev;
194 	int ret;
195 
196 	ret = gpio_to_device(gpio, &dev, &offset);
197 	if (ret)
198 		return ret;
199 
200 	return gpio_get_ops(dev)->get_value(dev, offset);
201 }
202 
203 /**
204  * gpio_set_value() - [COMPAT] Configure logical value on GPIO pin
205  * gpio:	GPIO number
206  * value:	Logical value to be set on the GPIO pin.
207  *
208  * This function implements the API that's compatible with current
209  * GPIO API used in U-Boot. The request is forwarded to particular
210  * GPIO driver. Returns 0 on success, negative value on error.
211  */
212 int gpio_set_value(unsigned gpio, int value)
213 {
214 	unsigned int offset;
215 	struct udevice *dev;
216 	int ret;
217 
218 	ret = gpio_to_device(gpio, &dev, &offset);
219 	if (ret)
220 		return ret;
221 
222 	return gpio_get_ops(dev)->set_value(dev, offset, value);
223 }
224 
225 const char *gpio_get_bank_info(struct udevice *dev, int *bit_count)
226 {
227 	struct gpio_dev_priv *priv;
228 
229 	/* Must be called on an active device */
230 	priv = dev->uclass_priv;
231 	assert(priv);
232 
233 	*bit_count = priv->gpio_count;
234 	return priv->bank_name;
235 }
236 
237 /* We need to renumber the GPIOs when any driver is probed/removed */
238 static int gpio_renumber(void)
239 {
240 	struct gpio_dev_priv *uc_priv;
241 	struct udevice *dev;
242 	struct uclass *uc;
243 	unsigned base;
244 	int ret;
245 
246 	ret = uclass_get(UCLASS_GPIO, &uc);
247 	if (ret)
248 		return ret;
249 
250 	/* Ensure that we have a base for each bank */
251 	base = 0;
252 	uclass_foreach_dev(dev, uc) {
253 		if (device_active(dev)) {
254 			uc_priv = dev->uclass_priv;
255 			uc_priv->gpio_base = base;
256 			base += uc_priv->gpio_count;
257 		}
258 	}
259 
260 	return 0;
261 }
262 
263 static int gpio_post_probe(struct udevice *dev)
264 {
265 	return gpio_renumber();
266 }
267 
268 static int gpio_pre_remove(struct udevice *dev)
269 {
270 	return gpio_renumber();
271 }
272 
273 UCLASS_DRIVER(gpio) = {
274 	.id		= UCLASS_GPIO,
275 	.name		= "gpio",
276 	.post_probe	= gpio_post_probe,
277 	.pre_remove	= gpio_pre_remove,
278 	.per_device_auto_alloc_size = sizeof(struct gpio_dev_priv),
279 };
280