diff options
Diffstat (limited to 'arch/avr32/mach-at32ap/pio.c')
-rw-r--r-- | arch/avr32/mach-at32ap/pio.c | 85 |
1 files changed, 78 insertions, 7 deletions
diff --git a/arch/avr32/mach-at32ap/pio.c b/arch/avr32/mach-at32ap/pio.c index d3aabfca8598..f1280ed8ed6d 100644 --- a/arch/avr32/mach-at32ap/pio.c +++ b/arch/avr32/mach-at32ap/pio.c | |||
@@ -25,27 +25,98 @@ struct pio_device { | |||
25 | void __iomem *regs; | 25 | void __iomem *regs; |
26 | const struct platform_device *pdev; | 26 | const struct platform_device *pdev; |
27 | struct clk *clk; | 27 | struct clk *clk; |
28 | u32 alloc_mask; | 28 | u32 pinmux_mask; |
29 | char name[32]; | 29 | char name[32]; |
30 | }; | 30 | }; |
31 | 31 | ||
32 | static struct pio_device pio_dev[MAX_NR_PIO_DEVICES]; | 32 | static struct pio_device pio_dev[MAX_NR_PIO_DEVICES]; |
33 | 33 | ||
34 | void portmux_set_func(unsigned int portmux_id, unsigned int pin_id, | 34 | static struct pio_device *gpio_to_pio(unsigned int gpio) |
35 | unsigned int function_id) | ||
36 | { | 35 | { |
37 | struct pio_device *pio; | 36 | struct pio_device *pio; |
38 | u32 mask = 1 << pin_id; | 37 | unsigned int index; |
39 | 38 | ||
40 | BUG_ON(portmux_id >= MAX_NR_PIO_DEVICES); | 39 | index = gpio >> 5; |
40 | if (index >= MAX_NR_PIO_DEVICES) | ||
41 | return NULL; | ||
42 | pio = &pio_dev[index]; | ||
43 | if (!pio->regs) | ||
44 | return NULL; | ||
41 | 45 | ||
42 | pio = &pio_dev[portmux_id]; | 46 | return pio; |
47 | } | ||
48 | |||
49 | /* Pin multiplexing API */ | ||
50 | |||
51 | void __init at32_select_periph(unsigned int pin, unsigned int periph, | ||
52 | unsigned long flags) | ||
53 | { | ||
54 | struct pio_device *pio; | ||
55 | unsigned int pin_index = pin & 0x1f; | ||
56 | u32 mask = 1 << pin_index; | ||
57 | |||
58 | pio = gpio_to_pio(pin); | ||
59 | if (unlikely(!pio)) { | ||
60 | printk("pio: invalid pin %u\n", pin); | ||
61 | goto fail; | ||
62 | } | ||
43 | 63 | ||
44 | if (function_id) | 64 | if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask))) { |
65 | printk("%s: pin %u is busy\n", pio->name, pin_index); | ||
66 | goto fail; | ||
67 | } | ||
68 | |||
69 | pio_writel(pio, PUER, mask); | ||
70 | if (periph) | ||
45 | pio_writel(pio, BSR, mask); | 71 | pio_writel(pio, BSR, mask); |
46 | else | 72 | else |
47 | pio_writel(pio, ASR, mask); | 73 | pio_writel(pio, ASR, mask); |
74 | |||
48 | pio_writel(pio, PDR, mask); | 75 | pio_writel(pio, PDR, mask); |
76 | if (!(flags & AT32_GPIOF_PULLUP)) | ||
77 | pio_writel(pio, PUDR, mask); | ||
78 | |||
79 | return; | ||
80 | |||
81 | fail: | ||
82 | dump_stack(); | ||
83 | } | ||
84 | |||
85 | void __init at32_select_gpio(unsigned int pin, unsigned long flags) | ||
86 | { | ||
87 | struct pio_device *pio; | ||
88 | unsigned int pin_index = pin & 0x1f; | ||
89 | u32 mask = 1 << pin_index; | ||
90 | |||
91 | pio = gpio_to_pio(pin); | ||
92 | if (unlikely(!pio)) { | ||
93 | printk("pio: invalid pin %u\n", pin); | ||
94 | goto fail; | ||
95 | } | ||
96 | |||
97 | if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask))) { | ||
98 | printk("%s: pin %u is busy\n", pio->name, pin_index); | ||
99 | goto fail; | ||
100 | } | ||
101 | |||
102 | pio_writel(pio, PUER, mask); | ||
103 | if (flags & AT32_GPIOF_HIGH) | ||
104 | pio_writel(pio, SODR, mask); | ||
105 | else | ||
106 | pio_writel(pio, CODR, mask); | ||
107 | if (flags & AT32_GPIOF_OUTPUT) | ||
108 | pio_writel(pio, OER, mask); | ||
109 | else | ||
110 | pio_writel(pio, ODR, mask); | ||
111 | |||
112 | pio_writel(pio, PER, mask); | ||
113 | if (!(flags & AT32_GPIOF_PULLUP)) | ||
114 | pio_writel(pio, PUDR, mask); | ||
115 | |||
116 | return; | ||
117 | |||
118 | fail: | ||
119 | dump_stack(); | ||
49 | } | 120 | } |
50 | 121 | ||
51 | static int __init pio_probe(struct platform_device *pdev) | 122 | static int __init pio_probe(struct platform_device *pdev) |