aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin
diff options
context:
space:
mode:
authorMichael Hennerich <michael.hennerich@analog.com>2009-09-28 08:23:41 -0400
committerMike Frysinger <vapier@gentoo.org>2009-12-15 00:14:05 -0500
commit621dd2474399237ca556a54037c3b8557e80d021 (patch)
tree53a8cef544f50c412d8239787f6dfa706624465e /arch/blackfin
parent46fe23ac39a0cdc4272946c1e3f9ff4fd5765a5b (diff)
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>
Diffstat (limited to 'arch/blackfin')
-rw-r--r--arch/blackfin/include/asm/gpio.h5
-rw-r--r--arch/blackfin/kernel/bfin_gpio.c97
-rw-r--r--arch/blackfin/mach-bf538/Makefile1
-rw-r--r--arch/blackfin/mach-bf538/ext-gpio.c123
-rw-r--r--arch/blackfin/mach-bf538/include/mach/defBF539.h42
-rw-r--r--arch/blackfin/mach-bf538/include/mach/gpio.h7
-rw-r--r--arch/blackfin/mach-bf538/include/mach/portmux.h2
-rw-r--r--arch/blackfin/mach-common/dpmc_modes.S30
8 files changed, 280 insertions, 27 deletions
diff --git a/arch/blackfin/include/asm/gpio.h b/arch/blackfin/include/asm/gpio.h
index 5b44d05ca53e..539468a05057 100644
--- a/arch/blackfin/include/asm/gpio.h
+++ b/arch/blackfin/include/asm/gpio.h
@@ -159,6 +159,11 @@ struct gpio_port_t {
159}; 159};
160#endif 160#endif
161 161
162#ifdef BFIN_SPECIAL_GPIO_BANKS
163void bfin_special_gpio_free(unsigned gpio);
164int bfin_special_gpio_request(unsigned gpio, const char *label);
165#endif
166
162#ifdef CONFIG_PM 167#ifdef CONFIG_PM
163 168
164unsigned int bfin_pm_standby_setup(void); 169unsigned int bfin_pm_standby_setup(void);
diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c
index c4161e03df78..a174596cc009 100644
--- a/arch/blackfin/kernel/bfin_gpio.c
+++ b/arch/blackfin/kernel/bfin_gpio.c
@@ -100,6 +100,12 @@ u8 pmux_offset[][16] = {
100}; 100};
101# endif 101# endif
102 102
103#elif defined(BF538_FAMILY)
104static unsigned short * const port_fer[] = {
105 (unsigned short *) PORTCIO_FER,
106 (unsigned short *) PORTDIO_FER,
107 (unsigned short *) PORTEIO_FER,
108};
103#endif 109#endif
104 110
105static unsigned short reserved_gpio_map[GPIO_BANK_NUM]; 111static unsigned short reserved_gpio_map[GPIO_BANK_NUM];
@@ -163,6 +169,27 @@ static int cmp_label(unsigned short ident, const char *label)
163 169
164static void port_setup(unsigned gpio, unsigned short usage) 170static void port_setup(unsigned gpio, unsigned short usage)
165{ 171{
172#if defined(BF538_FAMILY)
173 /*
174 * BF538/9 Port C,D and E are special.
175 * Inverted PORT_FER polarity on CDE and no PORF_FER on F
176 * Regular PORT F GPIOs are handled here, CDE are exclusively
177 * managed by GPIOLIB
178 */
179
180 if (gpio < MAX_BLACKFIN_GPIOS || gpio >= MAX_RESOURCES)
181 return;
182
183 gpio -= MAX_BLACKFIN_GPIOS;
184
185 if (usage == GPIO_USAGE)
186 *port_fer[gpio_bank(gpio)] |= gpio_bit(gpio);
187 else
188 *port_fer[gpio_bank(gpio)] &= ~gpio_bit(gpio);
189 SSYNC();
190 return;
191#endif
192
166 if (check_gpio(gpio)) 193 if (check_gpio(gpio))
167 return; 194 return;
168 195
@@ -981,6 +1008,76 @@ void bfin_gpio_free(unsigned gpio)
981} 1008}
982EXPORT_SYMBOL(bfin_gpio_free); 1009EXPORT_SYMBOL(bfin_gpio_free);
983 1010
1011#ifdef BFIN_SPECIAL_GPIO_BANKS
1012static unsigned short reserved_special_gpio_map[gpio_bank(MAX_RESOURCES)];
1013
1014int bfin_special_gpio_request(unsigned gpio, const char *label)
1015{
1016 unsigned long flags;
1017
1018 local_irq_save_hw(flags);
1019
1020 /*
1021 * Allow that the identical GPIO can
1022 * be requested from the same driver twice
1023 * Do nothing and return -
1024 */
1025
1026 if (cmp_label(gpio, label) == 0) {
1027 local_irq_restore_hw(flags);
1028 return 0;
1029 }
1030
1031 if (unlikely(reserved_special_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
1032 local_irq_restore_hw(flags);
1033 printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved by %s !\n",
1034 gpio, get_label(gpio));
1035
1036 return -EBUSY;
1037 }
1038 if (unlikely(reserved_peri_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
1039 local_irq_restore_hw(flags);
1040 printk(KERN_ERR
1041 "bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n",
1042 gpio, get_label(gpio));
1043
1044 return -EBUSY;
1045 }
1046
1047 reserved_special_gpio_map[gpio_bank(gpio)] |= gpio_bit(gpio);
1048 reserved_peri_map[gpio_bank(gpio)] |= gpio_bit(gpio);
1049
1050 set_label(gpio, label);
1051 local_irq_restore_hw(flags);
1052 port_setup(gpio, GPIO_USAGE);
1053
1054 return 0;
1055}
1056EXPORT_SYMBOL(bfin_special_gpio_request);
1057
1058void bfin_special_gpio_free(unsigned gpio)
1059{
1060 unsigned long flags;
1061
1062 might_sleep();
1063
1064 local_irq_save_hw(flags);
1065
1066 if (unlikely(!(reserved_special_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)))) {
1067 gpio_error(gpio);
1068 local_irq_restore_hw(flags);
1069 return;
1070 }
1071
1072 reserved_special_gpio_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
1073 reserved_peri_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
1074 set_label(gpio, "free");
1075 local_irq_restore_hw(flags);
1076}
1077EXPORT_SYMBOL(bfin_special_gpio_free);
1078#endif
1079
1080
984int bfin_gpio_irq_request(unsigned gpio, const char *label) 1081int bfin_gpio_irq_request(unsigned gpio, const char *label)
985{ 1082{
986 unsigned long flags; 1083 unsigned long flags;
diff --git a/arch/blackfin/mach-bf538/Makefile b/arch/blackfin/mach-bf538/Makefile
index 8cd2719684db..c0be54f2cd2b 100644
--- a/arch/blackfin/mach-bf538/Makefile
+++ b/arch/blackfin/mach-bf538/Makefile
@@ -3,3 +3,4 @@
3# 3#
4 4
5obj-y := ints-priority.o dma.o 5obj-y := ints-priority.o dma.o
6obj-$(CONFIG_GPIOLIB) += ext-gpio.o
diff --git a/arch/blackfin/mach-bf538/ext-gpio.c b/arch/blackfin/mach-bf538/ext-gpio.c
new file mode 100644
index 000000000000..180b1252679f
--- /dev/null
+++ b/arch/blackfin/mach-bf538/ext-gpio.c
@@ -0,0 +1,123 @@
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) \
16static inline u16 read_##reg(void __iomem *port) \
17 { return bfin_read16(port + off); } \
18static inline void write_##reg(void __iomem *port, u16 v) \
19 { bfin_write16(port + off, v); }
20
21DEFINE_REG(PORTIO, 0x00)
22DEFINE_REG(PORTIO_CLEAR, 0x10)
23DEFINE_REG(PORTIO_SET, 0x20)
24DEFINE_REG(PORTIO_DIR, 0x40)
25DEFINE_REG(PORTIO_INEN, 0x50)
26
27static 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
37static 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
43static 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
52static 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
60static 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
69static int bf538_gpio_request(struct gpio_chip *chip, unsigned gpio)
70{
71 return bfin_special_gpio_request(chip->base + gpio, chip->label);
72}
73
74static 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
81static 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
93static 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
105static 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
117static 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}
123arch_initcall(bf538_extgpio_setup);
diff --git a/arch/blackfin/mach-bf538/include/mach/defBF539.h b/arch/blackfin/mach-bf538/include/mach/defBF539.h
index 5f6c34dfd08e..1f1aeabc8c89 100644
--- a/arch/blackfin/mach-bf538/include/mach/defBF539.h
+++ b/arch/blackfin/mach-bf538/include/mach/defBF539.h
@@ -468,31 +468,31 @@
468/* General-Purpose Ports (0xFFC01500 - 0xFFC015FF) */ 468/* General-Purpose Ports (0xFFC01500 - 0xFFC015FF) */
469 469
470/* GPIO Port C Register Names */ 470/* GPIO Port C Register Names */
471#define GPIO_C_CNFG 0xFFC01500 /* GPIO Pin Port C Configuration Register */ 471#define PORTCIO_FER 0xFFC01500 /* GPIO Pin Port C Configuration Register */
472#define GPIO_C_D 0xFFC01510 /* GPIO Pin Port C Data Register */ 472#define PORTCIO 0xFFC01510 /* GPIO Pin Port C Data Register */
473#define GPIO_C_C 0xFFC01520 /* Clear GPIO Pin Port C Register */ 473#define PORTCIO_CLEAR 0xFFC01520 /* Clear GPIO Pin Port C Register */
474#define GPIO_C_S 0xFFC01530 /* Set GPIO Pin Port C Register */ 474#define PORTCIO_SET 0xFFC01530 /* Set GPIO Pin Port C Register */
475#define GPIO_C_T 0xFFC01540 /* Toggle GPIO Pin Port C Register */ 475#define PORTCIO_TOGGLE 0xFFC01540 /* Toggle GPIO Pin Port C Register */
476#define GPIO_C_DIR 0xFFC01550 /* GPIO Pin Port C Direction Register */ 476#define PORTCIO_DIR 0xFFC01550 /* GPIO Pin Port C Direction Register */
477#define GPIO_C_INEN 0xFFC01560 /* GPIO Pin Port C Input Enable Register */ 477#define PORTCIO_INEN 0xFFC01560 /* GPIO Pin Port C Input Enable Register */
478 478
479/* GPIO Port D Register Names */ 479/* GPIO Port D Register Names */
480#define GPIO_D_CNFG 0xFFC01504 /* GPIO Pin Port D Configuration Register */ 480#define PORTDIO_FER 0xFFC01504 /* GPIO Pin Port D Configuration Register */
481#define GPIO_D_D 0xFFC01514 /* GPIO Pin Port D Data Register */ 481#define PORTDIO 0xFFC01514 /* GPIO Pin Port D Data Register */
482#define GPIO_D_C 0xFFC01524 /* Clear GPIO Pin Port D Register */ 482#define PORTDIO_CLEAR 0xFFC01524 /* Clear GPIO Pin Port D Register */
483#define GPIO_D_S 0xFFC01534 /* Set GPIO Pin Port D Register */ 483#define PORTDIO_SET 0xFFC01534 /* Set GPIO Pin Port D Register */
484#define GPIO_D_T 0xFFC01544 /* Toggle GPIO Pin Port D Register */ 484#define PORTDIO_TOGGLE 0xFFC01544 /* Toggle GPIO Pin Port D Register */
485#define GPIO_D_DIR 0xFFC01554 /* GPIO Pin Port D Direction Register */ 485#define PORTDIO_DIR 0xFFC01554 /* GPIO Pin Port D Direction Register */
486#define GPIO_D_INEN 0xFFC01564 /* GPIO Pin Port D Input Enable Register */ 486#define PORTDIO_INEN 0xFFC01564 /* GPIO Pin Port D Input Enable Register */
487 487
488/* GPIO Port E Register Names */ 488/* GPIO Port E Register Names */
489#define GPIO_E_CNFG 0xFFC01508 /* GPIO Pin Port E Configuration Register */ 489#define PORTEIO_FER 0xFFC01508 /* GPIO Pin Port E Configuration Register */
490#define GPIO_E_D 0xFFC01518 /* GPIO Pin Port E Data Register */ 490#define PORTEIO 0xFFC01518 /* GPIO Pin Port E Data Register */
491#define GPIO_E_C 0xFFC01528 /* Clear GPIO Pin Port E Register */ 491#define PORTEIO_CLEAR 0xFFC01528 /* Clear GPIO Pin Port E Register */
492#define GPIO_E_S 0xFFC01538 /* Set GPIO Pin Port E Register */ 492#define PORTEIO_SET 0xFFC01538 /* Set GPIO Pin Port E Register */
493#define GPIO_E_T 0xFFC01548 /* Toggle GPIO Pin Port E Register */ 493#define PORTEIO_TOGGLE 0xFFC01548 /* Toggle GPIO Pin Port E Register */
494#define GPIO_E_DIR 0xFFC01558 /* GPIO Pin Port E Direction Register */ 494#define PORTEIO_DIR 0xFFC01558 /* GPIO Pin Port E Direction Register */
495#define GPIO_E_INEN 0xFFC01568 /* GPIO Pin Port E Input Enable Register */ 495#define PORTEIO_INEN 0xFFC01568 /* GPIO Pin Port E Input Enable Register */
496 496
497/* DMA Controller 1 Traffic Control Registers (0xFFC01B00 - 0xFFC01BFF) */ 497/* DMA Controller 1 Traffic Control Registers (0xFFC01B00 - 0xFFC01BFF) */
498 498
diff --git a/arch/blackfin/mach-bf538/include/mach/gpio.h b/arch/blackfin/mach-bf538/include/mach/gpio.h
index 295c78a465c2..0c346fba9619 100644
--- a/arch/blackfin/mach-bf538/include/mach/gpio.h
+++ b/arch/blackfin/mach-bf538/include/mach/gpio.h
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2008 Analog Devices Inc. 2 * Copyright (C) 2008-2009 Analog Devices Inc.
3 * Licensed under the GPL-2 or later. 3 * Licensed under the GPL-2 or later.
4 */ 4 */
5 5
@@ -7,11 +7,8 @@
7#ifndef _MACH_GPIO_H_ 7#ifndef _MACH_GPIO_H_
8#define _MACH_GPIO_H_ 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#define MAX_BLACKFIN_GPIOS 16 10#define MAX_BLACKFIN_GPIOS 16
11#define BFIN_SPECIAL_GPIO_BANKS 3
15 12
16#define GPIO_PF0 0 /* PF */ 13#define GPIO_PF0 0 /* PF */
17#define GPIO_PF1 1 14#define GPIO_PF1 1
diff --git a/arch/blackfin/mach-bf538/include/mach/portmux.h b/arch/blackfin/mach-bf538/include/mach/portmux.h
index 6121cf8b5872..0083ba13ee9e 100644
--- a/arch/blackfin/mach-bf538/include/mach/portmux.h
+++ b/arch/blackfin/mach-bf538/include/mach/portmux.h
@@ -7,7 +7,7 @@
7#ifndef _MACH_PORTMUX_H_ 7#ifndef _MACH_PORTMUX_H_
8#define _MACH_PORTMUX_H_ 8#define _MACH_PORTMUX_H_
9 9
10#define MAX_RESOURCES MAX_BLACKFIN_GPIOS 10#define MAX_RESOURCES 64
11 11
12#define P_TMR2 (P_DONTCARE) 12#define P_TMR2 (P_DONTCARE)
13#define P_TMR1 (P_DONTCARE) 13#define P_TMR1 (P_DONTCARE)
diff --git a/arch/blackfin/mach-common/dpmc_modes.S b/arch/blackfin/mach-common/dpmc_modes.S
index 8009a512fb11..b03716896051 100644
--- a/arch/blackfin/mach-common/dpmc_modes.S
+++ b/arch/blackfin/mach-common/dpmc_modes.S
@@ -404,6 +404,21 @@ ENTRY(_do_hibernate)
404 PM_SYS_PUSH(EBIU_FCTL) 404 PM_SYS_PUSH(EBIU_FCTL)
405#endif 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 PM_SYS_PUSH16(SYSCR) 422 PM_SYS_PUSH16(SYSCR)
408 423
409 /* Save Core MMRs */ 424 /* Save Core MMRs */
@@ -716,6 +731,21 @@ ENTRY(_do_hibernate)
716 P0.L = lo(PLL_CTL); 731 P0.L = lo(PLL_CTL);
717 PM_SYS_POP16(SYSCR) 732 PM_SYS_POP16(SYSCR)
718 733
734#ifdef PORTCIO_FER
735 PM_SYS_POP16(PORTEIO_FER)
736 PM_SYS_POP16(PORTEIO)
737 PM_SYS_POP16(PORTEIO_INEN)
738 PM_SYS_POP16(PORTEIO_DIR)
739 PM_SYS_POP16(PORTDIO_FER)
740 PM_SYS_POP16(PORTDIO)
741 PM_SYS_POP16(PORTDIO_INEN)
742 PM_SYS_POP16(PORTDIO_DIR)
743 PM_SYS_POP16(PORTCIO_FER)
744 PM_SYS_POP16(PORTCIO)
745 PM_SYS_POP16(PORTCIO_INEN)
746 PM_SYS_POP16(PORTCIO_DIR)
747#endif
748
719#ifdef EBIU_FCTL 749#ifdef EBIU_FCTL
720 PM_SYS_POP(EBIU_FCTL) 750 PM_SYS_POP(EBIU_FCTL)
721 PM_SYS_POP(EBIU_MODE) 751 PM_SYS_POP(EBIU_MODE)