diff options
Diffstat (limited to 'arch/blackfin/kernel/bfin_gpio.c')
| -rw-r--r-- | arch/blackfin/kernel/bfin_gpio.c | 791 |
1 files changed, 356 insertions, 435 deletions
diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c index a0678da4053..a017359c182 100644 --- a/arch/blackfin/kernel/bfin_gpio.c +++ b/arch/blackfin/kernel/bfin_gpio.c @@ -1,39 +1,17 @@ /* - * File: arch/blackfin/kernel/bfin_gpio.c - * Based on: - * Author: Michael Hennerich (hennerich@blackfin.uclinux.org) + * GPIO Abstraction Layer * - * Created: - * Description: GPIO Abstraction Layer + * Copyright 2006-2010 Analog Devices Inc. * - * Modified: - * Copyright 2008 Analog Devices Inc. - * - * Bugs: Enter bugs at http://blackfin.uclinux.org/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see the file COPYING, or write - * to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * Licensed under the GPL-2 or later */ #include <linux/delay.h> #include <linux/module.h> #include <linux/err.h> #include <linux/proc_fs.h> -#include <asm/blackfin.h> -#include <asm/gpio.h> -#include <asm/portmux.h> +#include <linux/seq_file.h> +#include <linux/gpio.h> #include <linux/irq.h> #if ANOMALY_05000311 || ANOMALY_05000323 @@ -77,17 +55,6 @@ static struct gpio_port_t * const gpio_array[] = { (struct gpio_port_t *) FIO0_FLAG_D, (struct gpio_port_t *) FIO1_FLAG_D, (struct gpio_port_t *) FIO2_FLAG_D, -#elif defined(CONFIG_BF54x) - (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, #else # error no gpio arrays defined #endif @@ -121,13 +88,15 @@ u8 pmux_offset[][16] = { }; # 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]; -static unsigned short reserved_peri_map[gpio_bank(MAX_RESOURCES)]; -static unsigned short reserved_gpio_irq_map[GPIO_BANK_NUM]; - -#define RESOURCE_LABEL_SIZE 16 +#define RESOURCE_LABEL_SIZE 16 static struct str_ident { char name[RESOURCE_LABEL_SIZE]; @@ -135,21 +104,11 @@ static struct str_ident { #if defined(CONFIG_PM) static struct gpio_port_s gpio_bank_saved[GPIO_BANK_NUM]; +# ifdef BF538_FAMILY +static unsigned short port_fer_saved[3]; +# endif #endif -inline int check_gpio(unsigned gpio) -{ -#if defined(CONFIG_BF54x) - if (gpio == GPIO_PB15 || gpio == GPIO_PC14 || gpio == GPIO_PC15 - || gpio == GPIO_PH14 || gpio == GPIO_PH15 - || gpio == GPIO_PJ14 || gpio == GPIO_PJ15) - return -EINVAL; -#endif - if (gpio >= MAX_BLACKFIN_GPIOS) - return -EINVAL; - return 0; -} - static void gpio_error(unsigned gpio) { printk(KERN_ERR "bfin-gpio: GPIO %d wasn't requested!\n", gpio); @@ -182,8 +141,46 @@ static int cmp_label(unsigned short ident, const char *label) return -EINVAL; } +#define map_entry(m, i) reserved_##m##_map[gpio_bank(i)] +#define is_reserved(m, i, e) (map_entry(m, i) & gpio_bit(i)) +#define reserve(m, i) (map_entry(m, i) |= gpio_bit(i)) +#define unreserve(m, i) (map_entry(m, i) &= ~gpio_bit(i)) +#define DECLARE_RESERVED_MAP(m, c) static unsigned short reserved_##m##_map[c] + +DECLARE_RESERVED_MAP(gpio, GPIO_BANK_NUM); +DECLARE_RESERVED_MAP(peri, DIV_ROUND_UP(MAX_RESOURCES, GPIO_BANKSIZE)); +DECLARE_RESERVED_MAP(gpio_irq, GPIO_BANK_NUM); + +inline int check_gpio(unsigned gpio) +{ + if (gpio >= MAX_BLACKFIN_GPIOS) + return -EINVAL; + return 0; +} + 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; @@ -193,117 +190,134 @@ static void port_setup(unsigned gpio, unsigned short usage) else *port_fer[gpio_bank(gpio)] |= gpio_bit(gpio); SSYNC(); -#elif defined(CONFIG_BF54x) - 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(); #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 const s8 port_mux[] = { + [GPIO_PF0] = 3, + [GPIO_PF1] = 3, + [GPIO_PF2] = 4, + [GPIO_PF3] = 4, + [GPIO_PF4] = 5, + [GPIO_PF5] = 6, + [GPIO_PF6] = 7, + [GPIO_PF7] = 8, + [GPIO_PF8 ... GPIO_PF15] = -1, + [GPIO_PG0 ... GPIO_PG7] = -1, + [GPIO_PG8] = 9, + [GPIO_PG9] = 9, + [GPIO_PG10] = 10, + [GPIO_PG11] = 10, + [GPIO_PG12] = 10, + [GPIO_PG13] = 11, + [GPIO_PG14] = 11, + [GPIO_PG15] = 11, + [GPIO_PH0 ... GPIO_PH15] = -1, + [PORT_PJ0 ... PORT_PJ3] = -1, + [PORT_PJ4] = 1, + [PORT_PJ5] = 1, + [PORT_PJ6 ... PORT_PJ9] = -1, + [PORT_PJ10] = 0, + [PORT_PJ11] = 0, }; -static void portmux_setup(unsigned short per) +static int portmux_group_check(unsigned short per) { - u16 y, offset, muxreg; + u16 ident = P_IDENT(per); u16 function = P_FUNCT2MUX(per); + s8 offset = port_mux[ident]; + u16 m, pmux, pfunc, mask; - for (y = 0; y < ARRAY_SIZE(port_mux_lut); y++) { - if (port_mux_lut[y].res == per) { - - /* SET PORTMUX REG */ + if (offset < 0) + return 0; - offset = port_mux_lut[y].offset; - muxreg = bfin_read_PORT_MUX(); + pmux = bfin_read_PORT_MUX(); + for (m = 0; m < ARRAY_SIZE(port_mux); ++m) { + if (m == ident) + continue; + if (port_mux[m] != offset) + continue; + if (!is_reserved(peri, m, 1)) + continue; - if (offset != 1) - muxreg &= ~(1 << offset); - else - muxreg &= ~(3 << 1); + if (offset == 1) + mask = 3; + else + mask = 1; - muxreg |= (function << offset); - bfin_write_PORT_MUX(muxreg); + pfunc = (pmux >> offset) & mask; + if (pfunc != (function & mask)) { + pr_err("pin group conflict! request pin %d func %d conflict with pin %d func %d\n", + ident, function, m, pfunc); + return -EINVAL; } } + + return 0; } -#elif defined(CONFIG_BF54x) -inline void portmux_setup(unsigned short per) + +static void portmux_setup(unsigned short per) { - u32 pmux; u16 ident = P_IDENT(per); u16 function = P_FUNCT2MUX(per); + s8 offset = port_mux[ident]; + u16 pmux, mask; - pmux = gpio_array[gpio_bank(ident)]->port_mux; + if (offset == -1) + return; + + pmux = bfin_read_PORT_MUX(); + if (offset == 1) + mask = 3; + else + mask = 1; - pmux &= ~(0x3 << (2 * gpio_sub_n(ident))); - pmux |= (function & 0x3) << (2 * gpio_sub_n(ident)); + pmux &= ~(mask << offset); + pmux |= ((function & mask) << offset); - gpio_array[gpio_bank(ident)]->port_mux = pmux; + bfin_write_PORT_MUX(pmux); } - -inline u16 get_portmux(unsigned short per) +#elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x) +static int portmux_group_check(unsigned short per) { - u32 pmux; u16 ident = P_IDENT(per); + u16 function = P_FUNCT2MUX(per); + u8 offset = pmux_offset[gpio_bank(ident)][gpio_sub_n(ident)]; + u16 pin, gpiopin, pfunc; - pmux = gpio_array[gpio_bank(ident)]->port_mux; + for (pin = 0; pin < GPIO_BANKSIZE; ++pin) { + if (offset != pmux_offset[gpio_bank(ident)][pin]) + continue; - return (pmux >> (2 * gpio_sub_n(ident)) & 0x3); + gpiopin = gpio_bank(ident) * GPIO_BANKSIZE + pin; + if (gpiopin == ident) + continue; + if (!is_reserved(peri, gpiopin, 1)) + continue; + + pfunc = *port_mux[gpio_bank(ident)]; + pfunc = (pfunc >> offset) & 3; + if (pfunc != function) { + pr_err("pin group conflict! request pin %d func %d conflict with pin %d func %d\n", + ident, function, gpiopin, pfunc); + return -EINVAL; + } + } + + return 0; } -#elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x) + inline void portmux_setup(unsigned short per) { - u16 pmux, ident = P_IDENT(per), function = P_FUNCT2MUX(per); + u16 ident = P_IDENT(per); + u16 function = P_FUNCT2MUX(per); u8 offset = pmux_offset[gpio_bank(ident)][gpio_sub_n(ident)]; + u16 pmux; pmux = *port_mux[gpio_bank(ident)]; + if (((pmux >> offset) & 3) == function) + return; pmux &= ~(3 << offset); pmux |= (function & 3) << offset; *port_mux[gpio_bank(ident)] = pmux; @@ -311,18 +325,12 @@ inline void portmux_setup(unsigned short per) } #else # define portmux_setup(...) do { } while (0) -#endif - -static int __init bfin_gpio_init(void) +static int portmux_group_check(unsigned short per) { - printk(KERN_INFO "Blackfin GPIO Controller\n"); - return 0; } -arch_initcall(bfin_gpio_init); - +#endif -#ifndef CONFIG_BF54x /*********************************************************** * * FUNCTIONS: Blackfin General Purpose Ports Access Functions @@ -346,13 +354,13 @@ arch_initcall(bfin_gpio_init); void set_gpio_ ## name(unsigned gpio, unsigned short arg) \ { \ unsigned long flags; \ - local_irq_save_hw(flags); \ + flags = hard_local_irq_save(); \ if (arg) \ gpio_array[gpio_bank(gpio)]->name |= gpio_bit(gpio); \ else \ gpio_array[gpio_bank(gpio)]->name &= ~gpio_bit(gpio); \ AWA_DUMMY_READ(name); \ - local_irq_restore_hw(flags); \ + hard_local_irq_restore(flags); \ } \ EXPORT_SYMBOL(set_gpio_ ## name); @@ -368,14 +376,14 @@ void set_gpio_ ## name(unsigned gpio, unsigned short arg) \ { \ unsigned long flags; \ if (ANOMALY_05000311 || ANOMALY_05000323) \ - local_irq_save_hw(flags); \ + flags = hard_local_irq_save(); \ if (arg) \ gpio_array[gpio_bank(gpio)]->name ## _set = gpio_bit(gpio); \ else \ gpio_array[gpio_bank(gpio)]->name ## _clear = gpio_bit(gpio); \ if (ANOMALY_05000311 || ANOMALY_05000323) { \ AWA_DUMMY_READ(name); \ - local_irq_restore_hw(flags); \ + hard_local_irq_restore(flags); \ } \ } \ EXPORT_SYMBOL(set_gpio_ ## name); @@ -388,11 +396,11 @@ void set_gpio_toggle(unsigned gpio) { unsigned long flags; if (ANOMALY_05000311 || ANOMALY_05000323) - local_irq_save_hw(flags); + flags = hard_local_irq_save(); gpio_array[gpio_bank(gpio)]->toggle = gpio_bit(gpio); if (ANOMALY_05000311 || ANOMALY_05000323) { AWA_DUMMY_READ(toggle); - local_irq_restore_hw(flags); + hard_local_irq_restore(flags); } } EXPORT_SYMBOL(set_gpio_toggle); @@ -405,11 +413,11 @@ void set_gpiop_ ## name(unsigned gpio, unsigned short arg) \ { \ unsigned long flags; \ if (ANOMALY_05000311 || ANOMALY_05000323) \ - local_irq_save_hw(flags); \ + flags = hard_local_irq_save(); \ gpio_array[gpio_bank(gpio)]->name = arg; \ if (ANOMALY_05000311 || ANOMALY_05000323) { \ AWA_DUMMY_READ(name); \ - local_irq_restore_hw(flags); \ + hard_local_irq_restore(flags); \ } \ } \ EXPORT_SYMBOL(set_gpiop_ ## name); @@ -430,11 +438,11 @@ unsigned short get_gpio_ ## name(unsigned gpio) \ unsigned long flags; \ unsigned short ret; \ if (ANOMALY_05000311 || ANOMALY_05000323) \ - local_irq_save_hw(flags); \ + flags = hard_local_irq_save(); \ ret = 0x01 & (gpio_array[gpio_bank(gpio)]->name >> gpio_sub_n(gpio)); \ if (ANOMALY_05000311 || ANOMALY_05000323) { \ AWA_DUMMY_READ(name); \ - local_irq_restore_hw(flags); \ + hard_local_irq_restore(flags); \ } \ return ret; \ } \ @@ -457,11 +465,11 @@ unsigned short get_gpiop_ ## name(unsigned gpio) \ unsigned long flags; \ unsigned short ret; \ if (ANOMALY_05000311 || ANOMALY_05000323) \ - local_irq_save_hw(flags); \ + flags = hard_local_irq_save(); \ ret = (gpio_array[gpio_bank(gpio)]->name); \ if (ANOMALY_05000311 || ANOMALY_05000323) { \ AWA_DUMMY_READ(name); \ - local_irq_restore_hw(flags); \ + hard_local_irq_restore(flags); \ } \ return ret; \ } \ @@ -478,15 +486,13 @@ GET_GPIO_P(maskb) #ifdef CONFIG_PM - -static unsigned short wakeup_map[GPIO_BANK_NUM]; -static unsigned char wakeup_flags_map[MAX_BLACKFIN_GPIOS]; +DECLARE_RESERVED_MAP(wakeup, GPIO_BANK_NUM); static const unsigned int sic_iwr_irqs[] = { #if defined(BF533_FAMILY) IRQ_PROG_INTB #elif defined(BF537_FAMILY) - IRQ_PROG_INTB, IRQ_PORTG_INTB, IRQ_MAC_TX + IRQ_PF_INTB_WATCH, IRQ_PORTG_INTB, IRQ_PH_INTB_MAC_TX #elif defined(BF538_FAMILY) IRQ_PORTF_INTB #elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x) @@ -517,143 +523,48 @@ static const unsigned int sic_iwr_irqs[] = { ************************************************************* * MODIFICATION HISTORY : **************************************************************/ -int gpio_pm_wakeup_request(unsigned gpio, unsigned char type) -{ - unsigned long flags; - - if ((check_gpio(gpio) < 0) || !type) - return -EINVAL; - - local_irq_save_hw(flags); - wakeup_map[gpio_bank(gpio)] |= gpio_bit(gpio); - wakeup_flags_map[gpio] = type; - local_irq_restore_hw(flags); - - return 0; -} -EXPORT_SYMBOL(gpio_pm_wakeup_request); - -void gpio_pm_wakeup_free(unsigned gpio) +int bfin_gpio_pm_wakeup_ctrl(unsigned gpio, unsigned ctrl) { unsigned long flags; if (check_gpio(gpio) < 0) - return; - - local_irq_save_hw(flags); - - wakeup_map[gpio_bank(gpio)] &= ~gpio_bit(gpio); - - local_irq_restore_hw(flags); -} -EXPORT_SYMBOL(gpio_pm_wakeup_free); - -static int bfin_gpio_wakeup_type(unsigned gpio, unsigned char type) -{ - port_setup(gpio, GPIO_USAGE); - set_gpio_dir(gpio, 0); - set_gpio_inen(gpio, 1); - - if (type & (PM_WAKE_RISING | PM_WAKE_FALLING)) - set_gpio_edge(gpio, 1); - else - set_gpio_edge(gpio, 0); - - if ((type & (PM_WAKE_BOTH_EDGES)) == (PM_WAKE_BOTH_EDGES)) - set_gpio_both(gpio, 1); - else - set_gpio_both(gpio, 0); + return -EINVAL; - if ((type & (PM_WAKE_FALLING | PM_WAKE_LOW))) - set_gpio_polar(gpio, 1); + flags = hard_local_irq_save(); + if (ctrl) + reserve(wakeup, gpio); else - set_gpio_polar(gpio, 0); + unreserve(wakeup, gpio); - SSYNC(); + set_gpio_maskb(gpio, ctrl); + hard_local_irq_restore(flags); return 0; } -u32 bfin_pm_standby_setup(void) -{ - u16 bank, mask, i, gpio; - - for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) { - mask = wakeup_map[gpio_bank(i)]; - bank = gpio_bank(i); - - gpio_bank_saved[bank].maskb = gpio_array[bank]->maskb; - gpio_array[bank]->maskb = 0; - - if (mask) { -#if defined(CONFIG_BF52x) || defined(BF537_FAMILY) || defined(CONFIG_BF51x) - gpio_bank_saved[bank].fer = *port_fer[bank]; -#endif - gpio_bank_saved[bank].inen = gpio_array[bank]->inen; - gpio_bank_saved[bank].polar = gpio_array[bank]->polar; - gpio_bank_saved[bank].dir = gpio_array[bank]->dir; - gpio_bank_saved[bank].edge = gpio_array[bank]->edge; - gpio_bank_saved[bank].both = gpio_array[bank]->both; - gpio_bank_saved[bank].reserved = - reserved_gpio_map[bank]; - - gpio = i; - - while (mask) { - if ((mask & 1) && (wakeup_flags_map[gpio] != - PM_WAKE_IGNORE)) { - reserved_gpio_map[gpio_bank(gpio)] |= - gpio_bit(gpio); - bfin_gpio_wakeup_type(gpio, - wakeup_flags_map[gpio]); - set_gpio_data(gpio, 0); /*Clear*/ - } - gpio++; - mask >>= 1; - } - - bfin_internal_set_wake(sic_iwr_irqs[bank], 1); - gpio_array[bank]->maskb_set = wakeup_map[gpio_bank(i)]; - } - } - - AWA_DUMMY_READ(maskb_set); - - return 0; -} - -void bfin_pm_standby_restore(void) +int bfin_gpio_pm_standby_ctrl(unsigned ctrl) { u16 bank, mask, i; for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) { - mask = wakeup_map[gpio_bank(i)]; + mask = map_entry(wakeup, i); bank = gpio_bank(i); - if (mask) { -#if defined(CONFIG_BF52x) || defined(BF537_FAMILY) || defined(CONFIG_BF51x) - *port_fer[bank] = gpio_bank_saved[bank].fer; -#endif - gpio_array[bank]->inen = gpio_bank_saved[bank].inen; - gpio_array[bank]->dir = gpio_bank_saved[bank].dir; - gpio_array[bank]->polar = gpio_bank_saved[bank].polar; - gpio_array[bank]->edge = gpio_bank_saved[bank].edge; - gpio_array[bank]->both = gpio_bank_saved[bank].both; - - reserved_gpio_map[bank] = - gpio_bank_saved[bank].reserved; - bfin_internal_set_wake(sic_iwr_irqs[bank], 0); - } - - gpio_array[bank]->maskb = gpio_bank_saved[bank].maskb; + if (mask) + bfin_internal_set_wake(sic_iwr_irqs[bank], ctrl); } - AWA_DUMMY_READ(maskb); + return 0; } void bfin_gpio_pm_hibernate_suspend(void) { int i, bank; +#ifdef BF538_FAMILY + for (i = 0; i < ARRAY_SIZE(port_fer_saved); ++i) + port_fer_saved[i] = *port_fer[i]; +#endif + for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) { bank = gpio_bank(i); @@ -675,6 +586,10 @@ void bfin_gpio_pm_hibernate_suspend(void) gpio_bank_saved[bank].maska = gpio_array[bank]->maska; } +#ifdef BFIN_SPECIAL_GPIO_BANKS + bfin_special_gpio_pm_hibernate_suspend(); +#endif + AWA_DUMMY_READ(maska); } @@ -682,6 +597,11 @@ void bfin_gpio_pm_hibernate_restore(void) { int i, bank; +#ifdef BF538_FAMILY + for (i = 0; i < ARRAY_SIZE(port_fer_saved); ++i) + *port_fer[i] = port_fer_saved[i]; +#endif + for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) { bank = gpio_bank(i); @@ -695,78 +615,28 @@ void bfin_gpio_pm_hibernate_restore(void) *port_fer[bank] = gpio_bank_saved[bank].fer; #endif gpio_array[bank]->inen = gpio_bank_saved[bank].inen; + gpio_array[bank]->data_set = gpio_bank_saved[bank].data + & gpio_bank_saved[bank].dir; gpio_array[bank]->dir = gpio_bank_saved[bank].dir; gpio_array[bank]->polar = gpio_bank_saved[bank].polar; gpio_array[bank]->edge = gpio_bank_saved[bank].edge; gpio_array[bank]->both = gpio_bank_saved[bank].both; - - gpio_array[bank]->data_set = gpio_bank_saved[bank].data - | gpio_bank_saved[bank].dir; - gpio_array[bank]->maska = gpio_bank_saved[bank].maska; } - AWA_DUMMY_READ(maska); -} - +#ifdef BFIN_SPECIAL_GPIO_BANKS + bfin_special_gpio_pm_hibernate_restore(); #endif -#else /* CONFIG_BF54x */ -#ifdef CONFIG_PM - -u32 bfin_pm_standby_setup(void) -{ - return 0; -} - -void bfin_pm_standby_restore(void) -{ - -} - -void bfin_gpio_pm_hibernate_suspend(void) -{ - int i, bank; - - for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) { - bank = gpio_bank(i); - gpio_bank_saved[bank].fer = gpio_array[bank]->port_fer; - gpio_bank_saved[bank].mux = gpio_array[bank]->port_mux; - gpio_bank_saved[bank].data = gpio_array[bank]->data; - gpio_bank_saved[bank].data = gpio_array[bank]->data; - gpio_bank_saved[bank].inen = gpio_array[bank]->inen; - gpio_bank_saved[bank].dir = gpio_array[bank]->dir_set; - } + AWA_DUMMY_READ(maska); } -void bfin_gpio_pm_hibernate_restore(void) -{ - int i, bank; - - for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) { - bank = gpio_bank(i); - gpio_array[bank]->port_mux = gpio_bank_saved[bank].mux; - gpio_array[bank]->port_fer = gpio_bank_saved[bank].fer; - gpio_array[bank]->inen = gpio_bank_saved[bank].inen; - gpio_array[bank]->dir_set = gpio_bank_saved[bank].dir; - gpio_array[bank]->data_set = gpio_bank_saved[bank].data - | gpio_bank_saved[bank].dir; - } -} #endif -unsigned short get_gpio_dir(unsigned gpio) -{ - return (0x01 & (gpio_array[gpio_bank(gpio)]->dir_clear >> gpio_sub_n(gpio))); -} -EXPORT_SYMBOL(get_gpio_dir); - -#endif /* CONFIG_BF54x */ - /*********************************************************** * -* FUNCTIONS: Blackfin Peripheral Resource Allocation +* FUNCTIONS: Blackfin Peripheral Resource Allocation * and PortMux Setup * * INPUTS/OUTPUTS: @@ -795,34 +665,31 @@ int peripheral_request(unsigned short per, const char *label) if (!(per & P_DEFINED)) return -ENODEV; - local_irq_save_hw(flags); + BUG_ON(ident >= MAX_RESOURCES); + + flags = hard_local_irq_save(); /* If a pin can be muxed as either GPIO or peripheral, make * sure it is not already a GPIO pin when we request it. */ - if (unlikely(!check_gpio(ident) && - reserved_gpio_map[gpio_bank(ident)] & gpio_bit(ident))) { + if (unlikely(!check_gpio(ident) && is_reserved(gpio, ident, 1))) { if (system_state == SYSTEM_BOOTING) dump_stack(); printk(KERN_ERR "%s: Peripheral %d is already reserved as GPIO by %s !\n", __func__, ident, get_label(ident)); - local_irq_restore_hw(flags); + hard_local_irq_restore(flags); return -EBUSY; } - if (unlikely(reserved_peri_map[gpio_bank(ident)] & gpio_bit(ident))) { + if (unlikely(is_reserved(peri, ident, 1))) { /* * Pin functions like AMC address strobes my * be requested and used by several drivers */ -#ifdef CONFIG_BF54x - if (!((per & P_MAYSHARE) && get_portmux(per) == P_FUNCT2MUX(per))) { -#else if (!(per & P_MAYSHARE)) { -#endif /* * Allow that the identical pin function can * be requested from the same driver twice @@ -836,18 +703,22 @@ int peripheral_request(unsigned short per, const char *label) printk(KERN_ERR "%s: Peripheral %d function %d is already reserved by %s !\n", __func__, ident, P_FUNCT2MUX(per), get_label(ident)); - local_irq_restore_hw(flags); + hard_local_irq_restore(flags); return -EBUSY; } } + if (unlikely(portmux_group_check(per))) { + hard_local_irq_restore(flags); + return -EBUSY; + } anyway: - reserved_peri_map[gpio_bank(ident)] |= gpio_bit(ident); + reserve(peri, ident); portmux_setup(per); port_setup(ident, PERIPHERAL_USAGE); - local_irq_restore_hw(flags); + hard_local_irq_restore(flags); set_label(ident, label); return 0; @@ -886,21 +757,21 @@ void peripheral_free(unsigned short per) if (!(per & P_DEFINED)) return; - local_irq_save_hw(flags); + flags = hard_local_irq_save(); - if (unlikely(!(reserved_peri_map[gpio_bank(ident)] & gpio_bit(ident)))) { - local_irq_restore_hw(flags); + if (unlikely(!is_reserved(peri, ident, 0))) { + hard_local_irq_restore(flags); return; } if (!(per & P_MAYSHARE)) port_setup(ident, GPIO_USAGE); - reserved_peri_map[gpio_bank(ident)] &= ~gpio_bit(ident); + unreserve(peri, ident); set_label(ident, "free"); - local_irq_restore_hw(flags); + hard_local_irq_restore(flags); } EXPORT_SYMBOL(peripheral_free); @@ -934,7 +805,7 @@ int bfin_gpio_request(unsigned gpio, const char *label) if (check_gpio(gpio) < 0) return -EINVAL; - local_irq_save_hw(flags); + flags = hard_local_irq_save(); /* * Allow that the identical GPIO can @@ -943,41 +814,38 @@ int bfin_gpio_request(unsigned gpio, const char *label) */ if (cmp_label(gpio, label) == 0) { - local_irq_restore_hw(flags); + hard_local_irq_restore(flags); return 0; } - if (unlikely(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) { + if (unlikely(is_reserved(gpio, gpio, 1))) { if (system_state == SYSTEM_BOOTING) dump_stack(); printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved by %s !\n", gpio, get_label(gpio)); - local_irq_restore_hw(flags); + hard_local_irq_restore(flags); return -EBUSY; } - if (unlikely(reserved_peri_map[gpio_bank(gpio)] & gpio_bit(gpio))) { + if (unlikely(is_reserved(peri, gpio, 1))) { if (system_state == SYSTEM_BOOTING) dump_stack(); printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n", gpio, get_label(gpio)); - local_irq_restore_hw(flags); + hard_local_irq_restore(flags); return -EBUSY; } - if (unlikely(reserved_gpio_irq_map[gpio_bank(gpio)] & gpio_bit(gpio))) { + if (unlikely(is_reserved(gpio_irq, gpio, 1))) { printk(KERN_NOTICE "bfin-gpio: GPIO %d is already reserved as gpio-irq!" " (Documentation/blackfin/bfin-gpio-notes.txt)\n", gpio); - } -#ifndef CONFIG_BF54x - else { /* Reset POLAR setting when acquiring a gpio for the first time */ + } else { /* Reset POLAR setting when acquiring a gpio for the first time */ set_gpio_polar(gpio, 0); } -#endif - reserved_gpio_map[gpio_bank(gpio)] |= gpio_bit(gpio); + reserve(gpio, gpio); set_label(gpio, label); - local_irq_restore_hw(flags); + hard_local_irq_restore(flags); port_setup(gpio, GPIO_USAGE); @@ -994,60 +862,121 @@ void bfin_gpio_free(unsigned gpio) might_sleep(); - local_irq_save_hw(flags); + flags = hard_local_irq_save(); - if (unlikely(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)))) { + if (unlikely(!is_reserved(gpio, gpio, 0))) { if (system_state == SYSTEM_BOOTING) dump_stack(); gpio_error(gpio); - local_irq_restore_hw(flags); + hard_local_irq_restore(flags); return; } - reserved_gpio_map[gpio_bank(gpio)] &= ~gpio_bit(gpio); + unreserve(gpio, gpio); set_label(gpio, "free"); - local_irq_restore_hw(flags); + hard_local_irq_restore(flags); } EXPORT_SYMBOL(bfin_gpio_free); -int bfin_gpio_irq_request(unsigned gpio, const char *label) +#ifdef BFIN_SPECIAL_GPIO_BANKS +DECLARE_RESERVED_MAP(special_gpio, gpio_bank(MAX_RESOURCES)); + +int bfin_special_gpio_request(unsigned gpio, const char *label) { unsigned long flags; - if (check_gpio(gpio) < 0) - return -EINVAL; + flags = hard_local_irq_save(); - local_irq_save_hw(flags); + /* + * Allow that the identical GPIO can + * be requested from the same driver twice + * Do nothing and return - + */ - if (unlikely(reserved_gpio_irq_map[gpio_bank(gpio)] & gpio_bit(gpio))) { - if (system_state == SYSTEM_BOOTING) - dump_stack(); + if (cmp_label(gpio, label) == 0) { + hard_local_irq_restore(flags); + return 0; + } + + if (unlikely(is_reserved(special_gpio, gpio, 1))) { + hard_local_irq_restore(flags); + printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved by %s !\n", + gpio, get_label(gpio)); + + return -EBUSY; + } + if (unlikely(is_reserved(peri, gpio, 1))) { + hard_local_irq_restore(flags); printk(KERN_ERR - "bfin-gpio: GPIO %d is already reserved as gpio-irq !\n", - gpio); - local_irq_restore_hw(flags); + "bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n", + gpio, get_label(gpio)); + return -EBUSY; } - if (unlikely(reserved_peri_map[gpio_bank(gpio)] & gpio_bit(gpio))) { + + reserve(special_gpio, gpio); + reserve(peri, gpio); + + set_label(gpio, label); + hard_local_irq_restore(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(); + + flags = hard_local_irq_save(); + + if (unlikely(!is_reserved(special_gpio, gpio, 0))) { + gpio_error(gpio); + hard_local_irq_restore(flags); + return; + } + + unreserve(special_gpio, gpio); + unreserve(peri, gpio); + set_label(gpio, "free"); + hard_local_irq_restore(flags); +} +EXPORT_SYMBOL(bfin_special_gpio_free); +#endif + + +int bfin_gpio_irq_request(unsigned gpio, const char *label) +{ + unsigned long flags; + + if (check_gpio(gpio) < 0) + return -EINVAL; + + flags = hard_local_irq_save(); + + if (unlikely(is_reserved(peri, gpio, 1))) { if (system_state == SYSTEM_BOOTING) dump_stack(); printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n", gpio, get_label(gpio)); - local_irq_restore_hw(flags); + hard_local_irq_restore(flags); return -EBUSY; } - if (unlikely(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) + if (unlikely(is_reserved(gpio, gpio, 1))) printk(KERN_NOTICE "bfin-gpio: GPIO %d is already reserved by %s! " "(Documentation/blackfin/bfin-gpio-notes.txt)\n", gpio, get_label(gpio)); - reserved_gpio_irq_map[gpio_bank(gpio)] |= gpio_bit(gpio); + reserve(gpio_irq, gpio); set_label(gpio, label); - local_irq_restore_hw(flags); + hard_local_irq_restore(flags); port_setup(gpio, GPIO_USAGE); @@ -1061,30 +990,26 @@ void bfin_gpio_irq_free(unsigned gpio) if (check_gpio(gpio) < 0) return; - local_irq_save_hw(flags); + flags = hard_local_irq_save(); - if (unlikely(!(reserved_gpio_irq_map[gpio_bank(gpio)] & gpio_bit(gpio)))) { + if (unlikely(!is_reserved(gpio_irq, gpio, 0))) { if (system_state == SYSTEM_BOOTING) dump_stack(); gpio_error(gpio); - local_irq_restore_hw(flags); + hard_local_irq_restore(flags); return; } - reserved_gpio_irq_map[gpio_bank(gpio)] &= ~gpio_bit(gpio); + unreserve(gpio_irq, gpio); set_label(gpio, "free"); - local_irq_restore_hw(flags); + hard_local_irq_restore(flags); } static inline void __bfin_gpio_direction_input(unsigned gpio) { -#ifdef CONFIG_BF54x - gpio_array[gpio_bank(gpio)]->dir_clear = gpio_bit(gpio); -#else gpio_array[gpio_bank(gpio)]->dir &= ~gpio_bit(gpio); -#endif gpio_array[gpio_bank(gpio)]->inen |= gpio_bit(gpio); } @@ -1092,15 +1017,15 @@ int bfin_gpio_direction_input(unsigned gpio) { unsigned long flags; - if (!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) { + if (unlikely(!is_reserved(gpio, gpio, 0))) { gpio_error(gpio); return -EINVAL; } - local_irq_save_hw(flags); + flags = hard_local_irq_save(); __bfin_gpio_direction_input(gpio); AWA_DUMMY_READ(inen); - local_irq_restore_hw(flags); + hard_local_irq_restore(flags); return 0; } @@ -1108,17 +1033,7 @@ EXPORT_SYMBOL(bfin_gpio_direction_input); void bfin_gpio_irq_prepare(unsigned gpio) { -#ifdef CONFIG_BF54x - unsigned long flags; -#endif - port_setup(gpio, GPIO_USAGE); - -#ifdef CONFIG_BF54x - local_irq_save_hw(flags); - __bfin_gpio_direction_input(gpio); - local_irq_restore_hw(flags); -#endif } void bfin_gpio_set_value(unsigned gpio, int arg) @@ -1134,23 +1049,19 @@ int bfin_gpio_direction_output(unsigned gpio, int value) { unsigned long flags; - if (!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) { + if (unlikely(!is_reserved(gpio, gpio, 0))) { gpio_error(gpio); return -EINVAL; } - local_irq_save_hw(flags); + flags = hard_local_irq_save(); gpio_array[gpio_bank(gpio)]->inen &= ~gpio_bit(gpio); gpio_set_value(gpio, value); -#ifdef CONFIG_BF54x - gpio_array[gpio_bank(gpio)]->dir_set = gpio_bit(gpio); -#else gpio_array[gpio_bank(gpio)]->dir |= gpio_bit(gpio); -#endif AWA_DUMMY_READ(dir); - local_irq_restore_hw(flags); + hard_local_irq_restore(flags); return 0; } @@ -1158,22 +1069,18 @@ EXPORT_SYMBOL(bfin_gpio_direction_output); int bfin_gpio_get_value(unsigned gpio) { -#ifdef CONFIG_BF54x - return (1 & (gpio_array[gpio_bank(gpio)]->data >> gpio_sub_n(gpio))); -#else unsigned long flags; if (unlikely(get_gpio_edge(gpio))) { int ret; - local_irq_save_hw(flags); + flags = hard_local_irq_save(); set_gpio_edge(gpio, 0); ret = get_gpio_data(gpio); set_gpio_edge(gpio, 1); - local_irq_restore_hw(flags); + hard_local_irq_restore(flags); return ret; } else return get_gpio_data(gpio); -#endif } EXPORT_SYMBOL(bfin_gpio_get_value); @@ -1197,79 +1104,93 @@ void bfin_reset_boot_spi_cs(unsigned short pin) } #if defined(CONFIG_PROC_FS) -static int gpio_proc_read(char *buf, char **start, off_t offset, - int len, int *unused_i, void *unused_v) +static int gpio_proc_show(struct seq_file *m, void *v) { - int c, irq, gpio, outlen = 0; + int c, irq, gpio; for (c = 0; c < MAX_RESOURCES; c++) { - irq = reserved_gpio_irq_map[gpio_bank(c)] & gpio_bit(c); - gpio = reserved_gpio_map[gpio_bank(c)] & gpio_bit(c); + irq = is_reserved(gpio_irq, c, 1); + gpio = is_reserved(gpio, c, 1); if (!check_gpio(c) && (gpio || irq)) - len = sprintf(buf, "GPIO_%d: \t%s%s \t\tGPIO %s\n", c, + seq_printf(m, "GPIO_%d: \t%s%s \t\tGPIO %s\n", c, get_label(c), (gpio && irq) ? " *" : "", get_gpio_dir(c) ? "OUTPUT" : "INPUT"); - else if (reserved_peri_map[gpio_bank(c)] & gpio_bit(c)) - len = sprintf(buf, "GPIO_%d: \t%s \t\tPeripheral\n", c, get_label(c)); + else if (is_reserved(peri, c, 1)) + seq_printf(m, "GPIO_%d: \t%s \t\tPeripheral\n", c, get_label(c)); else continue; - buf += len; - outlen += len; } - return outlen; + + return 0; } +static int gpio_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, gpio_proc_show, NULL); +} + +static const struct file_operations gpio_proc_ops = { + .open = gpio_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static __init int gpio_register_proc(void) { struct proc_dir_entry *proc_gpio; - proc_gpio = create_proc_entry("gpio", S_IRUGO, NULL); - if (proc_gpio) - proc_gpio->read_proc = gpio_proc_read; - return proc_gpio != NULL; + proc_gpio = proc_create("gpio", 0, NULL, &gpio_proc_ops); + return proc_gpio == NULL; } __initcall(gpio_register_proc); #endif #ifdef CONFIG_GPIOLIB -int bfin_gpiolib_direction_input(struct gpio_chip *chip, unsigned gpio) +static int bfin_gpiolib_direction_input(struct gpio_chip *chip, unsigned gpio) { return bfin_gpio_direction_input(gpio); } -int bfin_gpiolib_direction_output(struct gpio_chip *chip, unsigned gpio, int level) +static int bfin_gpiolib_direction_output(struct gpio_chip *chip, unsigned gpio, int level) { return bfin_gpio_direction_output(gpio, level); } -int bfin_gpiolib_get_value(struct gpio_chip *chip, unsigned gpio) +static int bfin_gpiolib_get_value(struct gpio_chip *chip, unsigned gpio) { return bfin_gpio_get_value(gpio); } -void bfin_gpiolib_set_value(struct gpio_chip *chip, unsigned gpio, int value) +static void bfin_gpiolib_set_value(struct gpio_chip *chip, unsigned gpio, int value) { return bfin_gpio_set_value(gpio, value); } -int bfin_gpiolib_gpio_request(struct gpio_chip *chip, unsigned gpio) +static int bfin_gpiolib_gpio_request(struct gpio_chip *chip, unsigned gpio) { return bfin_gpio_request(gpio, chip->label); } -void bfin_gpiolib_gpio_free(struct gpio_chip *chip, unsigned gpio) +static void bfin_gpiolib_gpio_free(struct gpio_chip *chip, unsigned gpio) { return bfin_gpio_free(gpio); } +static int bfin_gpiolib_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) +{ + return gpio + GPIO_IRQ_BASE; +} + static struct gpio_chip bfin_chip = { - .label = "Blackfin-GPIOlib", + .label = "BFIN-GPIO", .direction_input = bfin_gpiolib_direction_input, .get = bfin_gpiolib_get_value, .direction_output = bfin_gpiolib_direction_output, .set = bfin_gpiolib_set_value, .request = bfin_gpiolib_gpio_request, .free = bfin_gpiolib_gpio_free, + .to_irq = bfin_gpiolib_gpio_to_irq, .base = 0, .ngpio = MAX_BLACKFIN_GPIOS, }; |
