X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=arch%2Fblackfin%2Fkernel%2Fbfin_gpio.c;h=3fe0cd49e8db51736620acd924f1457c88b02e42;hb=19ad7ae47e4ce4eb2a583e437d653a96da7897ac;hp=d9284d7dc9fc824a25355c6674bb9962258c7c41;hpb=168f1212c098727f2509fe0f66bd30d7209a8159;p=pandora-kernel.git diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c index d9284d7dc9fc..3fe0cd49e8db 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 @@ -88,6 +88,36 @@ #include #include +#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, @@ -117,6 +147,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)]; @@ -147,12 +192,24 @@ static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG0_INT #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 +242,27 @@ static int cmp_label(unsigned short ident, const char *label) 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,18 +333,42 @@ 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); +} #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(); @@ -288,7 +377,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) { @@ -307,6 +402,7 @@ static int __init bfin_gpio_init(void) arch_initcall(bfin_gpio_init); +#ifndef BF548_FAMILY /*********************************************************** * * FUNCTIONS: Blackfin General Purpose Ports Access Functions @@ -336,6 +432,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); @@ -347,47 +444,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 @@ -402,13 +498,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) @@ -418,31 +528,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) @@ -451,33 +560,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) @@ -486,21 +593,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 /*********************************************************** @@ -624,6 +716,8 @@ u32 gpio_pm_setup(void) } } + AWA_DUMMY_READ(maskb_set); + if (sic_iwr) return sic_iwr; else @@ -655,12 +749,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) { @@ -722,8 +903,6 @@ int peripheral_request(unsigned short per, const char *label) } anyway: - - portmux_setup(per, P_FUNCT2MUX(per)); port_setup(ident, PERIPHERAL_USAGE); @@ -735,6 +914,7 @@ anyway: return 0; } EXPORT_SYMBOL(peripheral_request); +#endif int peripheral_request_list(unsigned short per[], const char *label) { @@ -785,6 +965,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); @@ -805,8 +987,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 * @@ -824,17 +1006,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; } @@ -860,10 +1064,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; @@ -873,6 +1124,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); @@ -886,6 +1138,7 @@ 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); @@ -902,7 +1155,11 @@ EXPORT_SYMBOL(gpio_direction_output); */ void bfin_gpio_reset_spi0_ssel1(void) { - port_setup(P_SPI0_SSEL1, GPIO_USAGE); - gpio_bankb[gpio_bank(P_SPI0_SSEL1)]->data_set = gpio_bit(P_SPI0_SSEL1); + 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 */