blob: 91a9c4436c392ad266237850bca5acf49bda761f [file] [log] [blame]
Pete Popov2cce8262005-09-18 11:18:10 +00001/*
Florian Fainelli47c969e2009-01-15 16:46:48 +01002 * Copyright (C) 2007-2009, OpenWrt.org, Florian Fainelli <florian@openwrt.org>
Florian Fainelli4ead1682007-05-22 21:44:42 +02003 * Architecture specific GPIO support
4 *
Pete Popov2cce8262005-09-18 11:18:10 +00005 * 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.
Florian Fainelli4ead1682007-05-22 21:44:42 +020024 *
25 * Notes :
26 * au1000 SoC have only one GPIO line : GPIO1
27 * others have a second one : GPIO2
Pete Popov2cce8262005-09-18 11:18:10 +000028 */
Florian Fainelli4ead1682007-05-22 21:44:42 +020029
Florian Fainelli47c969e2009-01-15 16:46:48 +010030#include <linux/kernel.h>
Pete Popov2cce8262005-09-18 11:18:10 +000031#include <linux/module.h>
Florian Fainelli47c969e2009-01-15 16:46:48 +010032#include <linux/types.h>
33#include <linux/platform_device.h>
34#include <linux/gpio.h>
Florian Fainelli4ead1682007-05-22 21:44:42 +020035
Florian Fainelli4ead1682007-05-22 21:44:42 +020036#include <asm/mach-au1x00/au1000.h>
37#include <asm/gpio.h>
Pete Popov2cce8262005-09-18 11:18:10 +000038
Florian Fainelli47c969e2009-01-15 16:46:48 +010039struct au1000_gpio_chip {
40 struct gpio_chip chip;
41 void __iomem *regbase;
42};
43
Pete Popov2cce8262005-09-18 11:18:10 +000044#if !defined(CONFIG_SOC_AU1000)
Florian Fainelli47c969e2009-01-15 16:46:48 +010045static int au1000_gpio2_get(struct gpio_chip *chip, unsigned offset)
Pete Popov2cce8262005-09-18 11:18:10 +000046{
Florian Fainelli47c969e2009-01-15 16:46:48 +010047 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;
Pete Popov2cce8262005-09-18 11:18:10 +000052}
53
Florian Fainelli47c969e2009-01-15 16:46:48 +010054static void au1000_gpio2_set(struct gpio_chip *chip,
55 unsigned offset, int value)
Pete Popov2cce8262005-09-18 11:18:10 +000056{
Florian Fainelli47c969e2009-01-15 16:46:48 +010057 u32 mask = ((GPIO2_OUT_EN_MASK << offset) | (!!value << offset));
58 struct au1000_gpio_chip *gpch;
59 unsigned long flags;
Pete Popov2cce8262005-09-18 11:18:10 +000060
Florian Fainelli47c969e2009-01-15 16:46:48 +010061 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);
Pete Popov2cce8262005-09-18 11:18:10 +000066}
67
Florian Fainelli47c969e2009-01-15 16:46:48 +010068static int au1000_gpio2_direction_input(struct gpio_chip *chip, unsigned offset)
Pete Popov2cce8262005-09-18 11:18:10 +000069{
Florian Fainelli47c969e2009-01-15 16:46:48 +010070 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
Florian Fainelli4ead1682007-05-22 21:44:42 +020083 return 0;
Pete Popov2cce8262005-09-18 11:18:10 +000084}
85
Florian Fainelli47c969e2009-01-15 16:46:48 +010086static int au1000_gpio2_direction_output(struct gpio_chip *chip,
87 unsigned offset, int value)
Pete Popov2cce8262005-09-18 11:18:10 +000088{
Florian Fainelli47c969e2009-01-15 16:46:48 +010089 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
Florian Fainelli4ead1682007-05-22 21:44:42 +0200104 return 0;
105}
Florian Fainelli4ead1682007-05-22 21:44:42 +0200106#endif /* !defined(CONFIG_SOC_AU1000) */
107
Florian Fainelli47c969e2009-01-15 16:46:48 +0100108static int au1000_gpio1_get(struct gpio_chip *chip, unsigned offset)
Florian Fainelli4ead1682007-05-22 21:44:42 +0200109{
Florian Fainelli47c969e2009-01-15 16:46:48 +0100110 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;
Florian Fainelli4ead1682007-05-22 21:44:42 +0200115}
116
Florian Fainelli47c969e2009-01-15 16:46:48 +0100117static void au1000_gpio1_set(struct gpio_chip *chip,
118 unsigned offset, int value)
Florian Fainelli4ead1682007-05-22 21:44:42 +0200119{
Florian Fainelli47c969e2009-01-15 16:46:48 +0100120 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
Florian Fainelli4ead1682007-05-22 21:44:42 +0200127 if (value)
Florian Fainelli47c969e2009-01-15 16:46:48 +0100128 reg_offset = AU1000_GPIO1_OUT;
Pete Popov2cce8262005-09-18 11:18:10 +0000129 else
Florian Fainelli47c969e2009-01-15 16:46:48 +0100130 reg_offset = AU1000_GPIO1_CLR;
131
132 local_irq_save(flags);
133 writel(mask, gpch->regbase + reg_offset);
134 local_irq_restore(flags);
Pete Popov2cce8262005-09-18 11:18:10 +0000135}
136
Florian Fainelli47c969e2009-01-15 16:46:48 +0100137static int au1000_gpio1_direction_input(struct gpio_chip *chip, unsigned offset)
Pete Popov2cce8262005-09-18 11:18:10 +0000138{
Florian Fainelli47c969e2009-01-15 16:46:48 +0100139 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
Florian Fainelli4ead1682007-05-22 21:44:42 +0200145 return 0;
Pete Popov2cce8262005-09-18 11:18:10 +0000146}
147
Florian Fainelli47c969e2009-01-15 16:46:48 +0100148static int au1000_gpio1_direction_output(struct gpio_chip *chip,
149 unsigned offset, int value)
Pete Popov2cce8262005-09-18 11:18:10 +0000150{
Florian Fainelli47c969e2009-01-15 16:46:48 +0100151 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
Florian Fainelli4ead1682007-05-22 21:44:42 +0200159 return 0;
160}
161
Florian Fainelli47c969e2009-01-15 16:46:48 +0100162struct 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 },
Pete Popov2cce8262005-09-18 11:18:10 +0000188#endif
Florian Fainelli47c969e2009-01-15 16:46:48 +0100189};
Florian Fainelli4ead1682007-05-22 21:44:42 +0200190
Florian Fainelli47c969e2009-01-15 16:46:48 +0100191static int __init au1000_gpio_init(void)
Pete Popov2cce8262005-09-18 11:18:10 +0000192{
Florian Fainelli47c969e2009-01-15 16:46:48 +0100193 gpiochip_add(&au1000_gpio_chip[0].chip);
194#if !defined(CONFIG_SOC_AU1000)
195 gpiochip_add(&au1000_gpio_chip[1].chip);
Pete Popov2cce8262005-09-18 11:18:10 +0000196#endif
Yoichi Yuasa7acae222007-08-02 12:48:00 +0900197
Florian Fainelli47c969e2009-01-15 16:46:48 +0100198 return 0;
Pete Popov2cce8262005-09-18 11:18:10 +0000199}
Florian Fainelli47c969e2009-01-15 16:46:48 +0100200arch_initcall(au1000_gpio_init);
Florian Fainelli4ead1682007-05-22 21:44:42 +0200201