blob: f1bbc587961709dec3922c52c76585227acecd9b [file] [log] [blame]
Simon Glasse821d182014-02-26 15:59:24 -07001/*
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
12/**
13 * gpio_to_device() - Convert global GPIO number to device, number
14 * gpio: The numeric representation of the GPIO
15 *
16 * Convert the GPIO number to an entry in the list of GPIOs
17 * or GPIO blocks registered with the GPIO controller. Returns
18 * entry on success, NULL on error.
19 */
Heiko Schocherb74fcb42014-05-22 12:43:05 +020020static int gpio_to_device(unsigned int gpio, struct udevice **devp,
Simon Glasse821d182014-02-26 15:59:24 -070021 unsigned int *offset)
22{
23 struct gpio_dev_priv *uc_priv;
Heiko Schocherb74fcb42014-05-22 12:43:05 +020024 struct udevice *dev;
Simon Glasse821d182014-02-26 15:59:24 -070025 int ret;
26
27 for (ret = uclass_first_device(UCLASS_GPIO, &dev);
28 dev;
29 ret = uclass_next_device(&dev)) {
30 uc_priv = dev->uclass_priv;
31 if (gpio >= uc_priv->gpio_base &&
32 gpio < uc_priv->gpio_base + uc_priv->gpio_count) {
33 *devp = dev;
34 *offset = gpio - uc_priv->gpio_base;
35 return 0;
36 }
37 }
38
39 /* No such GPIO */
40 return ret ? ret : -EINVAL;
41}
42
Heiko Schocherb74fcb42014-05-22 12:43:05 +020043int gpio_lookup_name(const char *name, struct udevice **devp,
Simon Glasse821d182014-02-26 15:59:24 -070044 unsigned int *offsetp, unsigned int *gpiop)
45{
46 struct gpio_dev_priv *uc_priv;
Heiko Schocherb74fcb42014-05-22 12:43:05 +020047 struct udevice *dev;
Simon Glasse821d182014-02-26 15:59:24 -070048 int ret;
49
50 if (devp)
51 *devp = NULL;
52 for (ret = uclass_first_device(UCLASS_GPIO, &dev);
53 dev;
54 ret = uclass_next_device(&dev)) {
55 ulong offset;
56 int len;
57
58 uc_priv = dev->uclass_priv;
59 len = uc_priv->bank_name ? strlen(uc_priv->bank_name) : 0;
60
Simon Glassd4acf632014-06-11 23:29:47 -060061 if (!strncasecmp(name, uc_priv->bank_name, len)) {
Simon Glasse821d182014-02-26 15:59:24 -070062 if (strict_strtoul(name + len, 10, &offset))
63 continue;
64 if (devp)
65 *devp = dev;
66 if (offsetp)
67 *offsetp = offset;
68 if (gpiop)
69 *gpiop = uc_priv->gpio_base + offset;
70 return 0;
71 }
72 }
73
74 return ret ? ret : -EINVAL;
75}
76
77/**
78 * gpio_request() - [COMPAT] Request GPIO
79 * gpio: GPIO number
80 * label: Name for the requested GPIO
81 *
82 * This function implements the API that's compatible with current
83 * GPIO API used in U-Boot. The request is forwarded to particular
84 * GPIO driver. Returns 0 on success, negative value on error.
85 */
86int gpio_request(unsigned gpio, const char *label)
87{
88 unsigned int offset;
Heiko Schocherb74fcb42014-05-22 12:43:05 +020089 struct udevice *dev;
Simon Glasse821d182014-02-26 15:59:24 -070090 int ret;
91
92 ret = gpio_to_device(gpio, &dev, &offset);
93 if (ret)
94 return ret;
95
96 if (!gpio_get_ops(dev)->request)
97 return 0;
98
99 return gpio_get_ops(dev)->request(dev, offset, label);
100}
101
102/**
103 * gpio_free() - [COMPAT] Relinquish GPIO
104 * gpio: GPIO number
105 *
106 * This function implements the API that's compatible with current
107 * GPIO API used in U-Boot. The request is forwarded to particular
108 * GPIO driver. Returns 0 on success, negative value on error.
109 */
110int gpio_free(unsigned gpio)
111{
112 unsigned int offset;
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200113 struct udevice *dev;
Simon Glasse821d182014-02-26 15:59:24 -0700114 int ret;
115
116 ret = gpio_to_device(gpio, &dev, &offset);
117 if (ret)
118 return ret;
119
120 if (!gpio_get_ops(dev)->free)
121 return 0;
122 return gpio_get_ops(dev)->free(dev, offset);
123}
124
125/**
126 * gpio_direction_input() - [COMPAT] Set GPIO direction to input
127 * gpio: GPIO number
128 *
129 * This function implements the API that's compatible with current
130 * GPIO API used in U-Boot. The request is forwarded to particular
131 * GPIO driver. Returns 0 on success, negative value on error.
132 */
133int gpio_direction_input(unsigned gpio)
134{
135 unsigned int offset;
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200136 struct udevice *dev;
Simon Glasse821d182014-02-26 15:59:24 -0700137 int ret;
138
139 ret = gpio_to_device(gpio, &dev, &offset);
140 if (ret)
141 return ret;
142
143 return gpio_get_ops(dev)->direction_input(dev, offset);
144}
145
146/**
147 * gpio_direction_output() - [COMPAT] Set GPIO direction to output and set value
148 * gpio: GPIO number
149 * value: Logical value to be set on the GPIO pin
150 *
151 * This function implements the API that's compatible with current
152 * GPIO API used in U-Boot. The request is forwarded to particular
153 * GPIO driver. Returns 0 on success, negative value on error.
154 */
155int gpio_direction_output(unsigned gpio, int value)
156{
157 unsigned int offset;
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200158 struct udevice *dev;
Simon Glasse821d182014-02-26 15:59:24 -0700159 int ret;
160
161 ret = gpio_to_device(gpio, &dev, &offset);
162 if (ret)
163 return ret;
164
165 return gpio_get_ops(dev)->direction_output(dev, offset, value);
166}
167
168/**
169 * gpio_get_value() - [COMPAT] Sample GPIO pin and return it's value
170 * gpio: GPIO number
171 *
172 * This function implements the API that's compatible with current
173 * GPIO API used in U-Boot. The request is forwarded to particular
174 * GPIO driver. Returns the value of the GPIO pin, or negative value
175 * on error.
176 */
177int gpio_get_value(unsigned gpio)
178{
179 unsigned int offset;
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200180 struct udevice *dev;
Simon Glasse821d182014-02-26 15:59:24 -0700181 int ret;
182
183 ret = gpio_to_device(gpio, &dev, &offset);
184 if (ret)
185 return ret;
186
187 return gpio_get_ops(dev)->get_value(dev, offset);
188}
189
190/**
191 * gpio_set_value() - [COMPAT] Configure logical value on GPIO pin
192 * gpio: GPIO number
193 * value: Logical value to be set on the GPIO pin.
194 *
195 * This function implements the API that's compatible with current
196 * GPIO API used in U-Boot. The request is forwarded to particular
197 * GPIO driver. Returns 0 on success, negative value on error.
198 */
199int gpio_set_value(unsigned gpio, int value)
200{
201 unsigned int offset;
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200202 struct udevice *dev;
Simon Glasse821d182014-02-26 15:59:24 -0700203 int ret;
204
205 ret = gpio_to_device(gpio, &dev, &offset);
206 if (ret)
207 return ret;
208
209 return gpio_get_ops(dev)->set_value(dev, offset, value);
210}
211
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200212const char *gpio_get_bank_info(struct udevice *dev, int *bit_count)
Simon Glasse821d182014-02-26 15:59:24 -0700213{
214 struct gpio_dev_priv *priv;
215
216 /* Must be called on an active device */
217 priv = dev->uclass_priv;
218 assert(priv);
219
220 *bit_count = priv->gpio_count;
221 return priv->bank_name;
222}
223
224/* We need to renumber the GPIOs when any driver is probed/removed */
225static int gpio_renumber(void)
226{
227 struct gpio_dev_priv *uc_priv;
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200228 struct udevice *dev;
Simon Glasse821d182014-02-26 15:59:24 -0700229 struct uclass *uc;
230 unsigned base;
231 int ret;
232
233 ret = uclass_get(UCLASS_GPIO, &uc);
234 if (ret)
235 return ret;
236
237 /* Ensure that we have a base for each bank */
238 base = 0;
239 uclass_foreach_dev(dev, uc) {
240 if (device_active(dev)) {
241 uc_priv = dev->uclass_priv;
242 uc_priv->gpio_base = base;
243 base += uc_priv->gpio_count;
244 }
245 }
246
247 return 0;
248}
249
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200250static int gpio_post_probe(struct udevice *dev)
Simon Glasse821d182014-02-26 15:59:24 -0700251{
252 return gpio_renumber();
253}
254
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200255static int gpio_pre_remove(struct udevice *dev)
Simon Glasse821d182014-02-26 15:59:24 -0700256{
257 return gpio_renumber();
258}
259
260UCLASS_DRIVER(gpio) = {
261 .id = UCLASS_GPIO,
262 .name = "gpio",
263 .post_probe = gpio_post_probe,
264 .pre_remove = gpio_pre_remove,
265 .per_device_auto_alloc_size = sizeof(struct gpio_dev_priv),
266};