Title: [7494] trunk/arch/blackfin: [#5193] BF538/9 PORT C,D,E GPIO support
Revision
7494
Author
hennerich
Date
2009-09-28 08:23:41 -0400 (Mon, 28 Sep 2009)

Log Message

[#5193] BF538/9 PORT C,D,E GPIO support
BF538/9 Port C,D and E are special.
- Inverted PORT_FER polarity on CDE and no PORF_FER on F.
- No Interrupt or wakeup capabilities
- Special registers, incompatible with regular Blackfin GPIOs  

Regular PORT F GPIOs are handled by bfin_gpio, CDE are exclusively 
managed by GPIOLIB. (new file added mach-bf538/ext-gpio.c)
GPIOLIB uses a side entry to bfin_gpio for peripheral 
resource reservation and allocation.
(bfin_special_gpio_request / bfin_special_gpio_free)

Modified Paths

Added Paths

Diff

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;

Modified: trunk/arch/blackfin/mach-bf538/Makefile (7493 => 7494)


--- trunk/arch/blackfin/mach-bf538/Makefile	2009-09-28 10:44:37 UTC (rev 7493)
+++ trunk/arch/blackfin/mach-bf538/Makefile	2009-09-28 12:23:41 UTC (rev 7494)
@@ -3,3 +3,4 @@
 #
 
 obj-y := ints-priority.o dma.o
+obj-$(CONFIG_GPIOLIB)	+= ext-gpio.o

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);

Modified: trunk/arch/blackfin/mach-bf538/include/mach/gpio.h (7493 => 7494)


--- trunk/arch/blackfin/mach-bf538/include/mach/gpio.h	2009-09-28 10:44:37 UTC (rev 7493)
+++ trunk/arch/blackfin/mach-bf538/include/mach/gpio.h	2009-09-28 12:23:41 UTC (rev 7494)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 Analog Devices Inc.
+ * Copyright (C) 2008-2009 Analog Devices Inc.
  * Licensed under the GPL-2 or later.
  */
 
@@ -7,7 +7,8 @@
 #ifndef _MACH_GPIO_H_
 #define _MACH_GPIO_H_
 
-#define MAX_BLACKFIN_GPIOS 64
+#define MAX_BLACKFIN_GPIOS 16
+#define BFIN_SPECIAL_GPIO_BANKS 3
 
 #define	GPIO_PF0	0	/* PF */
 #define	GPIO_PF1	1
@@ -69,4 +70,7 @@
 #define PORT_D GPIO_PD0
 #define PORT_E GPIO_PE0
 
+void bfin_special_gpio_free(unsigned gpio);
+int bfin_special_gpio_request(unsigned gpio, const char *label);
+
 #endif /* _MACH_GPIO_H_ */

Modified: trunk/arch/blackfin/mach-bf538/include/mach/portmux.h (7493 => 7494)


--- trunk/arch/blackfin/mach-bf538/include/mach/portmux.h	2009-09-28 10:44:37 UTC (rev 7493)
+++ trunk/arch/blackfin/mach-bf538/include/mach/portmux.h	2009-09-28 12:23:41 UTC (rev 7494)
@@ -7,7 +7,7 @@
 #ifndef _MACH_PORTMUX_H_
 #define _MACH_PORTMUX_H_
 
-#define MAX_RESOURCES	MAX_BLACKFIN_GPIOS
+#define MAX_RESOURCES	64
 
 #define P_TMR2		(P_DONTCARE)
 #define P_TMR1		(P_DONTCARE)
_______________________________________________
Linux-kernel-commits mailing list
[email protected]
https://blackfin.uclinux.org/mailman/listinfo/linux-kernel-commits

Reply via email to