Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Blackfin: bf538: add support for extended GPIO banks

The GPIOs on ports C/D/E on the BF538/BF539 do not behave the same way as
the other ports on the part and the same way as all other Blackfin parts.
The MMRs are programmed slightly different and they cannot be used to
generate interrupts or wakeup a sleeping system. Since these guys don't
fit into the existing code, create a simple gpiolib driver for them.

Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>

authored by

Michael Hennerich and committed by
Mike Frysinger
621dd247 46fe23ac

+280 -27
+5
arch/blackfin/include/asm/gpio.h
··· 159 159 }; 160 160 #endif 161 161 162 + #ifdef BFIN_SPECIAL_GPIO_BANKS 163 + void bfin_special_gpio_free(unsigned gpio); 164 + int bfin_special_gpio_request(unsigned gpio, const char *label); 165 + #endif 166 + 162 167 #ifdef CONFIG_PM 163 168 164 169 unsigned int bfin_pm_standby_setup(void);
+97
arch/blackfin/kernel/bfin_gpio.c
··· 100 100 }; 101 101 # endif 102 102 103 + #elif defined(BF538_FAMILY) 104 + static unsigned short * const port_fer[] = { 105 + (unsigned short *) PORTCIO_FER, 106 + (unsigned short *) PORTDIO_FER, 107 + (unsigned short *) PORTEIO_FER, 108 + }; 103 109 #endif 104 110 105 111 static unsigned short reserved_gpio_map[GPIO_BANK_NUM]; ··· 169 163 170 164 static void port_setup(unsigned gpio, unsigned short usage) 171 165 { 166 + #if defined(BF538_FAMILY) 167 + /* 168 + * BF538/9 Port C,D and E are special. 169 + * Inverted PORT_FER polarity on CDE and no PORF_FER on F 170 + * Regular PORT F GPIOs are handled here, CDE are exclusively 171 + * managed by GPIOLIB 172 + */ 173 + 174 + if (gpio < MAX_BLACKFIN_GPIOS || gpio >= MAX_RESOURCES) 175 + return; 176 + 177 + gpio -= MAX_BLACKFIN_GPIOS; 178 + 179 + if (usage == GPIO_USAGE) 180 + *port_fer[gpio_bank(gpio)] |= gpio_bit(gpio); 181 + else 182 + *port_fer[gpio_bank(gpio)] &= ~gpio_bit(gpio); 183 + SSYNC(); 184 + return; 185 + #endif 186 + 172 187 if (check_gpio(gpio)) 173 188 return; 174 189 ··· 1007 980 local_irq_restore_hw(flags); 1008 981 } 1009 982 EXPORT_SYMBOL(bfin_gpio_free); 983 + 984 + #ifdef BFIN_SPECIAL_GPIO_BANKS 985 + static unsigned short reserved_special_gpio_map[gpio_bank(MAX_RESOURCES)]; 986 + 987 + int bfin_special_gpio_request(unsigned gpio, const char *label) 988 + { 989 + unsigned long flags; 990 + 991 + local_irq_save_hw(flags); 992 + 993 + /* 994 + * Allow that the identical GPIO can 995 + * be requested from the same driver twice 996 + * Do nothing and return - 997 + */ 998 + 999 + if (cmp_label(gpio, label) == 0) { 1000 + local_irq_restore_hw(flags); 1001 + return 0; 1002 + } 1003 + 1004 + if (unlikely(reserved_special_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) { 1005 + local_irq_restore_hw(flags); 1006 + printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved by %s !\n", 1007 + gpio, get_label(gpio)); 1008 + 1009 + return -EBUSY; 1010 + } 1011 + if (unlikely(reserved_peri_map[gpio_bank(gpio)] & gpio_bit(gpio))) { 1012 + local_irq_restore_hw(flags); 1013 + printk(KERN_ERR 1014 + "bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n", 1015 + gpio, get_label(gpio)); 1016 + 1017 + return -EBUSY; 1018 + } 1019 + 1020 + reserved_special_gpio_map[gpio_bank(gpio)] |= gpio_bit(gpio); 1021 + reserved_peri_map[gpio_bank(gpio)] |= gpio_bit(gpio); 1022 + 1023 + set_label(gpio, label); 1024 + local_irq_restore_hw(flags); 1025 + port_setup(gpio, GPIO_USAGE); 1026 + 1027 + return 0; 1028 + } 1029 + EXPORT_SYMBOL(bfin_special_gpio_request); 1030 + 1031 + void bfin_special_gpio_free(unsigned gpio) 1032 + { 1033 + unsigned long flags; 1034 + 1035 + might_sleep(); 1036 + 1037 + local_irq_save_hw(flags); 1038 + 1039 + if (unlikely(!(reserved_special_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)))) { 1040 + gpio_error(gpio); 1041 + local_irq_restore_hw(flags); 1042 + return; 1043 + } 1044 + 1045 + reserved_special_gpio_map[gpio_bank(gpio)] &= ~gpio_bit(gpio); 1046 + reserved_peri_map[gpio_bank(gpio)] &= ~gpio_bit(gpio); 1047 + set_label(gpio, "free"); 1048 + local_irq_restore_hw(flags); 1049 + } 1050 + EXPORT_SYMBOL(bfin_special_gpio_free); 1051 + #endif 1052 + 1010 1053 1011 1054 int bfin_gpio_irq_request(unsigned gpio, const char *label) 1012 1055 {
+1
arch/blackfin/mach-bf538/Makefile
··· 3 3 # 4 4 5 5 obj-y := ints-priority.o dma.o 6 + obj-$(CONFIG_GPIOLIB) += ext-gpio.o
+123
arch/blackfin/mach-bf538/ext-gpio.c
··· 1 + /* 2 + * GPIOLIB interface for BF538/9 PORT C, D, and E GPIOs 3 + * 4 + * Copyright 2009 Analog Devices Inc. 5 + * 6 + * Licensed under the GPL-2 or later. 7 + */ 8 + 9 + #include <linux/module.h> 10 + #include <linux/err.h> 11 + #include <asm/blackfin.h> 12 + #include <asm/gpio.h> 13 + #include <asm/portmux.h> 14 + 15 + #define DEFINE_REG(reg, off) \ 16 + static inline u16 read_##reg(void __iomem *port) \ 17 + { return bfin_read16(port + off); } \ 18 + static inline void write_##reg(void __iomem *port, u16 v) \ 19 + { bfin_write16(port + off, v); } 20 + 21 + DEFINE_REG(PORTIO, 0x00) 22 + DEFINE_REG(PORTIO_CLEAR, 0x10) 23 + DEFINE_REG(PORTIO_SET, 0x20) 24 + DEFINE_REG(PORTIO_DIR, 0x40) 25 + DEFINE_REG(PORTIO_INEN, 0x50) 26 + 27 + static void __iomem *gpio_chip_to_mmr(struct gpio_chip *chip) 28 + { 29 + switch (chip->base) { 30 + default: /* not really needed, but keeps gcc happy */ 31 + case GPIO_PC0: return (void __iomem *)PORTCIO; 32 + case GPIO_PD0: return (void __iomem *)PORTDIO; 33 + case GPIO_PE0: return (void __iomem *)PORTEIO; 34 + } 35 + } 36 + 37 + static int bf538_gpio_get_value(struct gpio_chip *chip, unsigned gpio) 38 + { 39 + void __iomem *port = gpio_chip_to_mmr(chip); 40 + return !!(read_PORTIO(port) & (1u << gpio)); 41 + } 42 + 43 + static void bf538_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value) 44 + { 45 + void __iomem *port = gpio_chip_to_mmr(chip); 46 + if (value) 47 + write_PORTIO_SET(port, (1u << gpio)); 48 + else 49 + write_PORTIO_CLEAR(port, (1u << gpio)); 50 + } 51 + 52 + static int bf538_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) 53 + { 54 + void __iomem *port = gpio_chip_to_mmr(chip); 55 + write_PORTIO_DIR(port, read_PORTIO_DIR(port) & ~(1u << gpio)); 56 + write_PORTIO_INEN(port, read_PORTIO_INEN(port) | (1u << gpio)); 57 + return 0; 58 + } 59 + 60 + static int bf538_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value) 61 + { 62 + void __iomem *port = gpio_chip_to_mmr(chip); 63 + write_PORTIO_INEN(port, read_PORTIO_INEN(port) & ~(1u << gpio)); 64 + bf538_gpio_set_value(port, gpio, value); 65 + write_PORTIO_DIR(port, read_PORTIO_DIR(port) | (1u << gpio)); 66 + return 0; 67 + } 68 + 69 + static int bf538_gpio_request(struct gpio_chip *chip, unsigned gpio) 70 + { 71 + return bfin_special_gpio_request(chip->base + gpio, chip->label); 72 + } 73 + 74 + static void bf538_gpio_free(struct gpio_chip *chip, unsigned gpio) 75 + { 76 + return bfin_special_gpio_free(chip->base + gpio); 77 + } 78 + 79 + /* We don't set the irq fields as these banks cannot generate interrupts */ 80 + 81 + static struct gpio_chip bf538_portc_chip = { 82 + .label = "GPIO-PC", 83 + .direction_input = bf538_gpio_direction_input, 84 + .get = bf538_gpio_get_value, 85 + .direction_output = bf538_gpio_direction_output, 86 + .set = bf538_gpio_set_value, 87 + .request = bf538_gpio_request, 88 + .free = bf538_gpio_free, 89 + .base = GPIO_PC0, 90 + .ngpio = GPIO_PC9 - GPIO_PC0 + 1, 91 + }; 92 + 93 + static struct gpio_chip bf538_portd_chip = { 94 + .label = "GPIO-PD", 95 + .direction_input = bf538_gpio_direction_input, 96 + .get = bf538_gpio_get_value, 97 + .direction_output = bf538_gpio_direction_output, 98 + .set = bf538_gpio_set_value, 99 + .request = bf538_gpio_request, 100 + .free = bf538_gpio_free, 101 + .base = GPIO_PD0, 102 + .ngpio = GPIO_PD13 - GPIO_PD0 + 1, 103 + }; 104 + 105 + static struct gpio_chip bf538_porte_chip = { 106 + .label = "GPIO-PE", 107 + .direction_input = bf538_gpio_direction_input, 108 + .get = bf538_gpio_get_value, 109 + .direction_output = bf538_gpio_direction_output, 110 + .set = bf538_gpio_set_value, 111 + .request = bf538_gpio_request, 112 + .free = bf538_gpio_free, 113 + .base = GPIO_PE0, 114 + .ngpio = GPIO_PE15 - GPIO_PE0 + 1, 115 + }; 116 + 117 + static int __init bf538_extgpio_setup(void) 118 + { 119 + return gpiochip_add(&bf538_portc_chip) | 120 + gpiochip_add(&bf538_portd_chip) | 121 + gpiochip_add(&bf538_porte_chip); 122 + } 123 + arch_initcall(bf538_extgpio_setup);
+21 -21
arch/blackfin/mach-bf538/include/mach/defBF539.h
··· 468 468 /* General-Purpose Ports (0xFFC01500 - 0xFFC015FF) */ 469 469 470 470 /* GPIO Port C Register Names */ 471 - #define GPIO_C_CNFG 0xFFC01500 /* GPIO Pin Port C Configuration Register */ 472 - #define GPIO_C_D 0xFFC01510 /* GPIO Pin Port C Data Register */ 473 - #define GPIO_C_C 0xFFC01520 /* Clear GPIO Pin Port C Register */ 474 - #define GPIO_C_S 0xFFC01530 /* Set GPIO Pin Port C Register */ 475 - #define GPIO_C_T 0xFFC01540 /* Toggle GPIO Pin Port C Register */ 476 - #define GPIO_C_DIR 0xFFC01550 /* GPIO Pin Port C Direction Register */ 477 - #define GPIO_C_INEN 0xFFC01560 /* GPIO Pin Port C Input Enable Register */ 471 + #define PORTCIO_FER 0xFFC01500 /* GPIO Pin Port C Configuration Register */ 472 + #define PORTCIO 0xFFC01510 /* GPIO Pin Port C Data Register */ 473 + #define PORTCIO_CLEAR 0xFFC01520 /* Clear GPIO Pin Port C Register */ 474 + #define PORTCIO_SET 0xFFC01530 /* Set GPIO Pin Port C Register */ 475 + #define PORTCIO_TOGGLE 0xFFC01540 /* Toggle GPIO Pin Port C Register */ 476 + #define PORTCIO_DIR 0xFFC01550 /* GPIO Pin Port C Direction Register */ 477 + #define PORTCIO_INEN 0xFFC01560 /* GPIO Pin Port C Input Enable Register */ 478 478 479 479 /* GPIO Port D Register Names */ 480 - #define GPIO_D_CNFG 0xFFC01504 /* GPIO Pin Port D Configuration Register */ 481 - #define GPIO_D_D 0xFFC01514 /* GPIO Pin Port D Data Register */ 482 - #define GPIO_D_C 0xFFC01524 /* Clear GPIO Pin Port D Register */ 483 - #define GPIO_D_S 0xFFC01534 /* Set GPIO Pin Port D Register */ 484 - #define GPIO_D_T 0xFFC01544 /* Toggle GPIO Pin Port D Register */ 485 - #define GPIO_D_DIR 0xFFC01554 /* GPIO Pin Port D Direction Register */ 486 - #define GPIO_D_INEN 0xFFC01564 /* GPIO Pin Port D Input Enable Register */ 480 + #define PORTDIO_FER 0xFFC01504 /* GPIO Pin Port D Configuration Register */ 481 + #define PORTDIO 0xFFC01514 /* GPIO Pin Port D Data Register */ 482 + #define PORTDIO_CLEAR 0xFFC01524 /* Clear GPIO Pin Port D Register */ 483 + #define PORTDIO_SET 0xFFC01534 /* Set GPIO Pin Port D Register */ 484 + #define PORTDIO_TOGGLE 0xFFC01544 /* Toggle GPIO Pin Port D Register */ 485 + #define PORTDIO_DIR 0xFFC01554 /* GPIO Pin Port D Direction Register */ 486 + #define PORTDIO_INEN 0xFFC01564 /* GPIO Pin Port D Input Enable Register */ 487 487 488 488 /* GPIO Port E Register Names */ 489 - #define GPIO_E_CNFG 0xFFC01508 /* GPIO Pin Port E Configuration Register */ 490 - #define GPIO_E_D 0xFFC01518 /* GPIO Pin Port E Data Register */ 491 - #define GPIO_E_C 0xFFC01528 /* Clear GPIO Pin Port E Register */ 492 - #define GPIO_E_S 0xFFC01538 /* Set GPIO Pin Port E Register */ 493 - #define GPIO_E_T 0xFFC01548 /* Toggle GPIO Pin Port E Register */ 494 - #define GPIO_E_DIR 0xFFC01558 /* GPIO Pin Port E Direction Register */ 495 - #define GPIO_E_INEN 0xFFC01568 /* GPIO Pin Port E Input Enable Register */ 489 + #define PORTEIO_FER 0xFFC01508 /* GPIO Pin Port E Configuration Register */ 490 + #define PORTEIO 0xFFC01518 /* GPIO Pin Port E Data Register */ 491 + #define PORTEIO_CLEAR 0xFFC01528 /* Clear GPIO Pin Port E Register */ 492 + #define PORTEIO_SET 0xFFC01538 /* Set GPIO Pin Port E Register */ 493 + #define PORTEIO_TOGGLE 0xFFC01548 /* Toggle GPIO Pin Port E Register */ 494 + #define PORTEIO_DIR 0xFFC01558 /* GPIO Pin Port E Direction Register */ 495 + #define PORTEIO_INEN 0xFFC01568 /* GPIO Pin Port E Input Enable Register */ 496 496 497 497 /* DMA Controller 1 Traffic Control Registers (0xFFC01B00 - 0xFFC01BFF) */ 498 498
+2 -5
arch/blackfin/mach-bf538/include/mach/gpio.h
··· 1 1 /* 2 - * Copyright (C) 2008 Analog Devices Inc. 2 + * Copyright (C) 2008-2009 Analog Devices Inc. 3 3 * Licensed under the GPL-2 or later. 4 4 */ 5 5 ··· 7 7 #ifndef _MACH_GPIO_H_ 8 8 #define _MACH_GPIO_H_ 9 9 10 - /* FIXME: 11 - * For now only support PORTF GPIOs. 12 - * PORT C,D and E are for peripheral usage only 13 - */ 14 10 #define MAX_BLACKFIN_GPIOS 16 11 + #define BFIN_SPECIAL_GPIO_BANKS 3 15 12 16 13 #define GPIO_PF0 0 /* PF */ 17 14 #define GPIO_PF1 1
+1 -1
arch/blackfin/mach-bf538/include/mach/portmux.h
··· 7 7 #ifndef _MACH_PORTMUX_H_ 8 8 #define _MACH_PORTMUX_H_ 9 9 10 - #define MAX_RESOURCES MAX_BLACKFIN_GPIOS 10 + #define MAX_RESOURCES 64 11 11 12 12 #define P_TMR2 (P_DONTCARE) 13 13 #define P_TMR1 (P_DONTCARE)
+30
arch/blackfin/mach-common/dpmc_modes.S
··· 404 404 PM_SYS_PUSH(EBIU_FCTL) 405 405 #endif 406 406 407 + #ifdef PORTCIO_FER 408 + PM_SYS_PUSH16(PORTCIO_DIR) 409 + PM_SYS_PUSH16(PORTCIO_INEN) 410 + PM_SYS_PUSH16(PORTCIO) 411 + PM_SYS_PUSH16(PORTCIO_FER) 412 + PM_SYS_PUSH16(PORTDIO_DIR) 413 + PM_SYS_PUSH16(PORTDIO_INEN) 414 + PM_SYS_PUSH16(PORTDIO) 415 + PM_SYS_PUSH16(PORTDIO_FER) 416 + PM_SYS_PUSH16(PORTEIO_DIR) 417 + PM_SYS_PUSH16(PORTEIO_INEN) 418 + PM_SYS_PUSH16(PORTEIO) 419 + PM_SYS_PUSH16(PORTEIO_FER) 420 + #endif 421 + 407 422 PM_SYS_PUSH16(SYSCR) 408 423 409 424 /* Save Core MMRs */ ··· 730 715 P0.H = hi(PLL_CTL); 731 716 P0.L = lo(PLL_CTL); 732 717 PM_SYS_POP16(SYSCR) 718 + 719 + #ifdef PORTCIO_FER 720 + PM_SYS_POP16(PORTEIO_FER) 721 + PM_SYS_POP16(PORTEIO) 722 + PM_SYS_POP16(PORTEIO_INEN) 723 + PM_SYS_POP16(PORTEIO_DIR) 724 + PM_SYS_POP16(PORTDIO_FER) 725 + PM_SYS_POP16(PORTDIO) 726 + PM_SYS_POP16(PORTDIO_INEN) 727 + PM_SYS_POP16(PORTDIO_DIR) 728 + PM_SYS_POP16(PORTCIO_FER) 729 + PM_SYS_POP16(PORTCIO) 730 + PM_SYS_POP16(PORTCIO_INEN) 731 + PM_SYS_POP16(PORTCIO_DIR) 732 + #endif 733 733 734 734 #ifdef EBIU_FCTL 735 735 PM_SYS_POP(EBIU_FCTL)