aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFeng Kan <fkan@apm.com>2014-07-31 15:03:25 -0400
committerLinus Walleij <linus.walleij@linaro.org>2014-08-28 08:19:47 -0400
commit29cbf4589fc0dabef4dfc95dd9589c366ad2ec46 (patch)
tree76924b1c55f8ebaee291c4a302f89b192f1709ba
parente8126753a9a5896ed50c9d9bf66fa46f0f1982a6 (diff)
gpio: Add APM X-Gene SoC GPIO controller support
Add APM X-Gene SoC gpio controller driver. Signed-off-by: Feng Kan <fkan@apm.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
-rw-r--r--drivers/gpio/Kconfig9
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/gpio-xgene.c250
3 files changed, 260 insertions, 0 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 9de1515e5808..1fe93eb61927 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -334,6 +334,15 @@ config GPIO_TZ1090_PDC
334 help 334 help
335 Say yes here to support Toumaz Xenif TZ1090 PDC GPIOs. 335 Say yes here to support Toumaz Xenif TZ1090 PDC GPIOs.
336 336
337config GPIO_XGENE
338 bool "APM X-Gene GPIO controller support"
339 depends on ARM64 && OF_GPIO
340 help
341 This driver is to support the GPIO block within the APM X-Gene SoC
342 platform's generic flash controller. The GPIO pins are muxed with
343 the generic flash controller's address and data pins. Say yes
344 here to enable the GFC GPIO functionality.
345
337config GPIO_XILINX 346config GPIO_XILINX
338 bool "Xilinx GPIO support" 347 bool "Xilinx GPIO support"
339 depends on PPC_OF || MICROBLAZE || ARCH_ZYNQ 348 depends on PPC_OF || MICROBLAZE || ARCH_ZYNQ
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 5d024e396622..e5d346cf3b6e 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -101,6 +101,7 @@ obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o
101obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o 101obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o
102obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o 102obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o
103obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o 103obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o
104obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.o
104obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o 105obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o
105obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o 106obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o
106obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o 107obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o
diff --git a/drivers/gpio/gpio-xgene.c b/drivers/gpio/gpio-xgene.c
new file mode 100644
index 000000000000..e25ba14fbb64
--- /dev/null
+++ b/drivers/gpio/gpio-xgene.c
@@ -0,0 +1,250 @@
1/*
2 * AppliedMicro X-Gene SoC GPIO Driver
3 *
4 * Copyright (c) 2014, Applied Micro Circuits Corporation
5 * Author: Feng Kan <fkan@apm.com>.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <linux/module.h>
21#include <linux/kernel.h>
22#include <linux/init.h>
23#include <linux/io.h>
24#include <linux/spinlock.h>
25#include <linux/platform_device.h>
26#include <linux/gpio/driver.h>
27#include <linux/types.h>
28#include <linux/bitops.h>
29
30#define GPIO_SET_DR_OFFSET 0x0C
31#define GPIO_DATA_OFFSET 0x14
32#define GPIO_BANK_STRIDE 0x0C
33
34#define XGENE_GPIOS_PER_BANK 16
35#define XGENE_MAX_GPIO_BANKS 3
36#define XGENE_MAX_GPIOS (XGENE_GPIOS_PER_BANK * XGENE_MAX_GPIO_BANKS)
37
38#define GPIO_BIT_OFFSET(x) (x % XGENE_GPIOS_PER_BANK)
39#define GPIO_BANK_OFFSET(x) ((x / XGENE_GPIOS_PER_BANK) * GPIO_BANK_STRIDE)
40
41struct xgene_gpio;
42
43struct xgene_gpio {
44 struct gpio_chip chip;
45 void __iomem *base;
46 spinlock_t lock;
47#ifdef CONFIG_PM
48 u32 set_dr_val[XGENE_MAX_GPIO_BANKS];
49#endif
50};
51
52static inline struct xgene_gpio *to_xgene_gpio(struct gpio_chip *chip)
53{
54 return container_of(chip, struct xgene_gpio, chip);
55}
56
57static int xgene_gpio_get(struct gpio_chip *gc, unsigned int offset)
58{
59 struct xgene_gpio *chip = to_xgene_gpio(gc);
60 unsigned long bank_offset;
61 u32 bit_offset;
62
63 bank_offset = GPIO_DATA_OFFSET + GPIO_BANK_OFFSET(offset);
64 bit_offset = GPIO_BIT_OFFSET(offset);
65 return !!(ioread32(chip->base + bank_offset) & BIT(bit_offset));
66}
67
68static void __xgene_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
69{
70 struct xgene_gpio *chip = to_xgene_gpio(gc);
71 unsigned long bank_offset;
72 u32 setval, bit_offset;
73
74 bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset);
75 bit_offset = GPIO_BIT_OFFSET(offset) + XGENE_GPIOS_PER_BANK;
76
77 setval = ioread32(chip->base + bank_offset);
78 if (val)
79 setval |= BIT(bit_offset);
80 else
81 setval &= ~BIT(bit_offset);
82 iowrite32(setval, chip->base + bank_offset);
83}
84
85static void xgene_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
86{
87 struct xgene_gpio *chip = to_xgene_gpio(gc);
88 unsigned long flags;
89
90 spin_lock_irqsave(&chip->lock, flags);
91 __xgene_gpio_set(gc, offset, val);
92 spin_unlock_irqrestore(&chip->lock, flags);
93}
94
95static int xgene_gpio_dir_in(struct gpio_chip *gc, unsigned int offset)
96{
97 struct xgene_gpio *chip = to_xgene_gpio(gc);
98 unsigned long flags, bank_offset;
99 u32 dirval, bit_offset;
100
101 bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset);
102 bit_offset = GPIO_BIT_OFFSET(offset);
103
104 spin_lock_irqsave(&chip->lock, flags);
105
106 dirval = ioread32(chip->base + bank_offset);
107 dirval |= BIT(bit_offset);
108 iowrite32(dirval, chip->base + bank_offset);
109
110 spin_unlock_irqrestore(&chip->lock, flags);
111
112 return 0;
113}
114
115static int xgene_gpio_dir_out(struct gpio_chip *gc,
116 unsigned int offset, int val)
117{
118 struct xgene_gpio *chip = to_xgene_gpio(gc);
119 unsigned long flags, bank_offset;
120 u32 dirval, bit_offset;
121
122 bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset);
123 bit_offset = GPIO_BIT_OFFSET(offset);
124
125 spin_lock_irqsave(&chip->lock, flags);
126
127 dirval = ioread32(chip->base + bank_offset);
128 dirval &= ~BIT(bit_offset);
129 iowrite32(dirval, chip->base + bank_offset);
130 __xgene_gpio_set(gc, offset, val);
131
132 spin_unlock_irqrestore(&chip->lock, flags);
133
134 return 0;
135}
136
137#ifdef CONFIG_PM
138static int xgene_gpio_suspend(struct device *dev)
139{
140 struct xgene_gpio *gpio = dev_get_drvdata(dev);
141 unsigned long bank_offset;
142 unsigned int bank;
143
144 for (bank = 0; bank < XGENE_MAX_GPIO_BANKS; bank++) {
145 bank_offset = GPIO_SET_DR_OFFSET + bank * GPIO_BANK_STRIDE;
146 gpio->set_dr_val[bank] = ioread32(gpio->base + bank_offset);
147 }
148 return 0;
149}
150
151static int xgene_gpio_resume(struct device *dev)
152{
153 struct xgene_gpio *gpio = dev_get_drvdata(dev);
154 unsigned long bank_offset;
155 unsigned int bank;
156
157 for (bank = 0; bank < XGENE_MAX_GPIO_BANKS; bank++) {
158 bank_offset = GPIO_SET_DR_OFFSET + bank * GPIO_BANK_STRIDE;
159 iowrite32(gpio->set_dr_val[bank], gpio->base + bank_offset);
160 }
161 return 0;
162}
163
164static SIMPLE_DEV_PM_OPS(xgene_gpio_pm, xgene_gpio_suspend, xgene_gpio_resume);
165#define XGENE_GPIO_PM_OPS (&xgene_gpio_pm)
166#else
167#define XGENE_GPIO_PM_OPS NULL
168#endif
169
170static int xgene_gpio_probe(struct platform_device *pdev)
171{
172 struct resource *res;
173 struct xgene_gpio *gpio;
174 int err = 0;
175
176 gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
177 if (!gpio) {
178 err = -ENOMEM;
179 goto err;
180 }
181
182 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
183 gpio->base = devm_ioremap_nocache(&pdev->dev, res->start,
184 resource_size(res));
185 if (IS_ERR(gpio->base)) {
186 err = PTR_ERR(gpio->base);
187 goto err;
188 }
189
190 gpio->chip.ngpio = XGENE_MAX_GPIOS;
191
192 gpio->chip.dev = &pdev->dev;
193 gpio->chip.direction_input = xgene_gpio_dir_in;
194 gpio->chip.direction_output = xgene_gpio_dir_out;
195 gpio->chip.get = xgene_gpio_get;
196 gpio->chip.set = xgene_gpio_set;
197 gpio->chip.label = dev_name(&pdev->dev);
198 gpio->chip.base = -1;
199
200 platform_set_drvdata(pdev, gpio);
201
202 err = gpiochip_add(&gpio->chip);
203 if (err) {
204 dev_err(&pdev->dev,
205 "failed to register gpiochip.\n");
206 goto err;
207 }
208
209 dev_info(&pdev->dev, "X-Gene GPIO driver registered.\n");
210 return 0;
211err:
212 dev_err(&pdev->dev, "X-Gene GPIO driver registration failed.\n");
213 return err;
214}
215
216static int xgene_gpio_remove(struct platform_device *pdev)
217{
218 struct xgene_gpio *gpio = platform_get_drvdata(pdev);
219 int ret = 0;
220
221 ret = gpiochip_remove(&gpio->chip);
222 if (ret)
223 dev_err(&pdev->dev, "unable to remove gpio_chip.\n");
224 return ret;
225}
226
227#ifdef CONFIG_OF
228static const struct of_device_id xgene_gpio_of_match[] = {
229 { .compatible = "apm,xgene-gpio", },
230 {},
231};
232MODULE_DEVICE_TABLE(of, xgene_gpio_of_match);
233#endif
234
235static struct platform_driver xgene_gpio_driver = {
236 .driver = {
237 .name = "xgene-gpio",
238 .owner = THIS_MODULE,
239 .of_match_table = xgene_gpio_of_match,
240 .pm = XGENE_GPIO_PM_OPS,
241 },
242 .probe = xgene_gpio_probe,
243 .remove = xgene_gpio_remove,
244};
245
246module_platform_driver(xgene_gpio_driver);
247
248MODULE_AUTHOR("Feng Kan <fkan@apm.com>");
249MODULE_DESCRIPTION("APM X-Gene GPIO driver");
250MODULE_LICENSE("GPL");