aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-stmp3xxx/pinmux.c
diff options
context:
space:
mode:
authordmitry pervushin <dpervushin@embeddedalley.com>2009-04-23 07:24:13 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2009-04-27 05:28:08 -0400
commit5cccd37ea15970846a93b4b01fafd6e043bafe8e (patch)
tree4ab99b59f91964028fbba128d8ae086f60bd8c82 /arch/arm/plat-stmp3xxx/pinmux.c
parente317872ac532fd845c597e55ceb5a9bceee878c1 (diff)
[ARM] 5477/1: Freescale STMP platform support [6/10]
Sources: common STMP3xxx platform support Signed-off-by: dmitry pervushin <dpervushin@embeddedalley.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/plat-stmp3xxx/pinmux.c')
-rw-r--r--arch/arm/plat-stmp3xxx/pinmux.c545
1 files changed, 545 insertions, 0 deletions
diff --git a/arch/arm/plat-stmp3xxx/pinmux.c b/arch/arm/plat-stmp3xxx/pinmux.c
new file mode 100644
index 000000000000..9b28cc83f31c
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/pinmux.c
@@ -0,0 +1,545 @@
1/*
2 * Freescale STMP378X/STMP378X Pin Multiplexing
3 *
4 * Author: Vladislav Buzov <vbuzov@embeddedalley.com>
5 *
6 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
7 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
8 */
9
10/*
11 * The code contained herein is licensed under the GNU General Public
12 * License. You may obtain a copy of the GNU General Public License
13 * Version 2 or later at the following locations:
14 *
15 * http://www.opensource.org/licenses/gpl-license.html
16 * http://www.gnu.org/copyleft/gpl.html
17 */
18#include <linux/module.h>
19#include <linux/kernel.h>
20#include <linux/errno.h>
21#include <linux/sysdev.h>
22#include <linux/string.h>
23#include <linux/bitops.h>
24#include <linux/sysdev.h>
25#include <linux/irq.h>
26
27#include <mach/hardware.h>
28#include <mach/regs-pinctrl.h>
29#include <mach/pins.h>
30#include <mach/pinmux.h>
31
32#define NR_BANKS ARRAY_SIZE(pinmux_banks)
33static struct stmp3xxx_pinmux_bank pinmux_banks[] = {
34 [0] = {
35 .hw_muxsel = {
36 HW_PINCTRL_MUXSEL0_ADDR,
37 HW_PINCTRL_MUXSEL1_ADDR
38 },
39 .hw_drive = {
40 HW_PINCTRL_DRIVE0_ADDR,
41 HW_PINCTRL_DRIVE1_ADDR,
42 HW_PINCTRL_DRIVE2_ADDR,
43 HW_PINCTRL_DRIVE3_ADDR
44 },
45 .hw_pull = HW_PINCTRL_PULL0_ADDR,
46 .functions = { 0x0, 0x1, 0x2, 0x3 },
47 .strengths = { 0x0, 0x1, 0x2, 0x3, 0xff },
48
49 .hw_gpio_read = HW_PINCTRL_DIN0_ADDR,
50 .hw_gpio_set = HW_PINCTRL_DOUT0_ADDR + HW_STMP3xxx_SET,
51 .hw_gpio_clr = HW_PINCTRL_DOUT0_ADDR + HW_STMP3xxx_CLR,
52 .hw_gpio_doe = HW_PINCTRL_DOE0_ADDR,
53 .irq = IRQ_GPIO0,
54
55 .pin2irq = HW_PINCTRL_PIN2IRQ0_ADDR,
56 .irqstat = HW_PINCTRL_IRQSTAT0_ADDR,
57 .irqlevel = HW_PINCTRL_IRQLEVEL0_ADDR,
58 .irqpolarity = HW_PINCTRL_IRQPOL0_ADDR,
59 .irqen = HW_PINCTRL_IRQEN0_ADDR,
60 },
61 [1] = {
62 .hw_muxsel = {
63 HW_PINCTRL_MUXSEL2_ADDR,
64 HW_PINCTRL_MUXSEL3_ADDR
65 },
66 .hw_drive = {
67 HW_PINCTRL_DRIVE4_ADDR,
68 HW_PINCTRL_DRIVE5_ADDR,
69 HW_PINCTRL_DRIVE6_ADDR,
70 HW_PINCTRL_DRIVE7_ADDR
71 },
72 .hw_pull = HW_PINCTRL_PULL1_ADDR,
73 .functions = { 0x0, 0x1, 0x2, 0x3 },
74 .strengths = { 0x0, 0x1, 0x2, 0x3, 0xff },
75
76 .hw_gpio_read = HW_PINCTRL_DIN1_ADDR,
77 .hw_gpio_set = HW_PINCTRL_DOUT1_ADDR + HW_STMP3xxx_SET,
78 .hw_gpio_clr = HW_PINCTRL_DOUT1_ADDR + HW_STMP3xxx_CLR,
79 .hw_gpio_doe = HW_PINCTRL_DOE1_ADDR,
80 .irq = IRQ_GPIO1,
81
82 .pin2irq = HW_PINCTRL_PIN2IRQ1_ADDR,
83 .irqstat = HW_PINCTRL_IRQSTAT1_ADDR,
84 .irqlevel = HW_PINCTRL_IRQLEVEL1_ADDR,
85 .irqpolarity = HW_PINCTRL_IRQPOL1_ADDR,
86 .irqen = HW_PINCTRL_IRQEN1_ADDR,
87 },
88 [2] = {
89 .hw_muxsel = {
90 HW_PINCTRL_MUXSEL4_ADDR,
91 HW_PINCTRL_MUXSEL5_ADDR,
92 },
93 .hw_drive = {
94 HW_PINCTRL_DRIVE8_ADDR,
95 HW_PINCTRL_DRIVE9_ADDR,
96 HW_PINCTRL_DRIVE10_ADDR,
97 HW_PINCTRL_DRIVE11_ADDR,
98 },
99 .hw_pull = HW_PINCTRL_PULL2_ADDR,
100 .functions = { 0x0, 0x1, 0x2, 0x3 },
101 .strengths = { 0x0, 0x1, 0x2, 0x1, 0x2 },
102
103 .hw_gpio_read = HW_PINCTRL_DIN2_ADDR,
104 .hw_gpio_set = HW_PINCTRL_DOUT2_ADDR + HW_STMP3xxx_SET,
105 .hw_gpio_clr = HW_PINCTRL_DOUT2_ADDR + HW_STMP3xxx_CLR,
106 .hw_gpio_doe = HW_PINCTRL_DOE2_ADDR,
107 .irq = IRQ_GPIO2,
108
109 .pin2irq = HW_PINCTRL_PIN2IRQ2_ADDR,
110 .irqstat = HW_PINCTRL_IRQSTAT2_ADDR,
111 .irqlevel = HW_PINCTRL_IRQLEVEL2_ADDR,
112 .irqpolarity = HW_PINCTRL_IRQPOL2_ADDR,
113 .irqen = HW_PINCTRL_IRQEN2_ADDR,
114 },
115 [3] = {
116 .hw_muxsel = {
117 HW_PINCTRL_MUXSEL6_ADDR,
118 HW_PINCTRL_MUXSEL7_ADDR,
119 },
120 .hw_drive = {
121 HW_PINCTRL_DRIVE12_ADDR,
122 HW_PINCTRL_DRIVE13_ADDR,
123 HW_PINCTRL_DRIVE14_ADDR,
124 NULL,
125 },
126 .hw_pull = HW_PINCTRL_PULL3_ADDR,
127 .functions = {0x0, 0x1, 0x2, 0x3},
128 .strengths = {0x0, 0x1, 0x2, 0x3, 0xff},
129 },
130};
131
132static inline struct stmp3xxx_pinmux_bank *
133stmp3xxx_pinmux_bank(unsigned id, unsigned *bank, unsigned *pin)
134{
135 unsigned b, p;
136
137 b = STMP3XXX_PINID_TO_BANK(id);
138 p = STMP3XXX_PINID_TO_PINNUM(id);
139 BUG_ON(b >= NR_BANKS);
140 if (bank)
141 *bank = b;
142 if (pin)
143 *pin = p;
144 return &pinmux_banks[b];
145}
146
147/* Check if requested pin is owned by caller */
148static int stmp3xxx_check_pin(unsigned id, const char *label)
149{
150 unsigned pin;
151 struct stmp3xxx_pinmux_bank *pm = stmp3xxx_pinmux_bank(id, NULL, &pin);
152
153 if (!test_bit(pin, &pm->pin_map)) {
154 printk(KERN_WARNING
155 "%s: Accessing free pin %x, caller %s\n",
156 __func__, id, label);
157
158 return -EINVAL;
159 }
160
161 if (label && pm->pin_labels[pin] &&
162 strcmp(label, pm->pin_labels[pin])) {
163 printk(KERN_WARNING
164 "%s: Wrong pin owner %x, caller %s owner %s\n",
165 __func__, id, label, pm->pin_labels[pin]);
166
167 return -EINVAL;
168 }
169 return 0;
170}
171
172void stmp3xxx_pin_strength(unsigned id, enum pin_strength strength,
173 const char *label)
174{
175 struct stmp3xxx_pinmux_bank *pbank;
176 void __iomem *hwdrive;
177 u32 shift, val;
178 u32 bank, pin;
179
180 pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
181 pr_debug("%s: label %s bank %d pin %d strength %d\n", __func__, label,
182 bank, pin, strength);
183
184 hwdrive = pbank->hw_drive[pin / HW_DRIVE_PIN_NUM];
185 shift = (pin % HW_DRIVE_PIN_NUM) * HW_DRIVE_PIN_LEN;
186 val = pbank->strengths[strength];
187 if (val == 0xff) {
188 printk(KERN_WARNING
189 "%s: strength is not supported for bank %d, caller %s",
190 __func__, bank, label);
191 return;
192 }
193
194 if (stmp3xxx_check_pin(id, label))
195 return;
196
197 pr_debug("%s: writing 0x%x to 0x%p register\n", __func__,
198 val << shift, hwdrive);
199 __raw_writel(HW_DRIVE_PINDRV_MASK << shift, hwdrive + HW_STMP3xxx_CLR);
200 __raw_writel(val << shift, hwdrive + HW_STMP3xxx_SET);
201}
202
203void stmp3xxx_pin_voltage(unsigned id, enum pin_voltage voltage,
204 const char *label)
205{
206 struct stmp3xxx_pinmux_bank *pbank;
207 void __iomem *hwdrive;
208 u32 shift;
209 u32 bank, pin;
210
211 pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
212 pr_debug("%s: label %s bank %d pin %d voltage %d\n", __func__, label,
213 bank, pin, voltage);
214
215 hwdrive = pbank->hw_drive[pin / HW_DRIVE_PIN_NUM];
216 shift = (pin % HW_DRIVE_PIN_NUM) * HW_DRIVE_PIN_LEN;
217
218 if (stmp3xxx_check_pin(id, label))
219 return;
220
221 pr_debug("%s: changing 0x%x bit in 0x%p register\n",
222 __func__, HW_DRIVE_PINV_MASK << shift, hwdrive);
223 if (voltage == PIN_1_8V)
224 __raw_writel(HW_DRIVE_PINV_MASK << shift,
225 hwdrive + HW_STMP3xxx_CLR);
226 else
227 __raw_writel(HW_DRIVE_PINV_MASK << shift,
228 hwdrive + HW_STMP3xxx_SET);
229}
230
231void stmp3xxx_pin_pullup(unsigned id, int enable, const char *label)
232{
233 struct stmp3xxx_pinmux_bank *pbank;
234 void __iomem *hwpull;
235 u32 bank, pin;
236
237 pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
238 pr_debug("%s: label %s bank %d pin %d enable %d\n", __func__, label,
239 bank, pin, enable);
240
241 hwpull = pbank->hw_pull;
242
243 if (stmp3xxx_check_pin(id, label))
244 return;
245
246 pr_debug("%s: changing 0x%x bit in 0x%p register\n",
247 __func__, 1 << pin, hwpull);
248 __raw_writel(1 << pin,
249 hwpull + (enable ? HW_STMP3xxx_SET : HW_STMP3xxx_CLR));
250}
251
252int stmp3xxx_request_pin(unsigned id, enum pin_fun fun, const char *label)
253{
254 struct stmp3xxx_pinmux_bank *pbank;
255 u32 bank, pin;
256 int ret = 0;
257
258 pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
259 pr_debug("%s: label %s bank %d pin %d fun %d\n", __func__, label,
260 bank, pin, fun);
261
262 if (test_bit(pin, &pbank->pin_map)) {
263 printk(KERN_WARNING
264 "%s: CONFLICT DETECTED pin %d:%d caller %s owner %s\n",
265 __func__, bank, pin, label, pbank->pin_labels[pin]);
266 return -EBUSY;
267 }
268
269 set_bit(pin, &pbank->pin_map);
270 pbank->pin_labels[pin] = label;
271
272 stmp3xxx_set_pin_type(id, fun);
273
274 return ret;
275}
276
277void stmp3xxx_set_pin_type(unsigned id, enum pin_fun fun)
278{
279 struct stmp3xxx_pinmux_bank *pbank;
280 void __iomem *hwmux;
281 u32 shift, val;
282 u32 bank, pin;
283
284 pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
285
286 hwmux = pbank->hw_muxsel[pin / HW_MUXSEL_PIN_NUM];
287 shift = (pin % HW_MUXSEL_PIN_NUM) * HW_MUXSEL_PIN_LEN;
288
289 val = pbank->functions[fun];
290 shift = (pin % HW_MUXSEL_PIN_NUM) * HW_MUXSEL_PIN_LEN;
291 pr_debug("%s: writing 0x%x to 0x%p register\n",
292 __func__, val << shift, hwmux);
293 __raw_writel(HW_MUXSEL_PINFUN_MASK << shift, hwmux + HW_STMP3xxx_CLR);
294 __raw_writel(val << shift, hwmux + HW_STMP3xxx_SET);
295}
296
297void stmp3xxx_release_pin(unsigned id, const char *label)
298{
299 struct stmp3xxx_pinmux_bank *pbank;
300 u32 bank, pin;
301
302 pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
303 pr_debug("%s: label %s bank %d pin %d\n", __func__, label, bank, pin);
304
305 if (stmp3xxx_check_pin(id, label))
306 return;
307
308 clear_bit(pin, &pbank->pin_map);
309 pbank->pin_labels[pin] = NULL;
310}
311
312int stmp3xxx_request_pin_group(struct pin_group *pin_group, const char *label)
313{
314 struct pin_desc *pin;
315 int p;
316 int err = 0;
317
318 /* Allocate and configure pins */
319 for (p = 0; p < pin_group->nr_pins; p++) {
320 pr_debug("%s: #%d\n", __func__, p);
321 pin = &pin_group->pins[p];
322
323 err = stmp3xxx_request_pin(pin->id, pin->fun, label);
324 if (err)
325 goto out_err;
326
327 stmp3xxx_pin_strength(pin->id, pin->strength, label);
328 stmp3xxx_pin_voltage(pin->id, pin->voltage, label);
329 stmp3xxx_pin_pullup(pin->id, pin->pullup, label);
330 }
331
332 return 0;
333
334out_err:
335 /* Release allocated pins in case of error */
336 while (--p >= 0) {
337 pr_debug("%s: releasing #%d\n", __func__, p);
338 stmp3xxx_release_pin(pin_group->pins[p].id, label);
339 }
340 return err;
341}
342EXPORT_SYMBOL(stmp3xxx_request_pin_group);
343
344void stmp3xxx_release_pin_group(struct pin_group *pin_group, const char *label)
345{
346 struct pin_desc *pin;
347 int p;
348
349 for (p = 0; p < pin_group->nr_pins; p++) {
350 pin = &pin_group->pins[p];
351 stmp3xxx_release_pin(pin->id, label);
352 }
353}
354EXPORT_SYMBOL(stmp3xxx_release_pin_group);
355
356static int stmp3xxx_irq_to_gpio(int irq,
357 struct stmp3xxx_pinmux_bank **bank, unsigned *gpio)
358{
359 struct stmp3xxx_pinmux_bank *pm;
360
361 for (pm = pinmux_banks; pm < pinmux_banks + NR_BANKS; pm++)
362 if (pm->virq <= irq && irq < pm->virq + 32) {
363 *bank = pm;
364 *gpio = irq - pm->virq;
365 return 0;
366 }
367 return -ENOENT;
368}
369
370static int stmp3xxx_set_irqtype(unsigned irq, unsigned type)
371{
372 struct stmp3xxx_pinmux_bank *pm;
373 unsigned gpio;
374 int l, p;
375
376 stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
377 switch (type) {
378 case IRQ_TYPE_EDGE_RISING:
379 l = 0; p = 1; break;
380 case IRQ_TYPE_EDGE_FALLING:
381 l = 0; p = 0; break;
382 case IRQ_TYPE_LEVEL_HIGH:
383 l = 1; p = 1; break;
384 case IRQ_TYPE_LEVEL_LOW:
385 l = 1; p = 0; break;
386 default:
387 pr_debug("%s: Incorrect GPIO interrupt type 0x%x\n",
388 __func__, type);
389 return -ENXIO;
390 }
391 __raw_writel(1 << gpio,
392 pm->irqlevel + (l ? HW_STMP3xxx_SET : HW_STMP3xxx_CLR));
393 __raw_writel(1 << gpio,
394 pm->irqpolarity + (p ? HW_STMP3xxx_SET : HW_STMP3xxx_CLR));
395 return 0;
396}
397
398static void stmp3xxx_pin_ack_irq(unsigned irq)
399{
400 u32 stat;
401 struct stmp3xxx_pinmux_bank *pm;
402 unsigned gpio;
403
404 stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
405 stat = __raw_readl(pm->irqstat) & (1<<gpio);
406 __raw_writel(stat, pm->irqstat + HW_STMP3xxx_CLR);
407}
408
409static void stmp3xxx_pin_mask_irq(unsigned irq)
410{
411 struct stmp3xxx_pinmux_bank *pm;
412 unsigned gpio;
413
414 stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
415 __raw_writel(1 << gpio, pm->irqen + HW_STMP3xxx_CLR);
416 __raw_writel(1 << gpio, pm->pin2irq + HW_STMP3xxx_CLR);
417}
418
419static void stmp3xxx_pin_unmask_irq(unsigned irq)
420{
421 struct stmp3xxx_pinmux_bank *pm;
422 unsigned gpio;
423
424 stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
425 __raw_writel(1 << gpio, pm->irqen + HW_STMP3xxx_SET);
426 __raw_writel(1 << gpio, pm->pin2irq + HW_STMP3xxx_SET);
427}
428
429static inline
430struct stmp3xxx_pinmux_bank *to_pinmux_bank(struct gpio_chip *chip)
431{
432 return container_of(chip, struct stmp3xxx_pinmux_bank, chip);
433}
434
435static int stmp3xxx_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
436{
437 struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
438 return pm->virq + offset;
439}
440
441static int stmp3xxx_gpio_get(struct gpio_chip *chip, unsigned offset)
442{
443 struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
444 unsigned v;
445
446 v = __raw_readl(pm->hw_gpio_read) & (1 << offset);
447 return v ? 1 : 0;
448}
449
450static void stmp3xxx_gpio_set(struct gpio_chip *chip, unsigned offset, int v)
451{
452 struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
453
454 __raw_writel(1 << offset, v ? pm->hw_gpio_set : pm->hw_gpio_clr);
455}
456
457static int stmp3xxx_gpio_output(struct gpio_chip *chip, unsigned offset, int v)
458{
459 struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
460
461 __raw_writel(1 << offset, pm->hw_gpio_doe + HW_STMP3xxx_SET);
462 stmp3xxx_gpio_set(chip, offset, v);
463 return 0;
464}
465
466static int stmp3xxx_gpio_input(struct gpio_chip *chip, unsigned offset)
467{
468 struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
469
470 __raw_writel(1 << offset, pm->hw_gpio_doe + HW_STMP3xxx_CLR);
471 return 0;
472}
473
474static int stmp3xxx_gpio_request(struct gpio_chip *chip, unsigned offset)
475{
476 return stmp3xxx_request_pin(chip->base + offset, PIN_GPIO, "gpio");
477}
478
479static void stmp3xxx_gpio_free(struct gpio_chip *chip, unsigned offset)
480{
481 stmp3xxx_release_pin(chip->base + offset, "gpio");
482}
483
484static void stmp3xxx_gpio_irq(u32 irq, struct irq_desc *desc)
485{
486 struct stmp3xxx_pinmux_bank *pm = get_irq_data(irq);
487 int gpio_irq = pm->virq;
488 u32 stat = __raw_readl(pm->irqstat);
489
490 while (stat) {
491 if (stat & 1)
492 irq_desc[gpio_irq].handle_irq(gpio_irq,
493 &irq_desc[gpio_irq]);
494 gpio_irq++;
495 stat >>= 1;
496 }
497}
498
499static struct irq_chip gpio_irq_chip = {
500 .ack = stmp3xxx_pin_ack_irq,
501 .mask = stmp3xxx_pin_mask_irq,
502 .unmask = stmp3xxx_pin_unmask_irq,
503 .set_type = stmp3xxx_set_irqtype,
504};
505
506int __init stmp3xxx_pinmux_init(int virtual_irq_start)
507{
508 int b, r = 0;
509 struct stmp3xxx_pinmux_bank *pm;
510 int virq;
511
512 for (b = 0; b < 3; b++) {
513 /* only banks 0,1,2 are allowed to GPIO */
514 pm = pinmux_banks + b;
515 pm->chip.base = 32 * b;
516 pm->chip.ngpio = 32;
517 pm->chip.owner = THIS_MODULE;
518 pm->chip.can_sleep = 1;
519 pm->chip.exported = 1;
520 pm->chip.to_irq = stmp3xxx_gpio_to_irq;
521 pm->chip.direction_input = stmp3xxx_gpio_input;
522 pm->chip.direction_output = stmp3xxx_gpio_output;
523 pm->chip.get = stmp3xxx_gpio_get;
524 pm->chip.set = stmp3xxx_gpio_set;
525 pm->chip.request = stmp3xxx_gpio_request;
526 pm->chip.free = stmp3xxx_gpio_free;
527 pm->virq = virtual_irq_start + b * 32;
528
529 for (virq = pm->virq; virq < pm->virq; virq++) {
530 gpio_irq_chip.mask(virq);
531 set_irq_chip(virq, &gpio_irq_chip);
532 set_irq_handler(virq, handle_level_irq);
533 set_irq_flags(virq, IRQF_VALID);
534 }
535 r = gpiochip_add(&pm->chip);
536 if (r < 0)
537 break;
538 set_irq_chained_handler(pm->irq, stmp3xxx_gpio_irq);
539 set_irq_data(pm->irq, pm);
540 }
541 return r;
542}
543
544MODULE_AUTHOR("Vladislav Buzov");
545MODULE_LICENSE("GPL");