aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/alchemy/common/gpio.c
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/common/gpio.c
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/common/gpio.c')
-rw-r--r--arch/mips/alchemy/common/gpio.c201
1 files changed, 0 insertions, 201 deletions
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