/* * GPIO Abstraction Layer * * Copyright 2006-2010 Analog Devices Inc. * * Licensed under the GPL-2 or later */ #include #include #include #include #include #include #include #include #include #include #if ANOMALY_05000311 || ANOMALY_05000323 enum { AWA_data = SYSCR, AWA_data_clear = SYSCR, AWA_data_set = SYSCR, AWA_toggle = SYSCR, AWA_maska = BFIN_UART_SCR, AWA_maska_clear = BFIN_UART_SCR, AWA_maska_set = BFIN_UART_SCR, AWA_maska_toggle = BFIN_UART_SCR, AWA_maskb = BFIN_UART_GCTL, AWA_maskb_clear = BFIN_UART_GCTL, AWA_maskb_set = BFIN_UART_GCTL, AWA_maskb_toggle = BFIN_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 static struct gpio_port_t * const gpio_array[] = { #if defined(BF533_FAMILY) || defined(BF538_FAMILY) (struct gpio_port_t *) FIO_FLAG_D, #elif defined(CONFIG_BF52x) || defined(BF537_FAMILY) || defined(CONFIG_BF51x) (struct gpio_port_t *) PORTFIO, (struct gpio_port_t *) PORTGIO, (struct gpio_port_t *) PORTHIO, #elif defined(BF561_FAMILY) (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) || defined(CONFIG_BF60x) (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, # if defined(CONFIG_BF54x) (struct gpio_port_t *)PORTH_FER, (struct gpio_port_t *)PORTI_FER, (struct gpio_port_t *)PORTJ_FER, # endif #else # error no gpio arrays defined #endif }; #if defined(CONFIG_BF52x) || defined(BF537_FAMILY) || defined(CONFIG_BF51x) static unsigned short * const port_fer[] = { (unsigned short *) PORTF_FER, (unsigned short *) PORTG_FER, (unsigned short *) PORTH_FER, }; # if !defined(BF537_FAMILY) static unsigned short * const port_mux[] = { (unsigned short *) PORTF_MUX, (unsigned short *) PORTG_MUX, (unsigned short *) PORTH_MUX, }; static const u8 pmux_offset[][16] = { # if defined(CONFIG_BF52x) { 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 */ # elif defined(CONFIG_BF51x) { 0, 2, 2, 2, 2, 2, 2, 4, 6, 6, 6, 8, 8, 8, 8, 10 }, /* PORTF */ { 0, 0, 0, 2, 4, 6, 6, 6, 8, 10, 10, 12, 14, 14, 14, 14 }, /* PORTG */ { 0, 0, 0, 0, 2, 2, 4, 6, 10, 10, 10, 10, 10, 10, 10, 10 }, /* PORTH */ # endif }; # endif #elif defined(BF538_FAMILY) static unsigned short * const port_fer[] = { (unsigned short *) PORTCIO_FER, (unsigned short *) PORTDIO_FER, (unsigned short *) PORTEIO_FER, }; #endif #define RESOURCE_LABEL_SIZE 16 static struct str_ident { char name[RESOURCE_LABEL_SIZE]; } str_ident[MAX_RESOURCES]; #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 static void gpio_error(unsigned gpio) { printk(KERN_ERR "bfin-gpio: GPIO %d wasn't requested!\n", gpio); } static void set_label(unsigned short ident, const char *label) { if (label) { 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) { return (*str_ident[ident].name ? str_ident[ident].name : "UNKNOWN"); } static int cmp_label(unsigned short ident, const char *label) { if (label == NULL) { dump_stack(); printk(KERN_ERR "Please provide none-null label\n"); } if (label) return strcmp(str_ident[ident].name, label); else 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 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 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; #if defined(CONFIG_BF52x) || defined(BF537_FAMILY) || defined(CONFIG_BF51x) if (usage == GPIO_USAGE) *port_fer[gpio_bank(gpio)] &= ~gpio_bit(gpio); else *port_fer[gpio_bank(gpio)] |= gpio_bit(gpio); SSYNC(); #elif defined(CONFIG_BF54x) || defined(CONFIG_BF60x) 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 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 int portmux_group_check(unsigned short per) { u16 ident = P_IDENT(per); u16 function = P_FUNCT2MUX(per); s8 offset = port_mux[ident]; u16 m, pmux, pfunc; if (offset < 0) return 0; 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) pfunc = (pmux >> offset) & 3; else pfunc = (pmux >> offset) & 1; if (pfunc != function) { 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; } static void portmux_setup(unsigned short per) { u16 ident = P_IDENT(per); u16 function = P_FUNCT2MUX(per); s8 offset = port_mux[ident]; u16 pmux; if (offset == -1) return; pmux = bfin_read_PORT_MUX(); if (offset != 1) pmux &= ~(1 << offset); else pmux &= ~(3 << 1); pmux |= (function << offset); bfin_write_PORT_MUX(pmux); } #elif defined(CONFIG_BF54x) || defined(CONFIG_BF60x) inline void portmux_setup(unsigned short per) { u16 ident = P_IDENT(per); u16 function = P_FUNCT2MUX(per); u32 pmux; pmux = gpio_array[gpio_bank(ident)]->port_mux; pmux &= ~(0x3 << (2 * gpio_sub_n(ident))); pmux |= (function & 0x3) << (2 * gpio_sub_n(ident)); gpio_array[gpio_bank(ident)]->port_mux = pmux; } inline u16 get_portmux(unsigned short per) { u16 ident = P_IDENT(per); u32 pmux = gpio_array[gpio_bank(ident)]->port_mux; return (pmux >> (2 * gpio_sub_n(ident)) & 0x3); } static int portmux_group_check(unsigned short per) { return 0; } #elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x) static int portmux_group_check(unsigned short per) { 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;