aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/alchemy
diff options
context:
space:
mode:
authorManuel Lauss <manuel.lauss@googlemail.com>2009-06-06 08:09:55 -0400
committerRalf Baechle <ralf@linux-mips.org>2009-06-17 06:06:28 -0400
commit51e02b02e650183ff1277bcbad6a01d6ea0e9edb (patch)
tree413dfa5c93e2d01a42309f1cee6d6bf26d871962 /arch/mips/alchemy
parenteeb09e6545bf68222798ccf3f355560a9e406435 (diff)
MIPS: Alchemy: Rewrite GPIO support.
The current in-kernel Alchemy GPIO support is far too inflexible for all my use cases. To address this, the following changes are made: * create generic functions which deal with manipulating the on-chip GPIO1/2 blocks. Such functions are universally useful. * Macros for GPIO2 shared interrupt management and block control. * support for both built-in CONFIG_GPIOLIB and fast, inlined GPIO macros. If CONFIG_GPIOLIB is not enabled, provide linux gpio framework compatibility by directly inlining the GPIO1/2 functions. GPIO access is limited to on-chip ones and they can be accessed as documented in the datasheets (GPIO0-31 and 200-215). If CONFIG_GPIOLIB is selected, two (2) gpio_chip-s, one for GPIO1 and one for GPIO2, are registered. GPIOs can still be accessed by using the numberspace established in the databooks. However this is not yet flexible enough for my uses: My Alchemy systems have a documented "external" gpio interface (fixed, different numberspace) and can support a variety of baseboards, some of which are equipped with I2C gpio expanders. I want to be able to provide the default 16 GPIOs of the CPU board numbered as 0..15 and also support gpio expanders, if present, starting as gpio16. To achieve this, a new Kconfig symbol for Alchemy is introduced, CONFIG_ALCHEMY_GPIO_INDIRECT, which boards can enable to signal that they don't want the Alchemy numberspace exposed to the outside world, but instead want to provide their own. Boards are now respon- sible for providing the linux gpio interface glue code (either in a custom gpio.h header (in board include directory) or with gpio_chips). To make the board-specific inlined gpio functions work, the MIPS Makefile must be changed so that the mach-au1x00/gpio.h header is included _after_ the board headers, by moving the inclusion of the mach-au1x00/ to the end of the header list. See arch/mips/include/asm/mach-au1x00/gpio.h for more info. Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com> Acked-by: Florian Fainelli <florian@openwrt.org> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/alchemy')
-rw-r--r--arch/mips/alchemy/Kconfig19
-rw-r--r--arch/mips/alchemy/common/Makefile9
-rw-r--r--arch/mips/alchemy/common/gpio.c201
-rw-r--r--arch/mips/alchemy/common/gpiolib-au1000.c130
4 files changed, 156 insertions, 203 deletions
diff --git a/arch/mips/alchemy/Kconfig b/arch/mips/alchemy/Kconfig
index 8128aebfb155..00b498e97c83 100644
--- a/arch/mips/alchemy/Kconfig
+++ b/arch/mips/alchemy/Kconfig
@@ -1,3 +1,14 @@
1# au1000-style gpio
2config ALCHEMY_GPIO_AU1000
3 bool
4
5# select this in your board config if you don't want to use the gpio
6# namespace as documented in the manuals. In this case however you need
7# to create the necessary gpio_* functions in your board code/headers!
8# see arch/mips/include/asm/mach-au1x00/gpio.h for more information.
9config ALCHEMY_GPIO_INDIRECT
10 def_bool n
11
1choice 12choice
2 prompt "Machine type" 13 prompt "Machine type"
3 depends on MACH_ALCHEMY 14 depends on MACH_ALCHEMY
@@ -108,22 +119,27 @@ endchoice
108config SOC_AU1000 119config SOC_AU1000
109 bool 120 bool
110 select SOC_AU1X00 121 select SOC_AU1X00
122 select ALCHEMY_GPIO_AU1000
111 123
112config SOC_AU1100 124config SOC_AU1100
113 bool 125 bool
114 select SOC_AU1X00 126 select SOC_AU1X00
127 select ALCHEMY_GPIO_AU1000
115 128
116config SOC_AU1500 129config SOC_AU1500
117 bool 130 bool
118 select SOC_AU1X00 131 select SOC_AU1X00
132 select ALCHEMY_GPIO_AU1000
119 133
120config SOC_AU1550 134config SOC_AU1550
121 bool 135 bool
122 select SOC_AU1X00 136 select SOC_AU1X00
137 select ALCHEMY_GPIO_AU1000
123 138
124config SOC_AU1200 139config SOC_AU1200
125 bool 140 bool
126 select SOC_AU1X00 141 select SOC_AU1X00
142 select ALCHEMY_GPIO_AU1000
127 143
128config SOC_AU1X00 144config SOC_AU1X00
129 bool 145 bool
@@ -134,4 +150,5 @@ config SOC_AU1X00
134 select SYS_HAS_CPU_MIPS32_R1 150 select SYS_HAS_CPU_MIPS32_R1
135 select SYS_SUPPORTS_32BIT_KERNEL 151 select SYS_SUPPORTS_32BIT_KERNEL
136 select SYS_SUPPORTS_APM_EMULATION 152 select SYS_SUPPORTS_APM_EMULATION
137 select ARCH_REQUIRE_GPIOLIB 153 select GENERIC_GPIO
154 select ARCH_WANT_OPTIONAL_GPIOLIB
diff --git a/arch/mips/alchemy/common/Makefile b/arch/mips/alchemy/common/Makefile
index d50d4764eafe..b67fb512529d 100644
--- a/arch/mips/alchemy/common/Makefile
+++ b/arch/mips/alchemy/common/Makefile
@@ -7,7 +7,14 @@
7 7
8obj-y += prom.o irq.o puts.o time.o reset.o \ 8obj-y += prom.o irq.o puts.o time.o reset.o \
9 clocks.o platform.o power.o setup.o \ 9 clocks.o platform.o power.o setup.o \
10 sleeper.o dma.o dbdma.o gpio.o 10 sleeper.o dma.o dbdma.o
11
12# optional gpiolib support
13ifeq ($(CONFIG_ALCHEMY_GPIO_INDIRECT),)
14 ifeq ($(CONFIG_GPIOLIB),y)
15 obj-$(CONFIG_ALCHEMY_GPIO_AU1000) += gpiolib-au1000.o
16 endif
17endif
11 18
12obj-$(CONFIG_PCI) += pci.o 19obj-$(CONFIG_PCI) += pci.o
13 20
diff --git a/arch/mips/alchemy/common/gpio.c b/arch/mips/alchemy/common/gpio.c
deleted file mode 100644
index 91a9c4436c39..000000000000
--- a/arch/mips/alchemy/common/gpio.c
+++ /dev/null
@@ -1,201 +0,0 @@
1/*
2 * Copyright (C) 2007-2009, OpenWrt.org, Florian Fainelli <florian@openwrt.org>
3 * Architecture specific GPIO support
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
11 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
13 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
14 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
15 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
16 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
17 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
18 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
19 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 * Notes :
26 * au1000 SoC have only one GPIO line : GPIO1
27 * others have a second one : GPIO2
28 */
29
30#include <linux/kernel.h>
31#include <linux/module.h>
32#include <linux/types.h>
33#include <linux/platform_device.h>
34#include <linux/gpio.h>
35
36#include <asm/mach-au1x00/au1000.h>
37#include <asm/gpio.h>
38
39struct au1000_gpio_chip {
40 struct gpio_chip chip;
41 void __iomem *regbase;
42};
43
44#if !defined(CONFIG_SOC_AU1000)
45static int au1000_gpio2_get(struct gpio_chip *chip, unsigned offset)
46{
47 u32 mask = 1 << offset;
48 struct au1000_gpio_chip *gpch;
49
50 gpch = container_of(chip, struct au1000_gpio_chip, chip);
51 return readl(gpch->regbase + AU1000_GPIO2_ST) & mask;
52}
53
54static void au1000_gpio2_set(struct gpio_chip *chip,
55 unsigned offset, int value)
56{
57 u32 mask = ((GPIO2_OUT_EN_MASK << offset) | (!!value << offset));
58 struct au1000_gpio_chip *gpch;
59 unsigned long flags;
60
61 gpch = container_of(chip, struct au1000_gpio_chip, chip);
62
63 local_irq_save(flags);
64 writel(mask, gpch->regbase + AU1000_GPIO2_OUT);
65 local_irq_restore(flags);
66}
67
68static int au1000_gpio2_direction_input(struct gpio_chip *chip, unsigned offset)
69{
70 u32 mask = 1 << offset;
71 u32 tmp;
72 struct au1000_gpio_chip *gpch;
73 unsigned long flags;
74
75 gpch = container_of(chip, struct au1000_gpio_chip, chip);
76
77 local_irq_save(flags);
78 tmp = readl(gpch->regbase + AU1000_GPIO2_DIR);
79 tmp &= ~mask;
80 writel(tmp, gpch->regbase + AU1000_GPIO2_DIR);
81 local_irq_restore(flags);
82
83 return 0;
84}
85
86static int au1000_gpio2_direction_output(struct gpio_chip *chip,
87 unsigned offset, int value)
88{
89 u32 mask = 1 << offset;
90 u32 out_mask = ((GPIO2_OUT_EN_MASK << offset) | (!!value << offset));
91 u32 tmp;
92 struct au1000_gpio_chip *gpch;
93 unsigned long flags;
94
95 gpch = container_of(chip, struct au1000_gpio_chip, chip);
96
97 local_irq_save(flags);
98 tmp = readl(gpch->regbase + AU1000_GPIO2_DIR);
99 tmp |= mask;
100 writel(tmp, gpch->regbase + AU1000_GPIO2_DIR);
101 writel(out_mask, gpch->regbase + AU1000_GPIO2_OUT);
102 local_irq_restore(flags);
103
104 return 0;
105}
106#endif /* !defined(CONFIG_SOC_AU1000) */
107
108static int au1000_gpio1_get(struct gpio_chip *chip, unsigned offset)
109{
110 u32 mask = 1 << offset;
111 struct au1000_gpio_chip *gpch;
112
113 gpch = container_of(chip, struct au1000_gpio_chip, chip);
114 return readl(gpch->regbase + AU1000_GPIO1_ST) & mask;
115}
116
117static void au1000_gpio1_set(struct gpio_chip *chip,
118 unsigned offset, int value)
119{
120 u32 mask = 1 << offset;
121 u32 reg_offset;
122 struct au1000_gpio_chip *gpch;
123 unsigned long flags;
124
125 gpch = container_of(chip, struct au1000_gpio_chip, chip);
126
127 if (value)
128 reg_offset = AU1000_GPIO1_OUT;
129 else
130 reg_offset = AU1000_GPIO1_CLR;
131
132 local_irq_save(flags);
133 writel(mask, gpch->regbase + reg_offset);
134 local_irq_restore(flags);
135}
136
137static int au1000_gpio1_direction_input(struct gpio_chip *chip, unsigned offset)
138{
139 u32 mask = 1 << offset;
140 struct au1000_gpio_chip *gpch;
141
142 gpch = container_of(chip, struct au1000_gpio_chip, chip);
143 writel(mask, gpch->regbase + AU1000_GPIO1_ST);
144
145 return 0;
146}
147
148static int au1000_gpio1_direction_output(struct gpio_chip *chip,
149 unsigned offset, int value)
150{
151 u32 mask = 1 << offset;
152 struct au1000_gpio_chip *gpch;
153
154 gpch = container_of(chip, struct au1000_gpio_chip, chip);
155
156 writel(mask, gpch->regbase + AU1000_GPIO1_TRI_OUT);
157 au1000_gpio1_set(chip, offset, value);
158
159 return 0;
160}
161
162struct au1000_gpio_chip au1000_gpio_chip[] = {
163 [0] = {
164 .regbase = (void __iomem *)SYS_BASE,
165 .chip = {
166 .label = "au1000-gpio1",
167 .direction_input = au1000_gpio1_direction_input,
168 .direction_output = au1000_gpio1_direction_output,
169 .get = au1000_gpio1_get,
170 .set = au1000_gpio1_set,
171 .base = 0,
172 .ngpio = 32,
173 },
174 },
175#if !defined(CONFIG_SOC_AU1000)
176 [1] = {
177 .regbase = (void __iomem *)GPIO2_BASE,
178 .chip = {
179 .label = "au1000-gpio2",
180 .direction_input = au1000_gpio2_direction_input,
181 .direction_output = au1000_gpio2_direction_output,
182 .get = au1000_gpio2_get,
183 .set = au1000_gpio2_set,
184 .base = AU1XXX_GPIO_BASE,
185 .ngpio = 32,
186 },
187 },
188#endif
189};
190
191static int __init au1000_gpio_init(void)
192{
193 gpiochip_add(&au1000_gpio_chip[0].chip);
194#if !defined(CONFIG_SOC_AU1000)
195 gpiochip_add(&au1000_gpio_chip[1].chip);
196#endif
197
198 return 0;
199}
200arch_initcall(au1000_gpio_init);
201
diff --git a/arch/mips/alchemy/common/gpiolib-au1000.c b/arch/mips/alchemy/common/gpiolib-au1000.c
new file mode 100644
index 000000000000..1bfa91f939f4
--- /dev/null
+++ b/arch/mips/alchemy/common/gpiolib-au1000.c
@@ -0,0 +1,130 @@
1/*
2 * Copyright (C) 2007-2009, OpenWrt.org, Florian Fainelli <florian@openwrt.org>
3 * GPIOLIB support for Au1000, Au1500, Au1100, Au1550 and Au12x0.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
11 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
13 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
14 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
15 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
16 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
17 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
18 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
19 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 * Notes :
26 * au1000 SoC have only one GPIO block : GPIO1
27 * Au1100, Au15x0, Au12x0 have a second one : GPIO2
28 */
29
30#include <linux/kernel.h>
31#include <linux/module.h>
32#include <linux/types.h>
33#include <linux/platform_device.h>
34#include <linux/gpio.h>
35
36#include <asm/mach-au1x00/au1000.h>
37#include <asm/mach-au1x00/gpio.h>
38
39#if !defined(CONFIG_SOC_AU1000)
40static int gpio2_get(struct gpio_chip *chip, unsigned offset)
41{
42 return alchemy_gpio2_get_value(offset + ALCHEMY_GPIO2_BASE);
43}
44
45static void gpio2_set(struct gpio_chip *chip, unsigned offset, int value)
46{
47 alchemy_gpio2_set_value(offset + ALCHEMY_GPIO2_BASE, value);
48}
49
50static int gpio2_direction_input(struct gpio_chip *chip, unsigned offset)
51{
52 return alchemy_gpio2_direction_input(offset + ALCHEMY_GPIO2_BASE);
53}
54
55static int gpio2_direction_output(struct gpio_chip *chip, unsigned offset,
56 int value)
57{
58 return alchemy_gpio2_direction_output(offset + ALCHEMY_GPIO2_BASE,
59 value);
60}
61
62static int gpio2_to_irq(struct gpio_chip *chip, unsigned offset)
63{
64 return alchemy_gpio2_to_irq(offset + ALCHEMY_GPIO2_BASE);
65}
66#endif /* !defined(CONFIG_SOC_AU1000) */
67
68static int gpio1_get(struct gpio_chip *chip, unsigned offset)
69{
70 return alchemy_gpio1_get_value(offset + ALCHEMY_GPIO1_BASE);
71}
72
73static void gpio1_set(struct gpio_chip *chip,
74 unsigned offset, int value)
75{
76 alchemy_gpio1_set_value(offset + ALCHEMY_GPIO1_BASE, value);
77}
78
79static int gpio1_direction_input(struct gpio_chip *chip, unsigned offset)
80{
81 return alchemy_gpio1_direction_input(offset + ALCHEMY_GPIO1_BASE);
82}
83
84static int gpio1_direction_output(struct gpio_chip *chip,
85 unsigned offset, int value)
86{
87 return alchemy_gpio1_direction_output(offset + ALCHEMY_GPIO1_BASE,
88 value);
89}
90
91static int gpio1_to_irq(struct gpio_chip *chip, unsigned offset)
92{
93 return alchemy_gpio1_to_irq(offset + ALCHEMY_GPIO1_BASE);
94}
95
96struct gpio_chip alchemy_gpio_chip[] = {
97 [0] = {
98 .label = "alchemy-gpio1",
99 .direction_input = gpio1_direction_input,
100 .direction_output = gpio1_direction_output,
101 .get = gpio1_get,
102 .set = gpio1_set,
103 .to_irq = gpio1_to_irq,
104 .base = ALCHEMY_GPIO1_BASE,
105 .ngpio = ALCHEMY_GPIO1_NUM,
106 },
107#if !defined(CONFIG_SOC_AU1000)
108 [1] = {
109 .label = "alchemy-gpio2",
110 .direction_input = gpio2_direction_input,
111 .direction_output = gpio2_direction_output,
112 .get = gpio2_get,
113 .set = gpio2_set,
114 .to_irq = gpio2_to_irq,
115 .base = ALCHEMY_GPIO2_BASE,
116 .ngpio = ALCHEMY_GPIO2_NUM,
117 },
118#endif
119};
120
121static int __init alchemy_gpiolib_init(void)
122{
123 gpiochip_add(&alchemy_gpio_chip[0]);
124#if !defined(CONFIG_SOC_AU1000)
125 gpiochip_add(&alchemy_gpio_chip[1]);
126#endif
127
128 return 0;
129}
130arch_initcall(alchemy_gpiolib_init);