Modified: trunk/arch/blackfin/kernel/bfin_gpio.c (7493 => 7494)
--- trunk/arch/blackfin/kernel/bfin_gpio.c 2009-09-28 10:44:37 UTC (rev 7493)
+++ trunk/arch/blackfin/kernel/bfin_gpio.c 2009-09-28 12:23:41 UTC (rev 7494)
@@ -100,6 +100,12 @@
};
# endif
+#elif defined(BF538_FAMILY)
+static unsigned short * const port_fer[] = {
+ (unsigned short *) PORTCIO_FER,
+ (unsigned short *) PORTDIO_FER,
+ (unsigned short *) PORTEIO_FER,
+};
#endif
static unsigned short reserved_gpio_map[GPIO_BANK_NUM];
@@ -163,6 +169,27 @@
static void port_setup(unsigned gpio, unsigned short usage)
{
+#if defined(BF538_FAMILY)
+ /*
+ * BF538/9 Port C,D and E are special.
+ * Inverted PORT_FER polarity on CDE and no PORF_FER on F
+ * Regular PORT F GPIOs are handled here, CDE are exclusively
+ * managed by GPIOLIB
+ */
+
+ if (gpio < MAX_BLACKFIN_GPIOS || gpio >= MAX_RESOURCES)
+ return;
+
+ gpio -= MAX_BLACKFIN_GPIOS;
+
+ if (usage == GPIO_USAGE)
+ *port_fer[gpio_bank(gpio)] |= gpio_bit(gpio);
+ else
+ *port_fer[gpio_bank(gpio)] &= ~gpio_bit(gpio);
+ SSYNC();
+ return;
+#endif
+
if (check_gpio(gpio))
return;
@@ -981,6 +1008,76 @@
}
EXPORT_SYMBOL(bfin_gpio_free);
+#ifdef BFIN_SPECIAL_GPIO_BANKS
+static unsigned short reserved_special_gpio_map[gpio_bank(MAX_RESOURCES)];
+
+int bfin_special_gpio_request(unsigned gpio, const char *label)
+{
+ unsigned long flags;
+
+ local_irq_save_hw(flags);
+
+ /*
+ * Allow that the identical GPIO can
+ * be requested from the same driver twice
+ * Do nothing and return -
+ */
+
+ if (cmp_label(gpio, label) == 0) {
+ local_irq_restore_hw(flags);
+ return 0;
+ }
+
+ if (unlikely(reserved_special_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
+ local_irq_restore_hw(flags);
+ printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved by %s !\n",
+ gpio, get_label(gpio));
+
+ return -EBUSY;
+ }
+ if (unlikely(reserved_peri_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
+ local_irq_restore_hw(flags);
+ printk(KERN_ERR
+ "bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n",
+ gpio, get_label(gpio));
+
+ return -EBUSY;
+ }
+
+ reserved_special_gpio_map[gpio_bank(gpio)] |= gpio_bit(gpio);
+ reserved_peri_map[gpio_bank(gpio)] |= gpio_bit(gpio);
+
+ set_label(gpio, label);
+ local_irq_restore_hw(flags);
+ port_setup(gpio, GPIO_USAGE);
+
+ return 0;
+}
+EXPORT_SYMBOL(bfin_special_gpio_request);
+
+void bfin_special_gpio_free(unsigned gpio)
+{
+ unsigned long flags;
+
+ might_sleep();
+
+ local_irq_save_hw(flags);
+
+ if (unlikely(!(reserved_special_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)))) {
+ gpio_error(gpio);
+ local_irq_restore_hw(flags);
+ return;
+ }
+
+ reserved_special_gpio_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
+ reserved_peri_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
+ set_label(gpio, "free");
+ local_irq_restore_hw(flags);
+}
+EXPORT_SYMBOL(bfin_special_gpio_free);
+#endif
+
+
int bfin_gpio_irq_request(unsigned gpio, const char *label)
{
unsigned long flags;
Added: trunk/arch/blackfin/mach-bf538/ext-gpio.c (0 => 7494)
--- trunk/arch/blackfin/mach-bf538/ext-gpio.c (rev 0)
+++ trunk/arch/blackfin/mach-bf538/ext-gpio.c 2009-09-28 12:23:41 UTC (rev 7494)
@@ -0,0 +1,193 @@
+/*
+ * GPIOLIB interface for BF538/9 PORT C,D and E GPIOs
+ *
+ * Copyright 2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <asm/blackfin.h>
+#include <asm/gpio.h>
+#include <asm/portmux.h>
+
+#define DEFINE_REG(reg, off) \
+static inline u16 read_##reg(void __iomem *port) \
+ { return bfin_read16(port + off); } \
+static inline void write_##reg(void __iomem *port, u16 v) \
+ { bfin_write16(port + off, v); }
+
+DEFINE_REG(PORTIO, 0x00)
+DEFINE_REG(PORTIO_CLEAR, 0x10)
+DEFINE_REG(PORTIO_SET, 0x20)
+DEFINE_REG(PORTIO_DIR, 0x40)
+DEFINE_REG(PORTIO_INEN, 0x50)
+
+int bf538_gpio_get_value(void __iomem *port, unsigned gpio)
+{
+ return !!(read_PORTIO(port) & (1u << gpio));
+}
+
+void bf538_gpio_set_value(void __iomem *port, unsigned gpio, int value)
+{
+ if (value)
+ write_PORTIO_SET(port, (1u << gpio));
+ else
+ write_PORTIO_CLEAR(port, (1u << gpio));
+}
+
+int bf538_gpio_direction_input(void __iomem *port, unsigned gpio)
+{
+ write_PORTIO_DIR(port, read_PORTIO_DIR(port) & ~(1u << gpio));
+ write_PORTIO_INEN(port, read_PORTIO_INEN(port) | (1u << gpio));
+
+ return 0;
+}
+
+int bf538_gpio_direction_output(void __iomem *port, unsigned gpio, int value)
+{
+ write_PORTIO_INEN(port, read_PORTIO_INEN(port) & ~(1u << gpio));
+ bf538_gpio_set_value(port, gpio, value);
+ write_PORTIO_DIR(port, read_PORTIO_DIR(port) | (1u << gpio));
+
+ return 0;
+}
+
+/*
+ * PORTCIO
+ */
+
+int bf538_extgpio_portc_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+ return bf538_gpio_direction_input((void __iomem *)PORTCIO, gpio);
+}
+
+int bf538_extgpio_portc_direction_output(struct gpio_chip *chip, unsigned gpio,
+ int level)
+{
+ return bf538_gpio_direction_output((void __iomem *)PORTCIO, gpio,
+ level);
+}
+
+int bf538_extgpio_portc_get_value(struct gpio_chip *chip, unsigned gpio)
+{
+ return bf538_gpio_get_value((void __iomem *)PORTCIO, gpio);
+}
+
+void bf538_extgpio_portc_set_value(struct gpio_chip *chip, unsigned gpio,
+ int value)
+{
+ return bf538_gpio_set_value((void __iomem *)PORTCIO, gpio, value);
+}
+
+/*
+ * PORTDIO
+ */
+
+int bf538_extgpio_portd_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+ return bf538_gpio_direction_input((void __iomem *)PORTDIO, gpio);
+}
+
+int bf538_extgpio_portd_direction_output(struct gpio_chip *chip, unsigned gpio,
+ int level)
+{
+ return bf538_gpio_direction_output((void __iomem *)PORTDIO, gpio,
+ level);
+}
+
+int bf538_extgpio_portd_get_value(struct gpio_chip *chip, unsigned gpio)
+{
+ return bf538_gpio_get_value((void __iomem *)PORTDIO, gpio);
+}
+
+void bf538_extgpio_portd_set_value(struct gpio_chip *chip, unsigned gpio,
+ int value)
+{
+ return bf538_gpio_set_value((void __iomem *)PORTDIO, gpio, value);
+}
+
+/*
+ * PORTEIO
+ */
+
+int bf538_extgpio_porte_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+ return bf538_gpio_direction_input((void __iomem *)PORTEIO, gpio);
+}
+
+int bf538_extgpio_porte_direction_output(struct gpio_chip *chip, unsigned gpio,
+ int level)
+{
+ return bf538_gpio_direction_output((void __iomem *)PORTEIO, gpio,
+ level);
+}
+
+int bf538_extgpio_porte_get_value(struct gpio_chip *chip, unsigned gpio)
+{
+ return bf538_gpio_get_value((void __iomem *)PORTEIO, gpio);
+}
+
+void bf538_extgpio_porte_set_value(struct gpio_chip *chip, unsigned gpio,
+ int value)
+{
+ return bf538_gpio_set_value((void __iomem *)PORTEIO, gpio, value);
+}
+
+int bf538_extgpio_gpio_request(struct gpio_chip *chip, unsigned gpio)
+{
+ return bfin_special_gpio_request(chip->base + gpio, chip->label);
+}
+
+void bf538_extgpio_gpio_free(struct gpio_chip *chip, unsigned gpio)
+{
+ return bfin_special_gpio_free(chip->base + gpio);
+}
+
+static struct gpio_chip bf538_portc_chip = {
+ .label = "GPIO-PC",
+ .direction_input = bf538_extgpio_portc_direction_input,
+ .get = bf538_extgpio_portc_get_value,
+ .direction_output = bf538_extgpio_portc_direction_output,
+ .set = bf538_extgpio_portc_set_value,
+ .request = bf538_extgpio_gpio_request,
+ .free = bf538_extgpio_gpio_free,
+ .base = GPIO_PC0,
+ .ngpio = GPIO_PC9 - GPIO_PC0 + 1,
+};
+
+static struct gpio_chip bf538_portd_chip = {
+ .label = "GPIO-PD",
+ .direction_input = bf538_extgpio_portd_direction_input,
+ .get = bf538_extgpio_portd_get_value,
+ .direction_output = bf538_extgpio_portd_direction_output,
+ .set = bf538_extgpio_portd_set_value,
+ .request = bf538_extgpio_gpio_request,
+ .free = bf538_extgpio_gpio_free,
+ .base = GPIO_PD0,
+ .ngpio = GPIO_PD13 - GPIO_PD0 + 1,
+};
+
+static struct gpio_chip bf538_porte_chip = {
+ .label = "GPIO-PE",
+ .direction_input = bf538_extgpio_porte_direction_input,
+ .get = bf538_extgpio_porte_get_value,
+ .direction_output = bf538_extgpio_porte_direction_output,
+ .set = bf538_extgpio_porte_set_value,
+ .request = bf538_extgpio_gpio_request,
+ .free = bf538_extgpio_gpio_free,
+ .base = GPIO_PE0,
+ .ngpio = GPIO_PE15 - GPIO_PE0 + 1,
+};
+
+static int __init bf538_extgpio_setup(void)
+{
+ gpiochip_add(&bf538_portc_chip);
+ gpiochip_add(&bf538_portd_chip);
+ gpiochip_add(&bf538_porte_chip);
+
+ return 0;
+}
+
+arch_initcall(bf538_extgpio_setup);