* Description: GPIO Abstraction Layer
*
* Modified:
- * Copyright 2006 Analog Devices Inc.
+ * Copyright 2007 Analog Devices Inc.
*
* Bugs: Enter bugs at http://blackfin.uclinux.org/
*
*/
/*
-* 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
* GPIO_47 PH15 PF47
*/
+#include <linux/delay.h>
#include <linux/module.h>
#include <linux/err.h>
#include <asm/blackfin.h>
#include <asm/gpio.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,
#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,
};
#endif
-static unsigned short reserved_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
+#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)];
+
+#define MAX_RESOURCES 256
+#define RESOURCE_LABEL_SIZE 16
+
+struct str_ident {
+ char name[RESOURCE_LABEL_SIZE];
+} *str_ident;
+
#ifdef CONFIG_PM
static unsigned short wakeup_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
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
-#ifdef BF537_FAMILY
+static void set_label(unsigned short ident, const char *label)
+{
+
+ if (label && str_ident) {
+ strncpy(str_ident[ident].name, label,
+ RESOURCE_LABEL_SIZE);
+ str_ident[ident].name[RESOURCE_LABEL_SIZE - 1] = 0;
+ }
+}
+
+static char *get_label(unsigned short ident)
+{
+ if (!str_ident)
+ return "UNKNOWN";
+
+ return (*str_ident[ident].name ? str_ident[ident].name : "UNKNOWN");
+}
+
+static int cmp_label(unsigned short ident, const char *label)
+{
+ if (label && str_ident)
+ return strncmp(str_ident[ident].name,
+ label, strlen(label));
+ else
+ return -EINVAL;
+}
+
+#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)
+ *port_fer[gpio_bank(gpio)] &= ~gpio_bit(gpio);
+ 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) {
- if (*port_fer[gpio_bank(gpio)] & gpio_bit(gpio))
- printk(KERN_WARNING "bfin-gpio: Possible Conflict with Peripheral "
- "usage and GPIO %d detected!\n", gpio);
- *port_fer[gpio_bank(gpio)] &= ~gpio_bit(gpio);
- } else
- *port_fer[gpio_bank(gpio)] |= gpio_bit(gpio);
+ 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;
+} port_mux_lut[] = {
+ {.res = P_PPI0_D13, .offset = 11},
+ {.res = P_PPI0_D14, .offset = 11},
+ {.res = P_PPI0_D15, .offset = 11},
+ {.res = P_SPORT1_TFS, .offset = 11},
+ {.res = P_SPORT1_TSCLK, .offset = 11},
+ {.res = P_SPORT1_DTPRI, .offset = 11},
+ {.res = P_PPI0_D10, .offset = 10},
+ {.res = P_PPI0_D11, .offset = 10},
+ {.res = P_PPI0_D12, .offset = 10},
+ {.res = P_SPORT1_RSCLK, .offset = 10},
+ {.res = P_SPORT1_RFS, .offset = 10},
+ {.res = P_SPORT1_DRPRI, .offset = 10},
+ {.res = P_PPI0_D8, .offset = 9},
+ {.res = P_PPI0_D9, .offset = 9},
+ {.res = P_SPORT1_DRSEC, .offset = 9},
+ {.res = P_SPORT1_DTSEC, .offset = 9},
+ {.res = P_TMR2, .offset = 8},
+ {.res = P_PPI0_FS3, .offset = 8},
+ {.res = P_TMR3, .offset = 7},
+ {.res = P_SPI0_SSEL4, .offset = 7},
+ {.res = P_TMR4, .offset = 6},
+ {.res = P_SPI0_SSEL5, .offset = 6},
+ {.res = P_TMR5, .offset = 5},
+ {.res = P_SPI0_SSEL6, .offset = 5},
+ {.res = P_UART1_RX, .offset = 4},
+ {.res = P_UART1_TX, .offset = 4},
+ {.res = P_TMR6, .offset = 4},
+ {.res = P_TMR7, .offset = 4},
+ {.res = P_UART0_RX, .offset = 3},
+ {.res = P_UART0_TX, .offset = 3},
+ {.res = P_DMAR0, .offset = 3},
+ {.res = P_DMAR1, .offset = 3},
+ {.res = P_SPORT0_DTSEC, .offset = 1},
+ {.res = P_SPORT0_DRSEC, .offset = 1},
+ {.res = P_CAN0_RX, .offset = 1},
+ {.res = P_CAN0_TX, .offset = 1},
+ {.res = P_SPI0_SSEL7, .offset = 1},
+ {.res = P_SPORT0_TFS, .offset = 0},
+ {.res = P_SPORT0_DTPRI, .offset = 0},
+ {.res = P_SPI0_SSEL2, .offset = 0},
+ {.res = P_SPI0_SSEL3, .offset = 0},
+};
+
+static void portmux_setup(unsigned short per, unsigned short function)
+{
+ u16 y, offset, muxreg;
+
+ for (y = 0; y < ARRAY_SIZE(port_mux_lut); y++) {
+ if (port_mux_lut[y].res == per) {
+
+ /* SET PORTMUX REG */
+
+ offset = port_mux_lut[y].offset;
+ muxreg = bfin_read_PORT_MUX();
+
+ if (offset != 1) {
+ muxreg &= ~(1 << offset);
+ } else {
+ muxreg &= ~(3 << 1);
+ }
+
+ muxreg |= (function << offset);
+ bfin_write_PORT_MUX(muxreg);
+ }
+ }
+}
+#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();
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)
{
- int i;
+ str_ident = kcalloc(MAX_RESOURCES,
+ sizeof(struct str_ident), GFP_KERNEL);
+ if (str_ident == NULL)
+ return -ENOMEM;
- printk(KERN_INFO "Blackfin GPIO Controller\n");
-
- for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE)
- reserved_map[gpio_bank(i)] = 0;
+ memset(str_ident, 0, MAX_RESOURCES * sizeof(struct str_ident));
-#if defined(BF537_FAMILY) && (defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
-# if defined(CONFIG_BFIN_MAC_RMII)
- reserved_map[gpio_bank(PORT_H)] = 0xC373;
-# else
- reserved_map[gpio_bank(PORT_H)] = 0xFFFF;
-# endif
-#endif
+ printk(KERN_INFO "Blackfin GPIO Controller\n");
return 0;
-}
+}
arch_initcall(bfin_gpio_init);
+#ifndef BF548_FAMILY
/***********************************************************
*
* FUNCTIONS: Blackfin General Purpose Ports Access Functions
void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
{ \
unsigned long flags; \
- BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
local_irq_save(flags); \
if (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);
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_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
+ 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 defined(ANOMALY_05000311)
-void set_gpio_data(unsigned short gpio, unsigned short arg)
-{
- unsigned long flags;
- BUG_ON(!(reserved_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 defined(ANOMALY_05000311)
+#if ANOMALY_05000311 || ANOMALY_05000323
void set_gpio_toggle(unsigned short gpio)
{
unsigned long flags;
- BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+ 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
void set_gpio_toggle(unsigned short gpio)
{
- BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio);
}
#endif
/*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)
SET_GPIO_P(maskb)
-#if defined(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)
GET_GPIO(maska)
GET_GPIO(maskb)
-
-#if defined(ANOMALY_05000311)
-unsigned short get_gpio_data(unsigned short gpio)
-{
- unsigned long flags;
- unsigned short ret;
- BUG_ON(!(reserved_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)
GET_GPIO_P(maska)
GET_GPIO_P(maskb)
-#if defined(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
/***********************************************************
gpio_bank_saved[bank].dir = gpio_bankb[bank]->dir;
gpio_bank_saved[bank].edge = gpio_bankb[bank]->edge;
gpio_bank_saved[bank].both = gpio_bankb[bank]->both;
- gpio_bank_saved[bank].reserved = reserved_map[bank];
+ gpio_bank_saved[bank].reserved =
+ reserved_gpio_map[bank];
gpio = i;
while (mask) {
if (mask & 1) {
- reserved_map[gpio_bank(gpio)] |=
+ reserved_gpio_map[gpio_bank(gpio)] |=
gpio_bit(gpio);
bfin_gpio_wakeup_type(gpio,
wakeup_flags_map[gpio]);
}
}
+ AWA_DUMMY_READ(maskb_set);
+
if (sic_iwr)
return sic_iwr;
else
gpio_bankb[bank]->edge = gpio_bank_saved[bank].edge;
gpio_bankb[bank]->both = gpio_bank_saved[bank].both;
- reserved_map[bank] = gpio_bank_saved[bank].reserved;
+ reserved_gpio_map[bank] =
+ gpio_bank_saved[bank].reserved;
}
gpio_bankb[bank]->maskb = gpio_bank_saved[bank].maskb;
}
+ AWA_DUMMY_READ(maskb);
}
#endif
+#endif /* BF548_FAMILY */
/***********************************************************
*
-* FUNCTIONS: Blackfin GPIO Driver
+* FUNCTIONS: Blackfin Peripheral Resource Allocation
+* and PortMux Setup
*
* INPUTS/OUTPUTS:
-* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS
+* 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)
+{
+ 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;
+
+ local_irq_save(flags);
+
+ if (!check_gpio(ident)) {
+
+ 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))) {
+
+ /*
+ * Pin functions like AMC address strobes my
+ * be requested and used by several drivers
+ */
+
+ if (!(per & P_MAYSHARE)) {
+
+ /*
+ * 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:
+ portmux_setup(per, P_FUNCT2MUX(per));
+
+ port_setup(ident, PERIPHERAL_USAGE);
+
+ reserved_peri_map[gpio_bank(ident)] |= gpio_bit(ident);
+ local_irq_restore(flags);
+ set_label(ident, label);
+
+ return 0;
+}
+EXPORT_SYMBOL(peripheral_request);
+#endif
+
+int peripheral_request_list(unsigned short per[], const char *label)
+{
+ u16 cnt;
+ int ret;
+
+ for (cnt = 0; per[cnt] != 0; cnt++) {
+
+ ret = peripheral_request(per[cnt], label);
+
+ if (ret < 0) {
+ for ( ; cnt > 0; cnt--) {
+ peripheral_free(per[cnt - 1]);
+ }
+ return ret;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(peripheral_request_list);
+
+void peripheral_free(unsigned short per)
+{
+ unsigned long flags;
+ unsigned short ident = P_IDENT(per);
+
+ if (per & P_DONTCARE)
+ return;
+
+ if (!(per & P_DEFINED))
+ return;
+
+ if (check_gpio(ident) < 0)
+ return;
+
+ local_irq_save(flags);
+
+ if (unlikely(!(reserved_peri_map[gpio_bank(ident)]
+ & gpio_bit(ident)))) {
+ local_irq_restore(flags);
+ return;
+ }
+
+ if (!(per & P_MAYSHARE)) {
+ port_setup(ident, GPIO_USAGE);
+ }
+
+ reserved_peri_map[gpio_bank(ident)] &= ~gpio_bit(ident);
+
+ set_label(ident, "free");
+
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL(peripheral_free);
+
+void peripheral_free_list(unsigned short per[])
+{
+ u16 cnt;
+
+ for (cnt = 0; per[cnt] != 0; cnt++) {
+ peripheral_free(per[cnt]);
+ }
+
+}
+EXPORT_SYMBOL(peripheral_free_list);
+
+/***********************************************************
+*
+* FUNCTIONS: Blackfin GPIO Driver
+*
+* INPUTS/OUTPUTS:
+* gpio PIO Number between 0 and MAX_BLACKFIN_GPIOS
+* label String
*
* DESCRIPTION: Blackfin GPIO Driver API
*
local_irq_save(flags);
- if (unlikely(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
- printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved!\n", gpio);
+ /*
+ * 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 by %s !\n",
+ gpio, get_label(gpio));
dump_stack();
local_irq_restore(flags);
return -EBUSY;
}
- reserved_map[gpio_bank(gpio)] |= gpio_bit(gpio);
+ 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;
}
local_irq_save(flags);
- if (unlikely(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)))) {
+ if (unlikely(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)))) {
printk(KERN_ERR "bfin-gpio: GPIO %d wasn't reserved!\n", gpio);
dump_stack();
local_irq_restore(flags);
default_gpio(gpio);
- reserved_map[gpio_bank(gpio)] &= ~gpio_bit(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;
- BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(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);
{
unsigned long flags;
- BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(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 */