Pull cpuidle into release branch
[pandora-kernel.git] / arch / blackfin / kernel / bfin_gpio.c
index 0182ce1..ce85d4b 100644 (file)
@@ -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
@@ -80,6 +80,7 @@
 *  GPIO_47      PH15        PF47
 */
 
+#include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/err.h>
 #include <asm/blackfin.h>
 #include <asm/portmux.h>
 #include <linux/irq.h>
 
+#if ANOMALY_05000311 || ANOMALY_05000323
+enum {
+       AWA_data = SYSCR,
+       AWA_data_clear = SYSCR,
+       AWA_data_set = SYSCR,
+       AWA_toggle = SYSCR,
+       AWA_maska = UART_SCR,
+       AWA_maska_clear = UART_SCR,
+       AWA_maska_set = UART_SCR,
+       AWA_maska_toggle = UART_SCR,
+       AWA_maskb = UART_GCTL,
+       AWA_maskb_clear = UART_GCTL,
+       AWA_maskb_set = UART_GCTL,
+       AWA_maskb_toggle = UART_GCTL,
+       AWA_dir = SPORT1_STAT,
+       AWA_polar = SPORT1_STAT,
+       AWA_edge = SPORT1_STAT,
+       AWA_both = SPORT1_STAT,
+#if ANOMALY_05000311
+       AWA_inen = TIMER_ENABLE,
+#elif ANOMALY_05000323
+       AWA_inen = DMA1_1_CONFIG,
+#endif
+};
+       /* Anomaly Workaround */
+#define AWA_DUMMY_READ(name) bfin_read16(AWA_ ## name)
+#else
+#define AWA_DUMMY_READ(...)  do { } while (0)
+#endif
+
 #ifdef BF533_FAMILY
 static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
        (struct gpio_port_t *) FIO_FLAG_D,
 };
 #endif
 
-#ifdef BF537_FAMILY
+#if defined(BF527_FAMILY) || defined(BF537_FAMILY)
 static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
        (struct gpio_port_t *) PORTFIO,
        (struct gpio_port_t *) PORTGIO,
@@ -108,6 +139,21 @@ static unsigned short *port_fer[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
 
 #endif
 
+#ifdef BF527_FAMILY
+static unsigned short *port_mux[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
+       (unsigned short *) PORTF_MUX,
+       (unsigned short *) PORTG_MUX,
+       (unsigned short *) PORTH_MUX,
+};
+
+static const
+u8 pmux_offset[][16] =
+       {{ 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 4, 6, 8, 8, 10, 10 }, /* PORTF */
+        { 0, 0, 0, 0, 0, 2, 2, 4, 4, 6, 8, 10, 10, 10, 12, 12 }, /* PORTG */
+        { 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 4, 4, 4, 4, 4, 4 }, /* PORTH */
+       };
+#endif
+
 #ifdef BF561_FAMILY
 static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
        (struct gpio_port_t *) FIO0_FLAG_D,
@@ -116,6 +162,21 @@ static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
 };
 #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)];
 
@@ -140,18 +201,34 @@ static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG_INTB
 static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG_INTB, IRQ_PORTG_INTB, IRQ_MAC_TX};
 #endif
 
+#ifdef BF527_FAMILY
+static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PORTF_INTB, IRQ_PORTG_INTB, IRQ_PORTH_INTB};
+#endif
+
 #ifdef BF561_FAMILY
 static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG0_INTB, IRQ_PROG1_INTB, IRQ_PROG2_INTB};
 #endif
 
 #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)
 {
@@ -180,23 +257,31 @@ static int cmp_label(unsigned short ident, const char *label)
                return -EINVAL;
 }
 
-#ifdef BF537_FAMILY
+#if defined(BF527_FAMILY) || defined(BF537_FAMILY)
 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;
@@ -267,18 +352,54 @@ static void portmux_setup(unsigned short per, unsigned short function)
                }
        }
 }
+#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);
+}
+#elif defined(BF527_FAMILY)
+inline void portmux_setup(unsigned short portno, unsigned short function)
+{
+       u16 pmux, ident = P_IDENT(portno);
+       u8 offset = pmux_offset[gpio_bank(ident)][gpio_sub_n(ident)];
+
+       pmux = *port_mux[gpio_bank(ident)];
+       pmux &= ~(3 << offset);
+       pmux |= (function & 3) << offset;
+       *port_mux[gpio_bank(ident)] = pmux;
+       SSYNC();
+}
 #else
 # define portmux_setup(...)  do { } while (0)
 #endif
 
