]>
Commit | Line | Data |
---|---|---|
4e779ad2 MS |
1 | /* |
2 | * Copyright (c) 2013 Xilinx, Michal Simek | |
3 | * | |
1a459660 | 4 | * SPDX-License-Identifier: GPL-2.0+ |
4e779ad2 MS |
5 | */ |
6 | ||
7 | #include <common.h> | |
8 | #include <errno.h> | |
9 | #include <malloc.h> | |
10 | #include <linux/list.h> | |
11 | #include <asm/io.h> | |
12 | #include <asm/gpio.h> | |
13 | ||
14 | static LIST_HEAD(gpio_list); | |
15 | ||
16 | enum gpio_direction { | |
17 | GPIO_DIRECTION_OUT = 0, | |
18 | GPIO_DIRECTION_IN = 1, | |
19 | }; | |
20 | ||
21 | /* Gpio simple map */ | |
22 | struct gpio_regs { | |
23 | u32 gpiodata; | |
24 | u32 gpiodir; | |
25 | }; | |
26 | ||
27 | #define GPIO_NAME_SIZE 10 | |
28 | ||
29 | struct gpio_names { | |
30 | char name[GPIO_NAME_SIZE]; | |
31 | }; | |
32 | ||
33 | /* Initialized, rxbd_current, rx_first_buf must be 0 after init */ | |
34 | struct xilinx_gpio_priv { | |
35 | struct gpio_regs *regs; | |
36 | u32 gpio_min; | |
37 | u32 gpio_max; | |
38 | u32 gpiodata_store; | |
39 | char name[GPIO_NAME_SIZE]; | |
40 | struct list_head list; | |
41 | struct gpio_names *gpio_name; | |
42 | }; | |
43 | ||
44 | /* Store number of allocated gpio pins */ | |
45 | static u32 xilinx_gpio_max; | |
46 | ||
47 | /* Get associated gpio controller */ | |
48 | static struct xilinx_gpio_priv *gpio_get_controller(unsigned gpio) | |
49 | { | |
50 | struct list_head *entry; | |
51 | struct xilinx_gpio_priv *priv = NULL; | |
52 | ||
53 | list_for_each(entry, &gpio_list) { | |
54 | priv = list_entry(entry, struct xilinx_gpio_priv, list); | |
55 | if (gpio >= priv->gpio_min && gpio <= priv->gpio_max) { | |
56 | debug("%s: reg: %x, min-max: %d-%d\n", __func__, | |
57 | (u32)priv->regs, priv->gpio_min, priv->gpio_max); | |
58 | return priv; | |
59 | } | |
60 | } | |
61 | puts("!!!Can't get gpio controller!!!\n"); | |
62 | return NULL; | |
63 | } | |
64 | ||
65 | /* Get gpio pin name if used/setup */ | |
66 | static char *get_name(unsigned gpio) | |
67 | { | |
68 | u32 gpio_priv; | |
69 | struct xilinx_gpio_priv *priv; | |
70 | ||
71 | debug("%s\n", __func__); | |
72 | ||
73 | priv = gpio_get_controller(gpio); | |
74 | if (priv) { | |
75 | gpio_priv = gpio - priv->gpio_min; | |
76 | ||
77 | return *priv->gpio_name[gpio_priv].name ? | |
78 | priv->gpio_name[gpio_priv].name : "UNKNOWN"; | |
79 | } | |
80 | return "UNKNOWN"; | |
81 | } | |
82 | ||
83 | /* Get output value */ | |
84 | static int gpio_get_output_value(unsigned gpio) | |
85 | { | |
86 | u32 val, gpio_priv; | |
87 | struct xilinx_gpio_priv *priv = gpio_get_controller(gpio); | |
88 | ||
89 | if (priv) { | |
90 | gpio_priv = gpio - priv->gpio_min; | |
91 | val = !!(priv->gpiodata_store & (1 << gpio_priv)); | |
92 | debug("%s: reg: %x, gpio_no: %d, dir: %d\n", __func__, | |
93 | (u32)priv->regs, gpio_priv, val); | |
94 | ||
95 | return val; | |
96 | } | |
97 | return -1; | |
98 | } | |
99 | ||
100 | /* Get input value */ | |
101 | static int gpio_get_input_value(unsigned gpio) | |
102 | { | |
103 | u32 val, gpio_priv; | |
104 | struct gpio_regs *regs; | |
105 | struct xilinx_gpio_priv *priv = gpio_get_controller(gpio); | |
106 | ||
107 | if (priv) { | |
108 | regs = priv->regs; | |
109 | gpio_priv = gpio - priv->gpio_min; | |
110 | val = readl(®s->gpiodata); | |
111 | val = !!(val & (1 << gpio_priv)); | |
112 | debug("%s: reg: %x, gpio_no: %d, dir: %d\n", __func__, | |
113 | (u32)priv->regs, gpio_priv, val); | |
114 | ||
115 | return val; | |
116 | } | |
117 | return -1; | |
118 | } | |
119 | ||
120 | /* Set gpio direction */ | |
121 | static int gpio_set_direction(unsigned gpio, enum gpio_direction direction) | |
122 | { | |
123 | u32 val, gpio_priv; | |
124 | struct gpio_regs *regs; | |
125 | struct xilinx_gpio_priv *priv = gpio_get_controller(gpio); | |
126 | ||
127 | if (priv) { | |
128 | regs = priv->regs; | |
129 | val = readl(®s->gpiodir); | |
130 | ||
131 | gpio_priv = gpio - priv->gpio_min; | |
132 | if (direction == GPIO_DIRECTION_OUT) | |
133 | val &= ~(1 << gpio_priv); | |
134 | else | |
135 | val |= 1 << gpio_priv; | |
136 | ||
137 | writel(val, ®s->gpiodir); | |
138 | debug("%s: reg: %x, gpio_no: %d, dir: %d\n", __func__, | |
139 | (u32)priv->regs, gpio_priv, val); | |
140 | ||
141 | return 0; | |
142 | } | |
143 | ||
144 | return -1; | |
145 | } | |
146 | ||
147 | /* Get gpio direction */ | |
148 | static int gpio_get_direction(unsigned gpio) | |
149 | { | |
150 | u32 val, gpio_priv; | |
151 | struct gpio_regs *regs; | |
152 | struct xilinx_gpio_priv *priv = gpio_get_controller(gpio); | |
153 | ||
154 | if (priv) { | |
155 | regs = priv->regs; | |
156 | gpio_priv = gpio - priv->gpio_min; | |
157 | val = readl(®s->gpiodir); | |
158 | val = !!(val & (1 << gpio_priv)); | |
159 | debug("%s: reg: %x, gpio_no: %d, dir: %d\n", __func__, | |
160 | (u32)priv->regs, gpio_priv, val); | |
161 | ||
162 | return val; | |
163 | } | |
164 | ||
165 | return -1; | |
166 | } | |
167 | ||
168 | /* | |
169 | * Get input value | |
170 | * for example gpio setup to output only can't get input value | |
171 | * which is breaking gpio toggle command | |
172 | */ | |
173 | int gpio_get_value(unsigned gpio) | |
174 | { | |
175 | u32 val; | |
176 | ||
177 | if (gpio_get_direction(gpio) == GPIO_DIRECTION_OUT) | |
178 | val = gpio_get_output_value(gpio); | |
179 | else | |
180 | val = gpio_get_input_value(gpio); | |
181 | ||
182 | return val; | |
183 | } | |
184 | ||
185 | /* Set output value */ | |
186 | static int gpio_set_output_value(unsigned gpio, int value) | |
187 | { | |
188 | u32 val, gpio_priv; | |
189 | struct gpio_regs *regs; | |
190 | struct xilinx_gpio_priv *priv = gpio_get_controller(gpio); | |
191 | ||
192 | if (priv) { | |
193 | regs = priv->regs; | |
194 | gpio_priv = gpio - priv->gpio_min; | |
195 | val = priv->gpiodata_store; | |
196 | if (value) | |
197 | val |= 1 << gpio_priv; | |
198 | else | |
199 | val &= ~(1 << gpio_priv); | |
200 | ||
201 | writel(val, ®s->gpiodata); | |
202 | debug("%s: reg: %x, gpio_no: %d, output_val: %d\n", __func__, | |
203 | (u32)priv->regs, gpio_priv, val); | |
204 | priv->gpiodata_store = val; | |
205 | ||
206 | return 0; | |
207 | } | |
208 | ||
209 | return -1; | |
210 | } | |
211 | ||
212 | int gpio_set_value(unsigned gpio, int value) | |
213 | { | |
214 | if (gpio_get_direction(gpio) == GPIO_DIRECTION_OUT) | |
215 | return gpio_set_output_value(gpio, value); | |
216 | ||
217 | return -1; | |
218 | } | |
219 | ||
220 | /* Set GPIO as input */ | |
221 | int gpio_direction_input(unsigned gpio) | |
222 | { | |
223 | debug("%s\n", __func__); | |
224 | return gpio_set_direction(gpio, GPIO_DIRECTION_IN); | |
225 | } | |
226 | ||
227 | /* Setup GPIO as output and set output value */ | |
228 | int gpio_direction_output(unsigned gpio, int value) | |
229 | { | |
230 | int ret = gpio_set_direction(gpio, GPIO_DIRECTION_OUT); | |
231 | ||
232 | debug("%s\n", __func__); | |
233 | ||
234 | if (ret < 0) | |
235 | return ret; | |
236 | ||
237 | return gpio_set_output_value(gpio, value); | |
238 | } | |
239 | ||
240 | /* Show gpio status */ | |
241 | void gpio_info(void) | |
242 | { | |
243 | unsigned gpio; | |
244 | ||
245 | struct list_head *entry; | |
246 | struct xilinx_gpio_priv *priv = NULL; | |
247 | ||
248 | list_for_each(entry, &gpio_list) { | |
249 | priv = list_entry(entry, struct xilinx_gpio_priv, list); | |
250 | printf("\n%s: %s/%x (%d-%d)\n", __func__, priv->name, | |
251 | (u32)priv->regs, priv->gpio_min, priv->gpio_max); | |
252 | ||
253 | for (gpio = priv->gpio_min; gpio <= priv->gpio_max; gpio++) { | |
254 | printf("GPIO_%d:\t%s is an ", gpio, get_name(gpio)); | |
255 | if (gpio_get_direction(gpio) == GPIO_DIRECTION_OUT) | |
256 | printf("OUTPUT value = %d\n", | |
257 | gpio_get_output_value(gpio)); | |
258 | else | |
259 | printf("INPUT value = %d\n", | |
260 | gpio_get_input_value(gpio)); | |
261 | } | |
262 | } | |
263 | } | |
264 | ||
265 | int gpio_request(unsigned gpio, const char *label) | |
266 | { | |
267 | u32 gpio_priv; | |
268 | struct xilinx_gpio_priv *priv; | |
269 | ||
270 | if (gpio >= xilinx_gpio_max) | |
271 | return -EINVAL; | |
272 | ||
273 | priv = gpio_get_controller(gpio); | |
274 | if (priv) { | |
275 | gpio_priv = gpio - priv->gpio_min; | |
276 | ||
277 | if (label != NULL) { | |
278 | strncpy(priv->gpio_name[gpio_priv].name, label, | |
279 | GPIO_NAME_SIZE); | |
280 | priv->gpio_name[gpio_priv].name[GPIO_NAME_SIZE - 1] = | |
281 | '\0'; | |
282 | } | |
283 | return 0; | |
284 | } | |
285 | ||
286 | return -1; | |
287 | } | |
288 | ||
289 | int gpio_free(unsigned gpio) | |
290 | { | |
291 | u32 gpio_priv; | |
292 | struct xilinx_gpio_priv *priv; | |
293 | ||
294 | if (gpio >= xilinx_gpio_max) | |
295 | return -EINVAL; | |
296 | ||
297 | priv = gpio_get_controller(gpio); | |
298 | if (priv) { | |
299 | gpio_priv = gpio - priv->gpio_min; | |
300 | priv->gpio_name[gpio_priv].name[0] = '\0'; | |
301 | ||
302 | /* Do nothing here */ | |
303 | return 0; | |
304 | } | |
305 | ||
306 | return -1; | |
307 | } | |
308 | ||
309 | int gpio_alloc(u32 baseaddr, const char *name, u32 gpio_no) | |
310 | { | |
311 | struct xilinx_gpio_priv *priv; | |
312 | ||
313 | priv = calloc(1, sizeof(struct xilinx_gpio_priv)); | |
314 | ||
315 | /* Setup gpio name */ | |
316 | if (name != NULL) { | |
317 | strncpy(priv->name, name, GPIO_NAME_SIZE); | |
318 | priv->name[GPIO_NAME_SIZE - 1] = '\0'; | |
319 | } | |
320 | priv->regs = (struct gpio_regs *)baseaddr; | |
321 | ||
322 | priv->gpio_min = xilinx_gpio_max; | |
323 | xilinx_gpio_max = priv->gpio_min + gpio_no; | |
324 | priv->gpio_max = xilinx_gpio_max - 1; | |
325 | ||
326 | priv->gpio_name = calloc(gpio_no, sizeof(struct gpio_names)); | |
327 | ||
328 | INIT_LIST_HEAD(&priv->list); | |
329 | list_add_tail(&priv->list, &gpio_list); | |
330 | ||
331 | printf("%s: Add %s (%d-%d)\n", __func__, name, | |
332 | priv->gpio_min, priv->gpio_max); | |
333 | ||
334 | /* Return the first gpio allocated for this device */ | |
335 | return priv->gpio_min; | |
336 | } | |
337 | ||
338 | /* Dual channel gpio is one IP with two independent channels */ | |
339 | int gpio_alloc_dual(u32 baseaddr, const char *name, u32 gpio_no0, u32 gpio_no1) | |
340 | { | |
341 | int ret; | |
342 | ||
343 | ret = gpio_alloc(baseaddr, name, gpio_no0); | |
344 | gpio_alloc(baseaddr + 8, strcat((char *)name, "_1"), gpio_no1); | |
345 | ||
346 | /* Return the first gpio allocated for this device */ | |
347 | return ret; | |
348 | } |