Blackfin arch: Merge GPIO/Peripheral Resource Allocation back into a single file

Signed-off-by: Michael Hennerich <michale.hennerich@analog.com>
Signed-off-by: Bryan Wu <bryan.wu@analog.com>

diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c
index 0d1e87b..78438d8 100644
--- a/arch/blackfin/kernel/bfin_gpio.c
+++ b/arch/blackfin/kernel/bfin_gpio.c
@@ -7,7 +7,7 @@
  * Description:  GPIO Abstraction Layer
  *
  * Modified:
- *               Copyright 2006 Analog Devices Inc.
+ *               Copyright 2007 Analog Devices Inc.
  *
  * Bugs:         Enter bugs at http://blackfin.uclinux.org/
  *
@@ -28,9 +28,9 @@
  */
 
 /*
-*  Number     BF537/6/4    BF561    BF533/2/1
+*  Number     BF537/6/4    BF561    BF533/2/1	   BF549/8/4/2
 *
-*  GPIO_0       PF0         PF0        PF0
+*  GPIO_0       PF0         PF0        PF0	   PA0...PJ13
 *  GPIO_1       PF1         PF1        PF1
 *  GPIO_2       PF2         PF2        PF2
 *  GPIO_3       PF3         PF3        PF3
@@ -117,6 +117,21 @@
 };
 #endif
 
+#ifdef BF548_FAMILY
+static struct gpio_port_t *gpio_array[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
+	(struct gpio_port_t *)PORTA_FER,
+	(struct gpio_port_t *)PORTB_FER,
+	(struct gpio_port_t *)PORTC_FER,
+	(struct gpio_port_t *)PORTD_FER,
+	(struct gpio_port_t *)PORTE_FER,
+	(struct gpio_port_t *)PORTF_FER,
+	(struct gpio_port_t *)PORTG_FER,
+	(struct gpio_port_t *)PORTH_FER,
+	(struct gpio_port_t *)PORTI_FER,
+	(struct gpio_port_t *)PORTJ_FER,
+};
+#endif
+
 static unsigned short reserved_gpio_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
 static unsigned short reserved_peri_map[gpio_bank(MAX_BLACKFIN_GPIOS + 16)];
 
@@ -147,12 +162,24 @@
 
 #endif /* CONFIG_PM */
 
+#if defined(BF548_FAMILY)
+inline int check_gpio(unsigned short gpio)
+{
+	if (gpio == GPIO_PB15 || gpio == GPIO_PC14 || gpio == GPIO_PC15
+	    || gpio == GPIO_PH14 || gpio == GPIO_PH15
+	    || gpio == GPIO_PJ14 || gpio == GPIO_PJ15
+	    || gpio > MAX_BLACKFIN_GPIOS)
+		return -EINVAL;
+	return 0;
+}
+#else
 inline int check_gpio(unsigned short gpio)
 {
 	if (gpio >= MAX_BLACKFIN_GPIOS)
 		return -EINVAL;
 	return 0;
 }
+#endif
 
 static void set_label(unsigned short ident, const char *label)
 {
@@ -185,19 +212,27 @@
 static void port_setup(unsigned short gpio, unsigned short usage)
 {
 	if (!check_gpio(gpio)) {
-		if (usage == GPIO_USAGE) {
+		if (usage == GPIO_USAGE)
 			*port_fer[gpio_bank(gpio)] &= ~gpio_bit(gpio);
-		} else
+		else
 			*port_fer[gpio_bank(gpio)] |= gpio_bit(gpio);
 		SSYNC();
 	}
 }
+#elif defined(BF548_FAMILY)
+static void port_setup(unsigned short gpio, unsigned short usage)
+{
+	if (usage == GPIO_USAGE)
+		gpio_array[gpio_bank(gpio)]->port_fer &= ~gpio_bit(gpio);
+	else
+		gpio_array[gpio_bank(gpio)]->port_fer |= gpio_bit(gpio);
+	SSYNC();
+}
 #else
 # define port_setup(...)  do { } while (0)
 #endif
 
 #ifdef BF537_FAMILY
-
 static struct {
 	unsigned short res;
 	unsigned short offset;
@@ -268,11 +303,32 @@
 		}
 	}
 }
