]>
Commit | Line | Data |
---|---|---|
d764c504 NI |
1 | /* |
2 | * Pinmuxed GPIO support for SuperH. | |
3 | * Copy from linux kernel driver/sh/pfc.c | |
4 | * | |
5 | * Copyright (C) 2008 Magnus Damm | |
6 | * | |
7 | * This file is subject to the terms and conditions of the GNU General Public | |
8 | * License. See the file "COPYING" in the main directory of this archive | |
9 | * for more details. | |
10 | */ | |
11 | ||
12 | #include <common.h> | |
13 | #include <asm/bitops.h> | |
14 | #include <asm/io.h> | |
15 | #include <sh_pfc.h> | |
16 | ||
17 | static struct pinmux_info *gpioc; | |
18 | ||
19 | #define pfc_phys_to_virt(p, a) ((void *)a) | |
20 | ||
21 | static int enum_in_range(pinmux_enum_t enum_id, struct pinmux_range *r) | |
22 | { | |
23 | if (enum_id < r->begin) | |
24 | return 0; | |
25 | ||
26 | if (enum_id > r->end) | |
27 | return 0; | |
28 | ||
29 | return 1; | |
30 | } | |
31 | ||
32 | static unsigned long gpio_read_raw_reg(void *mapped_reg, | |
33 | unsigned long reg_width) | |
34 | { | |
35 | switch (reg_width) { | |
36 | ||
37 | case 8: | |
38 | return readb(mapped_reg); | |
39 | case 16: | |
40 | return readw(mapped_reg); | |
41 | case 32: | |
42 | return readl(mapped_reg); | |
43 | } | |
44 | ||
45 | BUG(); | |
46 | return 0; | |
47 | } | |
48 | ||
49 | static void gpio_write_raw_reg(void *mapped_reg, | |
50 | unsigned long reg_width, | |
51 | unsigned long data) | |
52 | { | |
53 | switch (reg_width) { | |
54 | case 8: | |
55 | writeb(data, mapped_reg); | |
56 | return; | |
57 | case 16: | |
58 | writew(data, mapped_reg); | |
59 | return; | |
60 | case 32: | |
61 | writel(data, mapped_reg); | |
62 | return; | |
63 | } | |
64 | ||
65 | BUG(); | |
66 | } | |
67 | ||
68 | static int gpio_read_bit(struct pinmux_data_reg *dr, | |
69 | unsigned long in_pos) | |
70 | { | |
71 | unsigned long pos; | |
72 | ||
73 | pos = dr->reg_width - (in_pos + 1); | |
74 | ||
75 | debug("read_bit: addr = %lx, pos = %ld, " | |
76 | "r_width = %ld\n", dr->reg, pos, dr->reg_width); | |
77 | ||
9035edba VB |
78 | return |
79 | (gpio_read_raw_reg(dr->mapped_reg + 0x4, dr->reg_width) >> pos) & 1; | |
d764c504 NI |
80 | } |
81 | ||
82 | static void gpio_write_bit(struct pinmux_data_reg *dr, | |
83 | unsigned long in_pos, unsigned long value) | |
84 | { | |
85 | unsigned long pos; | |
86 | ||
87 | pos = dr->reg_width - (in_pos + 1); | |
88 | ||
89 | debug("write_bit addr = %lx, value = %d, pos = %ld, " | |
90 | "r_width = %ld\n", | |
91 | dr->reg, !!value, pos, dr->reg_width); | |
92 | ||
93 | if (value) | |
94 | __set_bit(pos, &dr->reg_shadow); | |
95 | else | |
96 | __clear_bit(pos, &dr->reg_shadow); | |
97 | ||
98 | gpio_write_raw_reg(dr->mapped_reg, dr->reg_width, dr->reg_shadow); | |
99 | } | |
100 | ||
101 | static void config_reg_helper(struct pinmux_info *gpioc, | |
102 | struct pinmux_cfg_reg *crp, | |
103 | unsigned long in_pos, | |
104 | #if 0 | |
105 | void __iomem **mapped_regp, | |
106 | #else | |
107 | void **mapped_regp, | |
108 | #endif | |
109 | unsigned long *maskp, | |
110 | unsigned long *posp) | |
111 | { | |
112 | int k; | |
113 | ||
114 | *mapped_regp = pfc_phys_to_virt(gpioc, crp->reg); | |
115 | ||
116 | if (crp->field_width) { | |
117 | *maskp = (1 << crp->field_width) - 1; | |
118 | *posp = crp->reg_width - ((in_pos + 1) * crp->field_width); | |
119 | } else { | |
120 | *maskp = (1 << crp->var_field_width[in_pos]) - 1; | |
121 | *posp = crp->reg_width; | |
122 | for (k = 0; k <= in_pos; k++) | |
123 | *posp -= crp->var_field_width[k]; | |
124 | } | |
125 | } | |
126 | ||
127 | static int read_config_reg(struct pinmux_info *gpioc, | |
128 | struct pinmux_cfg_reg *crp, | |
129 | unsigned long field) | |
130 | { | |
131 | void *mapped_reg; | |
132 | ||
133 | unsigned long mask, pos; | |
134 | ||
135 | config_reg_helper(gpioc, crp, field, &mapped_reg, &mask, &pos); | |
136 | ||
137 | debug("read_reg: addr = %lx, field = %ld, " | |
138 | "r_width = %ld, f_width = %ld\n", | |
139 | crp->reg, field, crp->reg_width, crp->field_width); | |
140 | ||
141 | return (gpio_read_raw_reg(mapped_reg, crp->reg_width) >> pos) & mask; | |
142 | } | |
143 | ||
144 | static void write_config_reg(struct pinmux_info *gpioc, | |
145 | struct pinmux_cfg_reg *crp, | |
146 | unsigned long field, unsigned long value) | |
147 | { | |
148 | void *mapped_reg; | |
149 | unsigned long mask, pos, data; | |
150 | ||
151 | config_reg_helper(gpioc, crp, field, &mapped_reg, &mask, &pos); | |
152 | ||
153 | debug("write_reg addr = %lx, value = %ld, field = %ld, " | |
154 | "r_width = %ld, f_width = %ld\n", | |
155 | crp->reg, value, field, crp->reg_width, crp->field_width); | |
156 | ||
157 | mask = ~(mask << pos); | |
158 | value = value << pos; | |
159 | ||
160 | data = gpio_read_raw_reg(mapped_reg, crp->reg_width); | |
161 | data &= mask; | |
162 | data |= value; | |
163 | ||
164 | if (gpioc->unlock_reg) | |
165 | gpio_write_raw_reg(pfc_phys_to_virt(gpioc, gpioc->unlock_reg), | |
166 | 32, ~data); | |
167 | ||
168 | gpio_write_raw_reg(mapped_reg, crp->reg_width, data); | |
169 | } | |
170 | ||
171 | static int setup_data_reg(struct pinmux_info *gpioc, unsigned gpio) | |
172 | { | |
173 | struct pinmux_gpio *gpiop = &gpioc->gpios[gpio]; | |
174 | struct pinmux_data_reg *data_reg; | |
175 | int k, n; | |
176 | ||
177 | if (!enum_in_range(gpiop->enum_id, &gpioc->data)) | |
178 | return -1; | |
179 | ||
180 | k = 0; | |
181 | while (1) { | |
182 | data_reg = gpioc->data_regs + k; | |
183 | ||
184 | if (!data_reg->reg_width) | |
185 | break; | |
186 | ||
187 | data_reg->mapped_reg = pfc_phys_to_virt(gpioc, data_reg->reg); | |
188 | ||
189 | for (n = 0; n < data_reg->reg_width; n++) { | |
190 | if (data_reg->enum_ids[n] == gpiop->enum_id) { | |
191 | gpiop->flags &= ~PINMUX_FLAG_DREG; | |
192 | gpiop->flags |= (k << PINMUX_FLAG_DREG_SHIFT); | |
193 | gpiop->flags &= ~PINMUX_FLAG_DBIT; | |
194 | gpiop->flags |= (n << PINMUX_FLAG_DBIT_SHIFT); | |
195 | return 0; | |
196 | } | |
197 | } | |
198 | k++; | |
199 | } | |
200 | ||
201 | BUG(); | |
202 | ||
203 | return -1; | |
204 | } | |
205 | ||
206 | static void setup_data_regs(struct pinmux_info *gpioc) | |
207 | { | |
208 | struct pinmux_data_reg *drp; | |
209 | int k; | |
210 | ||
211 | for (k = gpioc->first_gpio; k <= gpioc->last_gpio; k++) | |
212 | setup_data_reg(gpioc, k); | |
213 | ||
214 | k = 0; | |
215 | while (1) { | |
216 | drp = gpioc->data_regs + k; | |
217 | ||
218 | if (!drp->reg_width) | |
219 | break; | |
220 | ||
221 | drp->reg_shadow = gpio_read_raw_reg(drp->mapped_reg, | |
222 | drp->reg_width); | |
223 | k++; | |
224 | } | |
225 | } | |
226 | ||
227 | static int get_data_reg(struct pinmux_info *gpioc, unsigned gpio, | |
228 | struct pinmux_data_reg **drp, int *bitp) | |
229 | { | |
230 | struct pinmux_gpio *gpiop = &gpioc->gpios[gpio]; | |
231 | int k, n; | |
232 | ||
233 | if (!enum_in_range(gpiop->enum_id, &gpioc->data)) | |
234 | return -1; | |
235 | ||
236 | k = (gpiop->flags & PINMUX_FLAG_DREG) >> PINMUX_FLAG_DREG_SHIFT; | |
237 | n = (gpiop->flags & PINMUX_FLAG_DBIT) >> PINMUX_FLAG_DBIT_SHIFT; | |
238 | *drp = gpioc->data_regs + k; | |
239 | *bitp = n; | |
240 | return 0; | |
241 | } | |
242 | ||
243 | static int get_config_reg(struct pinmux_info *gpioc, pinmux_enum_t enum_id, | |
244 | struct pinmux_cfg_reg **crp, | |
245 | int *fieldp, int *valuep, | |
246 | unsigned long **cntp) | |
247 | { | |
248 | struct pinmux_cfg_reg *config_reg; | |
249 | unsigned long r_width, f_width, curr_width, ncomb; | |
250 | int k, m, n, pos, bit_pos; | |
251 | ||
252 | k = 0; | |
253 | while (1) { | |
254 | config_reg = gpioc->cfg_regs + k; | |
255 | ||
256 | r_width = config_reg->reg_width; | |
257 | f_width = config_reg->field_width; | |
258 | ||
259 | if (!r_width) | |
260 | break; | |
261 | ||
262 | pos = 0; | |
263 | m = 0; | |
264 | for (bit_pos = 0; bit_pos < r_width; bit_pos += curr_width) { | |
265 | if (f_width) | |
266 | curr_width = f_width; | |
267 | else | |
268 | curr_width = config_reg->var_field_width[m]; | |
269 | ||
270 | ncomb = 1 << curr_width; | |
271 | for (n = 0; n < ncomb; n++) { | |
272 | if (config_reg->enum_ids[pos + n] == enum_id) { | |
273 | *crp = config_reg; | |
274 | *fieldp = m; | |
275 | *valuep = n; | |
276 | *cntp = &config_reg->cnt[m]; | |
277 | return 0; | |
278 | } | |
279 | } | |
280 | pos += ncomb; | |
281 | m++; | |
282 | } | |
283 | k++; | |
284 | } | |
285 | ||
286 | return -1; | |
287 | } | |
288 | ||
289 | static int get_gpio_enum_id(struct pinmux_info *gpioc, unsigned gpio, | |
290 | int pos, pinmux_enum_t *enum_idp) | |
291 | { | |
292 | pinmux_enum_t enum_id = gpioc->gpios[gpio].enum_id; | |
293 | pinmux_enum_t *data = gpioc->gpio_data; | |
294 | int k; | |
295 | ||
296 | if (!enum_in_range(enum_id, &gpioc->data)) { | |
297 | if (!enum_in_range(enum_id, &gpioc->mark)) { | |
298 | debug("non data/mark enum_id for gpio %d\n", gpio); | |
299 | return -1; | |
300 | } | |
301 | } | |
302 | ||
303 | if (pos) { | |
304 | *enum_idp = data[pos + 1]; | |
305 | return pos + 1; | |
306 | } | |
307 | ||
308 | for (k = 0; k < gpioc->gpio_data_size; k++) { | |
309 | if (data[k] == enum_id) { | |
310 | *enum_idp = data[k + 1]; | |
311 | return k + 1; | |
312 | } | |
313 | } | |
314 | ||
315 | debug("cannot locate data/mark enum_id for gpio %d\n", gpio); | |
316 | return -1; | |
317 | } | |
318 | ||
319 | enum { GPIO_CFG_DRYRUN, GPIO_CFG_REQ, GPIO_CFG_FREE }; | |
320 | ||
321 | static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio, | |
322 | int pinmux_type, int cfg_mode) | |
323 | { | |
324 | struct pinmux_cfg_reg *cr = NULL; | |
325 | pinmux_enum_t enum_id; | |
326 | struct pinmux_range *range; | |
327 | int in_range, pos, field, value; | |
328 | unsigned long *cntp; | |
329 | ||
330 | switch (pinmux_type) { | |
331 | ||
332 | case PINMUX_TYPE_FUNCTION: | |
333 | range = NULL; | |
334 | break; | |
335 | ||
336 | case PINMUX_TYPE_OUTPUT: | |
337 | range = &gpioc->output; | |
338 | break; | |
339 | ||
340 | case PINMUX_TYPE_INPUT: | |
341 | range = &gpioc->input; | |
342 | break; | |
343 | ||
344 | case PINMUX_TYPE_INPUT_PULLUP: | |
345 | range = &gpioc->input_pu; | |
346 | break; | |
347 | ||
348 | case PINMUX_TYPE_INPUT_PULLDOWN: | |
349 | range = &gpioc->input_pd; | |
350 | break; | |
351 | ||
352 | default: | |
353 | goto out_err; | |
354 | } | |
355 | ||
356 | pos = 0; | |
357 | enum_id = 0; | |
358 | field = 0; | |
359 | value = 0; | |
360 | while (1) { | |
361 | pos = get_gpio_enum_id(gpioc, gpio, pos, &enum_id); | |
362 | if (pos <= 0) | |
363 | goto out_err; | |
364 | ||
365 | if (!enum_id) | |
366 | break; | |
367 | ||
368 | /* first check if this is a function enum */ | |
369 | in_range = enum_in_range(enum_id, &gpioc->function); | |
370 | if (!in_range) { | |
371 | /* not a function enum */ | |
372 | if (range) { | |
373 | /* | |
374 | * other range exists, so this pin is | |
375 | * a regular GPIO pin that now is being | |
376 | * bound to a specific direction. | |
377 | * | |
378 | * for this case we only allow function enums | |
379 | * and the enums that match the other range. | |
380 | */ | |
381 | in_range = enum_in_range(enum_id, range); | |
382 | ||
383 | /* | |
384 | * special case pass through for fixed | |
385 | * input-only or output-only pins without | |
386 | * function enum register association. | |
387 | */ | |
388 | if (in_range && enum_id == range->force) | |
389 | continue; | |
390 | } else { | |
391 | /* | |
392 | * no other range exists, so this pin | |
393 | * must then be of the function type. | |
394 | * | |
395 | * allow function type pins to select | |
396 | * any combination of function/in/out | |
397 | * in their MARK lists. | |
398 | */ | |
399 | in_range = 1; | |
400 | } | |
401 | } | |
402 | ||
403 | if (!in_range) | |
404 | continue; | |
405 | ||
406 | if (get_config_reg(gpioc, enum_id, &cr, | |
407 | &field, &value, &cntp) != 0) | |
408 | goto out_err; | |
409 | ||
410 | switch (cfg_mode) { | |
411 | case GPIO_CFG_DRYRUN: | |
412 | if (!*cntp || | |
413 | (read_config_reg(gpioc, cr, field) != value)) | |
414 | continue; | |
415 | break; | |
416 | ||
417 | case GPIO_CFG_REQ: | |
418 | write_config_reg(gpioc, cr, field, value); | |
419 | *cntp = *cntp + 1; | |
420 | break; | |
421 | ||
422 | case GPIO_CFG_FREE: | |
423 | *cntp = *cntp - 1; | |
424 | break; | |
425 | } | |
426 | } | |
427 | ||
428 | return 0; | |
429 | out_err: | |
430 | return -1; | |
431 | } | |
432 | ||
433 | #if 0 | |
434 | static DEFINE_SPINLOCK(gpio_lock); | |
435 | static struct pinmux_info *chip_to_pinmux(struct gpio_chip *chip) | |
436 | { | |
437 | return container_of(chip, struct pinmux_info, chip); | |
438 | } | |
439 | #endif | |
440 | ||
441 | static int sh_gpio_request(unsigned offset) | |
442 | { | |
443 | struct pinmux_data_reg *dummy; | |
444 | int i, ret, pinmux_type; | |
445 | ||
446 | ret = -1; | |
447 | ||
448 | if (!gpioc) | |
449 | goto err_out; | |
450 | ||
451 | if ((gpioc->gpios[offset].flags & PINMUX_FLAG_TYPE) != PINMUX_TYPE_NONE) | |
452 | goto err_out; | |
453 | ||
454 | /* setup pin function here if no data is associated with pin */ | |
455 | ||
456 | if (get_data_reg(gpioc, offset, &dummy, &i) != 0) | |
457 | pinmux_type = PINMUX_TYPE_FUNCTION; | |
458 | else | |
459 | pinmux_type = PINMUX_TYPE_GPIO; | |
460 | ||
461 | if (pinmux_type == PINMUX_TYPE_FUNCTION) { | |
462 | if (pinmux_config_gpio(gpioc, offset, | |
463 | pinmux_type, | |
464 | GPIO_CFG_DRYRUN) != 0) | |
465 | goto err_out; | |
466 | ||
467 | if (pinmux_config_gpio(gpioc, offset, | |
468 | pinmux_type, | |
469 | GPIO_CFG_REQ) != 0) | |
470 | BUG(); | |
471 | } | |
472 | ||
473 | gpioc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE; | |
474 | gpioc->gpios[offset].flags |= pinmux_type; | |
475 | ||
476 | ret = 0; | |
477 | err_out: | |
478 | return ret; | |
479 | } | |
480 | ||
481 | static void sh_gpio_free(unsigned offset) | |
482 | { | |
483 | int pinmux_type; | |
484 | ||
485 | if (!gpioc) | |
486 | return; | |
487 | ||
488 | pinmux_type = gpioc->gpios[offset].flags & PINMUX_FLAG_TYPE; | |
489 | pinmux_config_gpio(gpioc, offset, pinmux_type, GPIO_CFG_FREE); | |
490 | gpioc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE; | |
491 | gpioc->gpios[offset].flags |= PINMUX_TYPE_NONE; | |
492 | } | |
493 | ||
494 | static int pinmux_direction(struct pinmux_info *gpioc, | |
495 | unsigned gpio, int new_pinmux_type) | |
496 | { | |
497 | int pinmux_type; | |
498 | int ret = -1; | |
499 | ||
500 | if (!gpioc) | |
501 | goto err_out; | |
502 | ||
503 | pinmux_type = gpioc->gpios[gpio].flags & PINMUX_FLAG_TYPE; | |
504 | ||
505 | switch (pinmux_type) { | |
506 | case PINMUX_TYPE_GPIO: | |
507 | break; | |
508 | case PINMUX_TYPE_OUTPUT: | |
509 | case PINMUX_TYPE_INPUT: | |
510 | case PINMUX_TYPE_INPUT_PULLUP: | |
511 | case PINMUX_TYPE_INPUT_PULLDOWN: | |
512 | pinmux_config_gpio(gpioc, gpio, pinmux_type, GPIO_CFG_FREE); | |
513 | break; | |
514 | default: | |
515 | goto err_out; | |
516 | } | |
517 | ||
518 | if (pinmux_config_gpio(gpioc, gpio, | |
519 | new_pinmux_type, | |
520 | GPIO_CFG_DRYRUN) != 0) | |
521 | goto err_out; | |
522 | ||
523 | if (pinmux_config_gpio(gpioc, gpio, | |
524 | new_pinmux_type, | |
525 | GPIO_CFG_REQ) != 0) | |
526 | BUG(); | |
527 | ||
528 | gpioc->gpios[gpio].flags &= ~PINMUX_FLAG_TYPE; | |
529 | gpioc->gpios[gpio].flags |= new_pinmux_type; | |
530 | ||
531 | ret = 0; | |
532 | err_out: | |
533 | return ret; | |
534 | } | |
535 | ||
536 | static int sh_gpio_direction_input(unsigned offset) | |
537 | { | |
538 | return pinmux_direction(gpioc, offset, PINMUX_TYPE_INPUT); | |
539 | } | |
540 | ||
541 | static void sh_gpio_set_value(struct pinmux_info *gpioc, | |
542 | unsigned gpio, int value) | |
543 | { | |
544 | struct pinmux_data_reg *dr = NULL; | |
545 | int bit = 0; | |
546 | ||
547 | if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0) | |
548 | BUG(); | |
549 | else | |
550 | gpio_write_bit(dr, bit, value); | |
551 | } | |
552 | ||
553 | static int sh_gpio_direction_output(unsigned offset, int value) | |
554 | { | |
555 | sh_gpio_set_value(gpioc, offset, value); | |
556 | return pinmux_direction(gpioc, offset, PINMUX_TYPE_OUTPUT); | |
557 | } | |
558 | ||
559 | static int sh_gpio_get_value(struct pinmux_info *gpioc, unsigned gpio) | |
560 | { | |
561 | struct pinmux_data_reg *dr = NULL; | |
562 | int bit = 0; | |
563 | ||
564 | if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0) | |
565 | return -1; | |
566 | ||
567 | return gpio_read_bit(dr, bit); | |
568 | } | |
569 | ||
570 | static int sh_gpio_get(unsigned offset) | |
571 | { | |
572 | return sh_gpio_get_value(gpioc, offset); | |
573 | } | |
574 | ||
575 | static void sh_gpio_set(unsigned offset, int value) | |
576 | { | |
577 | sh_gpio_set_value(gpioc, offset, value); | |
578 | } | |
579 | ||
580 | int register_pinmux(struct pinmux_info *pip) | |
581 | { | |
582 | if (pip != NULL) { | |
583 | gpioc = pip; | |
584 | debug("%s deregistering\n", pip->name); | |
585 | setup_data_regs(gpioc); | |
586 | } | |
587 | return 0; | |
588 | } | |
589 | ||
590 | int unregister_pinmux(struct pinmux_info *pip) | |
591 | { | |
592 | debug("%s deregistering\n", pip->name); | |
593 | if (gpioc != pip) | |
594 | return -1; | |
595 | ||
596 | gpioc = NULL; | |
597 | return 0; | |
598 | } | |
599 | ||
600 | int gpio_request(unsigned gpio, const char *label) | |
601 | { | |
602 | sh_gpio_request(gpio); | |
603 | return 0; | |
604 | } | |
605 | ||
606 | int gpio_free(unsigned gpio) | |
607 | { | |
608 | sh_gpio_free(gpio); | |
609 | return 0; | |
610 | } | |
611 | ||
612 | int gpio_direction_input(unsigned gpio) | |
613 | { | |
614 | return sh_gpio_direction_input(gpio); | |
615 | } | |
616 | ||
617 | int gpio_direction_output(unsigned gpio, int value) | |
618 | { | |
619 | return sh_gpio_direction_output(gpio, value); | |
620 | } | |
621 | ||
622 | void gpio_set_value(unsigned gpio, int value) | |
623 | { | |
624 | sh_gpio_set(gpio, value); | |
625 | } | |
626 | ||
627 | int gpio_get_value(unsigned gpio) | |
628 | { | |
629 | return sh_gpio_get(gpio); | |
630 | } |