+#ifndef BF548_FAMILY
 static void default_gpio(unsigned short gpio)
 {
        unsigned short bank, bitmask;
+       unsigned long flags;
 
        bank = gpio_bank(gpio);
        bitmask = gpio_bit(gpio);
 
+       local_irq_save(flags);
+
        gpio_bankb[bank]->maska_clear = bitmask;
        gpio_bankb[bank]->maskb_clear = bitmask;
        SSYNC();
@@ -287,7 +408,13 @@ static void default_gpio(unsigned short gpio)
        gpio_bankb[bank]->polar &= ~bitmask;
        gpio_bankb[bank]->both &= ~bitmask;
        gpio_bankb[bank]->edge &= ~bitmask;
+       AWA_DUMMY_READ(edge);
+       local_irq_restore(flags);
+
 }
+#else
+# define default_gpio(...)  do { } while (0)
+#endif
 
 static int __init bfin_gpio_init(void)
 {
@@ -306,6 +433,7 @@ static int __init bfin_gpio_init(void)
 arch_initcall(bfin_gpio_init);
 
 
+#ifndef BF548_FAMILY
 /***********************************************************
 *
 * FUNCTIONS: Blackfin General Purpose Ports Access Functions
@@ -335,6 +463,7 @@ void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
                gpio_bankb[gpio_bank(gpio)]->name |= gpio_bit(gpio); \
        else \
                gpio_bankb[gpio_bank(gpio)]->name &= ~gpio_bit(gpio); \
+       AWA_DUMMY_READ(name); \
        local_irq_restore(flags); \
 } \
 EXPORT_SYMBOL(set_gpio_ ## name);
@@ -346,47 +475,46 @@ SET_GPIO(edge)
 SET_GPIO(both)
 
 
+#if ANOMALY_05000311 || ANOMALY_05000323
 #define SET_GPIO_SC(name) \
 void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
 { \
+       unsigned long flags; \
        BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
+       local_irq_save(flags); \
        if (arg) \
                gpio_bankb[gpio_bank(gpio)]->name ## _set = gpio_bit(gpio); \
        else \
                gpio_bankb[gpio_bank(gpio)]->name ## _clear = gpio_bit(gpio); \
+       AWA_DUMMY_READ(name); \
+       local_irq_restore(flags); \
 } \
 EXPORT_SYMBOL(set_gpio_ ## name);
+#else
+#define SET_GPIO_SC(name) \
+void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
+{ \
+       BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
+       if (arg) \
+               gpio_bankb[gpio_bank(gpio)]->name ## _set = gpio_bit(gpio); \
+       else \
+               gpio_bankb[gpio_bank(gpio)]->name ## _clear = gpio_bit(gpio); \
+} \
+EXPORT_SYMBOL(set_gpio_ ## name);
+#endif
 
 SET_GPIO_SC(maska)
 SET_GPIO_SC(maskb)
-
-#if ANOMALY_05000311
-void set_gpio_data(unsigned short gpio, unsigned short arg)
-{
-       unsigned long flags;
-       BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
-       local_irq_save(flags);
-       if (arg)
-               gpio_bankb[gpio_bank(gpio)]->data_set = gpio_bit(gpio);
-       else
-               gpio_bankb[gpio_bank(gpio)]->data_clear = gpio_bit(gpio);
-       bfin_read_CHIPID();
-       local_irq_restore(flags);
-}
-EXPORT_SYMBOL(set_gpio_data);
-#else
 SET_GPIO_SC(data)
-#endif
 
-
-#if ANOMALY_05000311
+#if ANOMALY_05000311 || ANOMALY_05000323
 void set_gpio_toggle(unsigned short gpio)
 {
        unsigned long flags;
        BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
        local_irq_save(flags);
        gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio);
-       bfin_read_CHIPID();
+       AWA_DUMMY_READ(toggle);
        local_irq_restore(flags);
 }
 #else
@@ -401,13 +529,27 @@ EXPORT_SYMBOL(set_gpio_toggle);
 
 /*Set current PORT date (16-bit word)*/
 
+#if ANOMALY_05000311 || ANOMALY_05000323
 #define SET_GPIO_P(name) \
 void set_gpiop_ ## name(unsigned short gpio, unsigned short arg) \
 { \
+       unsigned long flags; \
+       local_irq_save(flags); \
        gpio_bankb[gpio_bank(gpio)]->name = arg; \
+       AWA_DUMMY_READ(name); \
+       local_irq_restore(flags); \
 } \
 EXPORT_SYMBOL(set_gpiop_ ## name);
+#else
+#define SET_GPIO_P(name) \
+void set_gpiop_ ## name(unsigned short gpio, unsigned short arg) \
+{ \
+       gpio_bankb[gpio_bank(gpio)]->name = arg; \
+} \
+EXPORT_SYMBOL(set_gpiop_ ## name);
+#endif
 
+SET_GPIO_P(data)
 SET_GPIO_P(dir)
 SET_GPIO_P(inen)
 SET_GPIO_P(polar)
@@ -417,31 +559,30 @@ SET_GPIO_P(maska)
 SET_GPIO_P(maskb)
 
 
-#if ANOMALY_05000311
-void set_gpiop_data(unsigned short gpio, unsigned short arg)
-{
-       unsigned long flags;
-       local_irq_save(flags);
-       gpio_bankb[gpio_bank(gpio)]->data = arg;
-       bfin_read_CHIPID();
-       local_irq_restore(flags);
-}
-EXPORT_SYMBOL(set_gpiop_data);
-#else
-SET_GPIO_P(data)
-#endif
-
-
-
 /* Get a specific bit */
-
+#if ANOMALY_05000311 || ANOMALY_05000323
+#define GET_GPIO(name) \
+unsigned short get_gpio_ ## name(unsigned short gpio) \
+{ \
+       unsigned long flags; \
+       unsigned short ret; \
+       local_irq_save(flags); \
+       ret = 0x01 & (gpio_bankb[gpio_bank(gpio)]->name >> gpio_sub_n(gpio)); \
+       AWA_DUMMY_READ(name); \
+       local_irq_restore(flags); \
+       return ret; \
+} \
+EXPORT_SYMBOL(get_gpio_ ## name);
+#else
 #define GET_GPIO(name) \
 unsigned short get_gpio_ ## name(unsigned short gpio) \
 { \
        return (0x01 & (gpio_bankb[gpio_bank(gpio)]->name >> gpio_sub_n(gpio))); \
 } \
 EXPORT_SYMBOL(get_gpio_ ## name);
+#endif
 
+GET_GPIO(data)
 GET_GPIO(dir)
 GET_GPIO(inen)
 GET_GPIO(polar)
@@ -450,33 +591,31 @@ GET_GPIO(both)
 GET_GPIO(maska)
 GET_GPIO(maskb)
 
-
-#if ANOMALY_05000311
-unsigned short get_gpio_data(unsigned short gpio)
-{
-       unsigned long flags;
-       unsigned short ret;
-       BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
-       local_irq_save(flags);
-       ret = 0x01 & (gpio_bankb[gpio_bank(gpio)]->data >> gpio_sub_n(gpio));
-       bfin_read_CHIPID();
-       local_irq_restore(flags);
-       return ret;
-}
-EXPORT_SYMBOL(get_gpio_data);
-#else
-GET_GPIO(data)
-#endif
-
 /*Get current PORT date (16-bit word)*/
 
+#if ANOMALY_05000311 || ANOMALY_05000323
+#define GET_GPIO_P(name) \
+unsigned short get_gpiop_ ## name(unsigned short gpio) \
+{ \
+       unsigned long flags; \
+       unsigned short ret; \
+       local_irq_save(flags); \
+       ret = (gpio_bankb[gpio_bank(gpio)]->name); \
+       AWA_DUMMY_READ(name); \
+       local_irq_restore(flags); \
+       return ret; \
+} \
+EXPORT_SYMBOL(get_gpiop_ ## name);
+#else
 #define GET_GPIO_P(name) \
 unsigned short get_gpiop_ ## name(unsigned short gpio) \
 { \
        return (gpio_bankb[gpio_bank(gpio)]->name);\
 } \
 EXPORT_SYMBOL(get_gpiop_ ## name);
+#endif
 
+GET_GPIO_P(data)
 GET_GPIO_P(dir)
 GET_GPIO_P(inen)
 GET_GPIO_P(polar)
@@ -485,21 +624,6 @@ GET_GPIO_P(both)
 GET_GPIO_P(maska)
 GET_GPIO_P(maskb)
 
-#if ANOMALY_05000311
-unsigned short get_gpiop_data(unsigned short gpio)
-{
-       unsigned long flags;
-       unsigned short ret;
-       local_irq_save(flags);
-       ret = gpio_bankb[gpio_bank(gpio)]->data;
-       bfin_read_CHIPID();
-       local_irq_restore(flags);
-       return ret;
-}
-EXPORT_SYMBOL(get_gpiop_data);
-#else
-GET_GPIO_P(data)
-#endif
 
 #ifdef CONFIG_PM
 /***********************************************************
@@ -623,6 +747,8 @@ u32 gpio_pm_setup(void)
                }
        }
 
+       AWA_DUMMY_READ(maskb_set);
+
        if (sic_iwr)
                return sic_iwr;
        else
@@ -654,12 +780,99 @@ void gpio_pm_restore(void)
 
                gpio_bankb[bank]->maskb = gpio_bank_saved[bank].maskb;
        }
+       AWA_DUMMY_READ(maskb);
 }
 
 #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)
 {
@@ -721,8 +934,6 @@ int peripheral_request(unsigned short per, const char *label)
        }
 
 anyway:
-
-
        portmux_setup(per, P_FUNCT2MUX(per));
 
        port_setup(ident, PERIPHERAL_USAGE);
@@ -734,6 +945,7 @@ anyway:
        return 0;
 }
 EXPORT_SYMBOL(peripheral_request);
+#endif
 
 int peripheral_request_list(unsigned short per[], const char *label)
 {
@@ -784,6 +996,8 @@ void peripheral_free(unsigned short per)
 
        reserved_peri_map[gpio_bank(ident)] &= ~gpio_bit(ident);
 
+       set_label(ident, "free");
+
        local_irq_restore(flags);
 }
 EXPORT_SYMBOL(peripheral_free);
@@ -804,8 +1018,8 @@ EXPORT_SYMBOL(peripheral_free_list);
 * 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
 *
@@ -823,17 +1037,39 @@ int gpio_request(unsigned short gpio, const char *label)
 
        local_irq_save(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(flags);
+               return 0;
+       }
+
        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;
 }
@@ -859,10 +1095,57 @@ void gpio_free(unsigned short gpio)
 
        reserved_gpio_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
 
+       set_label(gpio, "free");
+
        local_irq_restore(flags);
 }
 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;
@@ -872,6 +1155,7 @@ void gpio_direction_input(unsigned short gpio)
        local_irq_save(flags);
        gpio_bankb[gpio_bank(gpio)]->dir &= ~gpio_bit(gpio);
        gpio_bankb[gpio_bank(gpio)]->inen |= gpio_bit(gpio);
+       AWA_DUMMY_READ(inen);
        local_irq_restore(flags);
 }
 EXPORT_SYMBOL(gpio_direction_input);
@@ -885,6 +1169,28 @@ void gpio_direction_output(unsigned short gpio)
        local_irq_save(flags);
        gpio_bankb[gpio_bank(gpio)]->inen &= ~gpio_bit(gpio);
        gpio_bankb[gpio_bank(gpio)]->dir |= gpio_bit(gpio);
+       AWA_DUMMY_READ(dir);
        local_irq_restore(flags);
 }
 EXPORT_SYMBOL(gpio_direction_output);
+
+/* If we are booting from SPI and our board lacks a strong enough pull up,
+ * the core can reset and execute the bootrom faster than the resistor can
+ * pull the signal logically high.  To work around this (common) error in
+ * board design, we explicitly set the pin back to GPIO mode, force /CS
+ * high, and wait for the electrons to do their thing.
+ *
+ * This function only makes sense to be called from reset code, but it
+ * lives here as we need to force all the GPIO states w/out going through
+ * BUG() checks and such.
+ */
+void bfin_gpio_reset_spi0_ssel1(void)
+{
+       u16 gpio = P_IDENT(P_SPI0_SSEL1);
+
+       port_setup(gpio, GPIO_USAGE);
+       gpio_bankb[gpio_bank(gpio)]->data_set = gpio_bit(gpio);
+       udelay(1);
+}
+
+#endif /*BF548_FAMILY */