+#elif defined(BF548_FAMILY)
+inline void portmux_setup(unsigned short portno, unsigned short function)
+{
+	u32 pmux;
 
+	pmux = gpio_array[gpio_bank(portno)]->port_mux;
+
+	pmux &= ~(0x3 << (2 * gpio_sub_n(portno)));
+	pmux |= (function & 0x3) << (2 * gpio_sub_n(portno));
+
+	gpio_array[gpio_bank(portno)]->port_mux = pmux;
+}
+
+inline u16 get_portmux(unsigned short portno)
+{
+	u32 pmux;
+
+	pmux = gpio_array[gpio_bank(portno)]->port_mux;
+
+	return (pmux >> (2 * gpio_sub_n(portno)) & 0x3);
+}
 #else
 # define portmux_setup(...)  do { } while (0)
 #endif
 
+#ifndef BF548_FAMILY
 static void default_gpio(unsigned short gpio)
 {
 	unsigned short bank, bitmask;
@@ -289,6 +345,9 @@
 	gpio_bankb[bank]->both &= ~bitmask;
 	gpio_bankb[bank]->edge &= ~bitmask;
 }
+#else
+# define default_gpio(...)  do { } while (0)
+#endif
 
 static int __init bfin_gpio_init(void)
 {
@@ -307,6 +366,7 @@
 arch_initcall(bfin_gpio_init);
 
 
+#ifndef BF548_FAMILY
 /***********************************************************
 *
 * FUNCTIONS: Blackfin General Purpose Ports Access Functions
@@ -658,9 +718,95 @@
 }
 
 #endif
+#endif /* BF548_FAMILY */
 
+/***********************************************************
+*
+* FUNCTIONS: 	Blackfin Peripheral Resource Allocation
+*		and PortMux Setup
+*
+* INPUTS/OUTPUTS:
+* per	Peripheral Identifier
+* label	String
+*
+* DESCRIPTION: Blackfin Peripheral Resource Allocation and Setup API
+*
+* CAUTION:
+*************************************************************
+* MODIFICATION HISTORY :
+**************************************************************/
 
+#ifdef BF548_FAMILY
+int peripheral_request(unsigned short per, const char *label)
+{
+	unsigned long flags;
+	unsigned short ident = P_IDENT(per);
 
+	/*
+	 * Don't cares are pins with only one dedicated function
+	 */
+
+	if (per & P_DONTCARE)
+		return 0;
+
+	if (!(per & P_DEFINED))
+		return -ENODEV;
+
+	if (check_gpio(ident) < 0)
+		return -EINVAL;
+
+	local_irq_save(flags);
+
+	if (unlikely(reserved_gpio_map[gpio_bank(ident)] & gpio_bit(ident))) {
+		printk(KERN_ERR
+		    "%s: Peripheral %d is already reserved as GPIO by %s !\n",
+		       __FUNCTION__, ident, get_label(ident));
+		dump_stack();
+		local_irq_restore(flags);
+		return -EBUSY;
+	}
+
+	if (unlikely(reserved_peri_map[gpio_bank(ident)] & gpio_bit(ident))) {
+
+		u16 funct = get_portmux(ident);
+
+	/*
+	 * Pin functions like AMC address strobes my
+	 * be requested and used by several drivers
+	 */
+
+		if (!((per & P_MAYSHARE) && (funct == P_FUNCT2MUX(per)))) {
+
+		/*
+		 * Allow that the identical pin function can
+		 * be requested from the same driver twice
+		 */
+
+		if (cmp_label(ident, label) == 0)
+			goto anyway;
+
+			printk(KERN_ERR
+			       "%s: Peripheral %d function %d is already reserved by %s !\n",
+			       __FUNCTION__, ident, P_FUNCT2MUX(per), get_label(ident));
+			dump_stack();
+			local_irq_restore(flags);
+			return -EBUSY;
+		}
+	}
+
+anyway:
+	reserved_peri_map[gpio_bank(ident)] |= gpio_bit(ident);
+
+	portmux_setup(ident, P_FUNCT2MUX(per));
+	port_setup(ident, PERIPHERAL_USAGE);
+
+	local_irq_restore(flags);
+	set_label(ident, label);
+
+	return 0;
+}
+EXPORT_SYMBOL(peripheral_request);
+#else
 
 int peripheral_request(unsigned short per, const char *label)
 {
@@ -722,8 +868,6 @@
 	}
 
 anyway:
-
-
 	portmux_setup(per, P_FUNCT2MUX(per));
 
 	port_setup(ident, PERIPHERAL_USAGE);
@@ -735,6 +879,7 @@
 	return 0;
 }
 EXPORT_SYMBOL(peripheral_request);
