diff options
Diffstat (limited to 'arch/avr32/mach-at32ap/pio.c')
-rw-r--r-- | arch/avr32/mach-at32ap/pio.c | 172 |
1 files changed, 92 insertions, 80 deletions
diff --git a/arch/avr32/mach-at32ap/pio.c b/arch/avr32/mach-at32ap/pio.c index d61a02da898c..38a8fa31c0b5 100644 --- a/arch/avr32/mach-at32ap/pio.c +++ b/arch/avr32/mach-at32ap/pio.c | |||
@@ -24,11 +24,11 @@ | |||
24 | #define MAX_NR_PIO_DEVICES 8 | 24 | #define MAX_NR_PIO_DEVICES 8 |
25 | 25 | ||
26 | struct pio_device { | 26 | struct pio_device { |
27 | struct gpio_chip chip; | ||
27 | void __iomem *regs; | 28 | void __iomem *regs; |
28 | const struct platform_device *pdev; | 29 | const struct platform_device *pdev; |
29 | struct clk *clk; | 30 | struct clk *clk; |
30 | u32 pinmux_mask; | 31 | u32 pinmux_mask; |
31 | u32 gpio_mask; | ||
32 | char name[8]; | 32 | char name[8]; |
33 | }; | 33 | }; |
34 | 34 | ||
@@ -64,7 +64,8 @@ void __init at32_select_periph(unsigned int pin, unsigned int periph, | |||
64 | goto fail; | 64 | goto fail; |
65 | } | 65 | } |
66 | 66 | ||
67 | if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask))) { | 67 | if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask) |
68 | || gpiochip_is_requested(&pio->chip, pin_index))) { | ||
68 | printk("%s: pin %u is busy\n", pio->name, pin_index); | 69 | printk("%s: pin %u is busy\n", pio->name, pin_index); |
69 | goto fail; | 70 | goto fail; |
70 | } | 71 | } |
@@ -79,9 +80,6 @@ void __init at32_select_periph(unsigned int pin, unsigned int periph, | |||
79 | if (!(flags & AT32_GPIOF_PULLUP)) | 80 | if (!(flags & AT32_GPIOF_PULLUP)) |
80 | pio_writel(pio, PUDR, mask); | 81 | pio_writel(pio, PUDR, mask); |
81 | 82 | ||
82 | /* gpio_request NOT allowed */ | ||
83 | set_bit(pin_index, &pio->gpio_mask); | ||
84 | |||
85 | return; | 83 | return; |
86 | 84 | ||
87 | fail: | 85 | fail: |
@@ -130,9 +128,6 @@ void __init at32_select_gpio(unsigned int pin, unsigned long flags) | |||
130 | 128 | ||
131 | pio_writel(pio, PER, mask); | 129 | pio_writel(pio, PER, mask); |
132 | 130 | ||
133 | /* gpio_request now allowed */ | ||
134 | clear_bit(pin_index, &pio->gpio_mask); | ||
135 | |||
136 | return; | 131 | return; |
137 | 132 | ||
138 | fail: | 133 | fail: |
@@ -166,96 +161,50 @@ fail: | |||
166 | 161 | ||
167 | /* GPIO API */ | 162 | /* GPIO API */ |
168 | 163 | ||
169 | int gpio_request(unsigned int gpio, const char *label) | 164 | static int direction_input(struct gpio_chip *chip, unsigned offset) |
170 | { | 165 | { |
171 | struct pio_device *pio; | 166 | struct pio_device *pio = container_of(chip, struct pio_device, chip); |
172 | unsigned int pin; | 167 | u32 mask = 1 << offset; |
173 | |||
174 | pio = gpio_to_pio(gpio); | ||
175 | if (!pio) | ||
176 | return -ENODEV; | ||
177 | 168 | ||
178 | pin = gpio & 0x1f; | 169 | if (!(pio_readl(pio, PSR) & mask)) |
179 | if (test_and_set_bit(pin, &pio->gpio_mask)) | 170 | return -EINVAL; |
180 | return -EBUSY; | ||
181 | 171 | ||
172 | pio_writel(pio, ODR, mask); | ||
182 | return 0; | 173 | return 0; |
183 | } | 174 | } |
184 | EXPORT_SYMBOL(gpio_request); | ||
185 | 175 | ||
186 | void gpio_free(unsigned int gpio) | 176 | static int gpio_get(struct gpio_chip *chip, unsigned offset) |
187 | { | 177 | { |
188 | struct pio_device *pio; | 178 | struct pio_device *pio = container_of(chip, struct pio_device, chip); |
189 | unsigned int pin; | ||
190 | 179 | ||
191 | pio = gpio_to_pio(gpio); | 180 | return (pio_readl(pio, PDSR) >> offset) & 1; |
192 | if (!pio) { | ||
193 | printk(KERN_ERR | ||
194 | "gpio: attempted to free invalid pin %u\n", gpio); | ||
195 | return; | ||
196 | } | ||
197 | |||
198 | pin = gpio & 0x1f; | ||
199 | if (!test_and_clear_bit(pin, &pio->gpio_mask)) | ||
200 | printk(KERN_ERR "gpio: freeing free or non-gpio pin %s-%u\n", | ||
201 | pio->name, pin); | ||
202 | } | 181 | } |
203 | EXPORT_SYMBOL(gpio_free); | ||
204 | 182 | ||
205 | int gpio_direction_input(unsigned int gpio) | 183 | static void gpio_set(struct gpio_chip *chip, unsigned offset, int value); |
206 | { | ||
207 | struct pio_device *pio; | ||
208 | unsigned int pin; | ||
209 | |||
210 | pio = gpio_to_pio(gpio); | ||
211 | if (!pio) | ||
212 | return -ENODEV; | ||
213 | |||
214 | pin = gpio & 0x1f; | ||
215 | pio_writel(pio, ODR, 1 << pin); | ||
216 | |||
217 | return 0; | ||
218 | } | ||
219 | EXPORT_SYMBOL(gpio_direction_input); | ||
220 | 184 | ||
221 | int gpio_direction_output(unsigned int gpio, int value) | 185 | static int direction_output(struct gpio_chip *chip, unsigned offset, int value) |
222 | { | 186 | { |
223 | struct pio_device *pio; | 187 | struct pio_device *pio = container_of(chip, struct pio_device, chip); |
224 | unsigned int pin; | 188 | u32 mask = 1 << offset; |
225 | |||
226 | pio = gpio_to_pio(gpio); | ||
227 | if (!pio) | ||
228 | return -ENODEV; | ||
229 | 189 | ||
230 | gpio_set_value(gpio, value); | 190 | if (!(pio_readl(pio, PSR) & mask)) |
231 | 191 | return -EINVAL; | |
232 | pin = gpio & 0x1f; | ||
233 | pio_writel(pio, OER, 1 << pin); | ||
234 | 192 | ||
193 | gpio_set(chip, offset, value); | ||
194 | pio_writel(pio, OER, mask); | ||
235 | return 0; | 195 | return 0; |
236 | } | 196 | } |
237 | EXPORT_SYMBOL(gpio_direction_output); | ||
238 | 197 | ||
239 | int gpio_get_value(unsigned int gpio) | 198 | static void gpio_set(struct gpio_chip *chip, unsigned offset, int value) |
240 | { | 199 | { |
241 | struct pio_device *pio = &pio_dev[gpio >> 5]; | 200 | struct pio_device *pio = container_of(chip, struct pio_device, chip); |
201 | u32 mask = 1 << offset; | ||
242 | 202 | ||
243 | return (pio_readl(pio, PDSR) >> (gpio & 0x1f)) & 1; | ||
244 | } | ||
245 | EXPORT_SYMBOL(gpio_get_value); | ||
246 | |||
247 | void gpio_set_value(unsigned int gpio, int value) | ||
248 | { | ||
249 | struct pio_device *pio = &pio_dev[gpio >> 5]; | ||
250 | u32 mask; | ||
251 | |||
252 | mask = 1 << (gpio & 0x1f); | ||
253 | if (value) | 203 | if (value) |
254 | pio_writel(pio, SODR, mask); | 204 | pio_writel(pio, SODR, mask); |
255 | else | 205 | else |
256 | pio_writel(pio, CODR, mask); | 206 | pio_writel(pio, CODR, mask); |
257 | } | 207 | } |
258 | EXPORT_SYMBOL(gpio_set_value); | ||
259 | 208 | ||
260 | /*--------------------------------------------------------------------------*/ | 209 | /*--------------------------------------------------------------------------*/ |
261 | 210 | ||
@@ -339,6 +288,63 @@ gpio_irq_setup(struct pio_device *pio, int irq, int gpio_irq) | |||
339 | 288 | ||
340 | /*--------------------------------------------------------------------------*/ | 289 | /*--------------------------------------------------------------------------*/ |
341 | 290 | ||
291 | #ifdef CONFIG_DEBUG_FS | ||
292 | |||
293 | #include <linux/seq_file.h> | ||
294 | |||
295 | /* | ||
296 | * This shows more info than the generic gpio dump code: | ||
297 | * pullups, deglitching, open drain drive. | ||
298 | */ | ||
299 | static void pio_bank_show(struct seq_file *s, struct gpio_chip *chip) | ||
300 | { | ||
301 | struct pio_device *pio = container_of(chip, struct pio_device, chip); | ||
302 | u32 psr, osr, imr, pdsr, pusr, ifsr, mdsr; | ||
303 | unsigned i; | ||
304 | u32 mask; | ||
305 | char bank; | ||
306 | |||
307 | psr = pio_readl(pio, PSR); | ||
308 | osr = pio_readl(pio, OSR); | ||
309 | imr = pio_readl(pio, IMR); | ||
310 | pdsr = pio_readl(pio, PDSR); | ||
311 | pusr = pio_readl(pio, PUSR); | ||
312 | ifsr = pio_readl(pio, IFSR); | ||
313 | mdsr = pio_readl(pio, MDSR); | ||
314 | |||
315 | bank = 'A' + pio->pdev->id; | ||
316 | |||
317 | for (i = 0, mask = 1; i < 32; i++, mask <<= 1) { | ||
318 | const char *label; | ||
319 | |||
320 | label = gpiochip_is_requested(chip, i); | ||
321 | if (!label) | ||
322 | continue; | ||
323 | |||
324 | seq_printf(s, " gpio-%-3d P%c%-2d (%-12s) %s %s %s", | ||
325 | chip->base + i, bank, i, | ||
326 | label, | ||
327 | (osr & mask) ? "out" : "in ", | ||
328 | (mask & pdsr) ? "hi" : "lo", | ||
329 | (mask & pusr) ? " " : "up"); | ||
330 | if (ifsr & mask) | ||
331 | seq_printf(s, " deglitch"); | ||
332 | if ((osr & mdsr) & mask) | ||
333 | seq_printf(s, " open-drain"); | ||
334 | if (imr & mask) | ||
335 | seq_printf(s, " irq-%d edge-both", | ||
336 | gpio_to_irq(chip->base + i)); | ||
337 | seq_printf(s, "\n"); | ||
338 | } | ||
339 | } | ||
340 | |||
341 | #else | ||
342 | #define pio_bank_show NULL | ||
343 | #endif | ||
344 | |||
345 | |||
346 | /*--------------------------------------------------------------------------*/ | ||
347 | |||
342 | static int __init pio_probe(struct platform_device *pdev) | 348 | static int __init pio_probe(struct platform_device *pdev) |
343 | { | 349 | { |
344 | struct pio_device *pio = NULL; | 350 | struct pio_device *pio = NULL; |
@@ -349,6 +355,18 @@ static int __init pio_probe(struct platform_device *pdev) | |||
349 | pio = &pio_dev[pdev->id]; | 355 | pio = &pio_dev[pdev->id]; |
350 | BUG_ON(!pio->regs); | 356 | BUG_ON(!pio->regs); |
351 | 357 | ||
358 | pio->chip.label = pio->name; | ||
359 | pio->chip.base = pdev->id * 32; | ||
360 | pio->chip.ngpio = 32; | ||
361 | |||
362 | pio->chip.direction_input = direction_input; | ||
363 | pio->chip.get = gpio_get; | ||
364 | pio->chip.direction_output = direction_output; | ||
365 | pio->chip.set = gpio_set; | ||
366 | pio->chip.dbg_show = pio_bank_show; | ||
367 | |||
368 | gpiochip_add(&pio->chip); | ||
369 | |||
352 | gpio_irq_setup(pio, irq, gpio_irq_base); | 370 | gpio_irq_setup(pio, irq, gpio_irq_base); |
353 | 371 | ||
354 | platform_set_drvdata(pdev, pio); | 372 | platform_set_drvdata(pdev, pio); |
@@ -406,12 +424,6 @@ void __init at32_init_pio(struct platform_device *pdev) | |||
406 | pio->pdev = pdev; | 424 | pio->pdev = pdev; |
407 | pio->regs = ioremap(regs->start, regs->end - regs->start + 1); | 425 | pio->regs = ioremap(regs->start, regs->end - regs->start + 1); |
408 | 426 | ||
409 | /* | ||
410 | * request_gpio() is only valid for pins that have been | ||
411 | * explicitly configured as GPIO and not previously requested | ||
412 | */ | ||
413 | pio->gpio_mask = ~0UL; | ||
414 | |||
415 | /* start with irqs disabled and acked */ | 427 | /* start with irqs disabled and acked */ |
416 | pio_writel(pio, IDR, ~0UL); | 428 | pio_writel(pio, IDR, ~0UL); |
417 | (void) pio_readl(pio, ISR); | 429 | (void) pio_readl(pio, ISR); |