123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- /*
- * Atmel PIO2 Port Multiplexer support
- *
- * Copyright (C) 2004-2006 Atmel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
- #include <linux/clk.h>
- #include <linux/debugfs.h>
- #include <linux/export.h>
- #include <linux/fs.h>
- #include <linux/platform_device.h>
- #include <linux/irq.h>
- #include <asm/gpio.h>
- #include <asm/io.h>
- #include <mach/portmux.h>
- #include "pio.h"
- #define MAX_NR_PIO_DEVICES 8
- struct pio_device {
- struct gpio_chip chip;
- void __iomem *regs;
- const struct platform_device *pdev;
- struct clk *clk;
- u32 pinmux_mask;
- char name[8];
- };
- static struct pio_device pio_dev[MAX_NR_PIO_DEVICES];
- static struct pio_device *gpio_to_pio(unsigned int gpio)
- {
- struct pio_device *pio;
- unsigned int index;
- index = gpio >> 5;
- if (index >= MAX_NR_PIO_DEVICES)
- return NULL;
- pio = &pio_dev[index];
- if (!pio->regs)
- return NULL;
- return pio;
- }
- /* Pin multiplexing API */
- static DEFINE_SPINLOCK(pio_lock);
- void __init at32_select_periph(unsigned int port, u32 pin_mask,
- unsigned int periph, unsigned long flags)
- {
- struct pio_device *pio;
- /* assign and verify pio */
- pio = gpio_to_pio(port);
- if (unlikely(!pio)) {
- printk(KERN_WARNING "pio: invalid port %u\n", port);
- goto fail;
- }
- /* Test if any of the requested pins is already muxed */
- spin_lock(&pio_lock);
- if (unlikely(pio->pinmux_mask & pin_mask)) {
- printk(KERN_WARNING "%s: pin(s) busy (requested 0x%x, busy 0x%x)\n",
- pio->name, pin_mask, pio->pinmux_mask & pin_mask);
- spin_unlock(&pio_lock);
- goto fail;
- }
- pio->pinmux_mask |= pin_mask;
- /* enable pull ups */
- pio_writel(pio, PUER, pin_mask);
- /* select either peripheral A or B */
- if (periph)
- pio_writel(pio, BSR, pin_mask);
- else
- pio_writel(pio, ASR, pin_mask);
- /* enable peripheral control */
- pio_writel(pio, PDR, pin_mask);
- /* Disable pull ups if not requested. */
- if (!(flags & AT32_GPIOF_PULLUP))
- pio_writel(pio, PUDR, pin_mask);
- spin_unlock(&pio_lock);
- return;
- fail:
- dump_stack();
- }
- void __init at32_select_gpio(unsigned int pin, unsigned long flags)
- {
- struct pio_device *pio;
- unsigned int pin_index = pin & 0x1f;
- u32 mask = 1 << pin_index;
- pio = gpio_to_pio(pin);
- if (unlikely(!pio)) {
- printk("pio: invalid pin %u\n", pin);
- goto fail;
- }
- if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask))) {
- printk("%s: pin %u is busy\n", pio->name, pin_index);
- goto fail;
- }
- if (flags & AT32_GPIOF_OUTPUT) {
- if (flags & AT32_GPIOF_HIGH)
- pio_writel(pio, SODR, mask);
- else
- pio_writel(pio, CODR, mask);
- if (flags & AT32_GPIOF_MULTIDRV)
- pio_writel(pio, MDER, mask);
- else
- pio_writel(pio, MDDR, mask);
- pio_writel(pio, PUDR, mask);
- pio_writel(pio, OER, mask);
- } else {
- if (flags & AT32_GPIOF_PULLUP)
- pio_writel(pio, PUER, mask);
- else
- pio_writel(pio, PUDR, mask);
- if (flags & AT32_GPIOF_DEGLITCH)
- pio_writel(pio, IFER, mask);
- else
- pio_writel(pio, IFDR, mask);
- pio_writel(pio, ODR, mask);
- }
- pio_writel(pio, PER, mask);
- return;
- fail:
- dump_stack();
- }
- /*
- * Undo a previous pin reservation. Will not affect the hardware
- * configuration.
- */
- void at32_deselect_pin(unsigned int pin)
- {
- struct pio_device *pio;
- unsigned int pin_index = pin & 0x1f;
- pio = gpio_to_pio(pin);
- if (unlikely(!pio)) {
|