+#endif
 
 int peripheral_request_list(unsigned short per[], const char *label)
 {
@@ -805,8 +950,8 @@
 * FUNCTIONS: Blackfin GPIO Driver
 *
 * INPUTS/OUTPUTS:
-* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS
-*
+* gpio	PIO Number between 0 and MAX_BLACKFIN_GPIOS
+* label	String
 *
 * DESCRIPTION: Blackfin GPIO Driver API
 *
@@ -825,16 +970,27 @@
 	local_irq_save(flags);
 
 	if (unlikely(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
-		printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved!\n", gpio);
+		printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved by %s !\n",
+			 gpio, get_label(gpio));
 		dump_stack();
 		local_irq_restore(flags);
 		return -EBUSY;
 	}
+	if (unlikely(reserved_peri_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
+		printk(KERN_ERR
+		       "bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n",
+		       gpio, get_label(gpio));
+		dump_stack();
+		local_irq_restore(flags);
+		return -EBUSY;
+	}
+
 	reserved_gpio_map[gpio_bank(gpio)] |= gpio_bit(gpio);
 
 	local_irq_restore(flags);
 
 	port_setup(gpio, GPIO_USAGE);
+	set_label(gpio, label);
 
 	return 0;
 }
@@ -864,6 +1020,51 @@
 }
 EXPORT_SYMBOL(gpio_free);
 
+#ifdef BF548_FAMILY
+void gpio_direction_input(unsigned short gpio)
+{
+	unsigned long flags;
+
+	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+
+	local_irq_save(flags);
+	gpio_array[gpio_bank(gpio)]->port_dir_clear = gpio_bit(gpio);
+	gpio_array[gpio_bank(gpio)]->port_inen |= gpio_bit(gpio);
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL(gpio_direction_input);
+
+void gpio_direction_output(unsigned short gpio)
+{
+	unsigned long flags;
+
+	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+
+	local_irq_save(flags);
+	gpio_array[gpio_bank(gpio)]->port_inen &= ~gpio_bit(gpio);
+	gpio_array[gpio_bank(gpio)]->port_dir_set = gpio_bit(gpio);
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL(gpio_direction_output);
+
+void gpio_set_value(unsigned short gpio, unsigned short arg)
+{
+	if (arg)
+		gpio_array[gpio_bank(gpio)]->port_set = gpio_bit(gpio);
+	else
+		gpio_array[gpio_bank(gpio)]->port_clear = gpio_bit(gpio);
+
+}
+EXPORT_SYMBOL(gpio_set_value);
+
+unsigned short gpio_get_value(unsigned short gpio)
+{
+	return (1 & (gpio_array[gpio_bank(gpio)]->port_data >> gpio_sub_n(gpio)));
+}
+EXPORT_SYMBOL(gpio_get_value);
+
+#else
+
 void gpio_direction_input(unsigned short gpio)
 {
 	unsigned long flags;
@@ -908,3 +1109,5 @@
 	gpio_bankb[gpio_bank(gpio)]->data_set = gpio_bit(gpio);
 	udelay(1);
 }
+
+#endif /*BF548_FAMILY */