aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio
diff options
context:
space:
mode:
authorFabian Vogt <fabian@ritter-vogt.de>2014-02-24 14:54:58 -0500
committerLinus Walleij <linus.walleij@linaro.org>2014-02-27 04:30:42 -0500
commit9af4d80ba5666579944f570e113c5a87444afbde (patch)
treed14c2c723ccc0b80134b8745b08ccbf7f2dbfe4d /drivers/gpio
parentf29b9d13ddb32f84f33197042ca187c531cfda7a (diff)
gpio: New driver for LSI ZEVIO SoCs
This driver supports the GPIO controller found in LSI ZEVIO SoCs. It has been successfully tested on a TI nspire CX calculator. Signed-off-by: Fabian Vogt <fabian@ritter-vogt.de> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/Kconfig6
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/gpio-zevio.c220
3 files changed, 227 insertions, 0 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 3bddd36d2d12..5e8bd21240a1 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -145,6 +145,12 @@ config GPIO_EP93XX
145 depends on ARCH_EP93XX 145 depends on ARCH_EP93XX
146 select GPIO_GENERIC 146 select GPIO_GENERIC
147 147
148config GPIO_ZEVIO
149 bool "LSI ZEVIO SoC memory mapped GPIOs"
150 depends on OF
151 help
152 Say yes here to support the GPIO controller in LSI ZEVIO SoCs.
153
148config GPIO_MM_LANTIQ 154config GPIO_MM_LANTIQ
149 bool "Lantiq Memory mapped GPIOs" 155 bool "Lantiq Memory mapped GPIOs"
150 depends on LANTIQ && SOC_XWAY 156 depends on LANTIQ && SOC_XWAY
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 5d50179ece16..b8453750e502 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -99,3 +99,4 @@ obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o
99obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o 99obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o
100obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o 100obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o
101obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o 101obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o
102obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o
diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c
new file mode 100644
index 000000000000..9bf5034b6cdb
--- /dev/null
+++ b/drivers/gpio/gpio-zevio.c
@@ -0,0 +1,220 @@
1/*
2 * GPIO controller in LSI ZEVIO SoCs.
3 *
4 * Author: Fabian Vogt <fabian@ritter-vogt.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/spinlock.h>
12#include <linux/errno.h>
13#include <linux/module.h>
14#include <linux/bitops.h>
15#include <linux/io.h>
16#include <linux/of_device.h>
17#include <linux/of_gpio.h>
18#include <linux/slab.h>
19#include <linux/gpio.h>
20
21/*
22 * Memory layout:
23 * This chip has four gpio sections, each controls 8 GPIOs.
24 * Bit 0 in section 0 is GPIO 0, bit 2 in section 1 is GPIO 10.
25 * Disclaimer: Reverse engineered!
26 * For more information refer to:
27 * http://hackspire.unsads.com/wiki/index.php/Memory-mapped_I/O_ports#90000000_-_General_Purpose_I.2FO_.28GPIO.29
28 *
29 * 0x00-0x3F: Section 0
30 * +0x00: Masked interrupt status (read-only)
31 * +0x04: R: Interrupt status W: Reset interrupt status
32 * +0x08: R: Interrupt mask W: Mask interrupt
33 * +0x0C: W: Unmask interrupt (write-only)
34 * +0x10: Direction: I/O=1/0
35 * +0x14: Output
36 * +0x18: Input (read-only)
37 * +0x20: R: Level interrupt W: Set as level interrupt
38 * 0x40-0x7F: Section 1
39 * 0x80-0xBF: Section 2
40 * 0xC0-0xFF: Section 3
41 */
42
43#define ZEVIO_GPIO_SECTION_SIZE 0x40
44
45/* Offsets to various registers */
46#define ZEVIO_GPIO_INT_MASKED_STATUS 0x00
47#define ZEVIO_GPIO_INT_STATUS 0x04
48#define ZEVIO_GPIO_INT_UNMASK 0x08
49#define ZEVIO_GPIO_INT_MASK 0x0C
50#define ZEVIO_GPIO_DIRECTION 0x10
51#define ZEVIO_GPIO_OUTPUT 0x14
52#define ZEVIO_GPIO_INPUT 0x18
53#define ZEVIO_GPIO_INT_STICKY 0x20
54
55#define to_zevio_gpio(chip) container_of(to_of_mm_gpio_chip(chip), \
56 struct zevio_gpio, chip)
57
58/* Bit number of GPIO in its section */
59#define ZEVIO_GPIO_BIT(gpio) (gpio&7)
60
61struct zevio_gpio {
62 spinlock_t lock;
63 struct of_mm_gpio_chip chip;
64};
65
66static inline u32 zevio_gpio_port_get(struct zevio_gpio *c, unsigned pin,
67 unsigned port_offset)
68{
69 unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE;
70 return readl(IOMEM(c->chip.regs + section_offset + port_offset));
71}
72
73static inline void zevio_gpio_port_set(struct zevio_gpio *c, unsigned pin,
74 unsigned port_offset, u32 val)
75{
76 unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE;
77 writel(val, IOMEM(c->chip.regs + section_offset + port_offset));
78}
79
80/* Functions for struct gpio_chip */
81static int zevio_gpio_get(struct gpio_chip *chip, unsigned pin)
82{
83 struct zevio_gpio *controller = to_zevio_gpio(chip);
84
85 /* Only reading allowed, so no spinlock needed */
86 u32 val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_INPUT);
87
88 return (val >> ZEVIO_GPIO_BIT(pin)) & 0x1;
89}
90
91static void zevio_gpio_set(struct gpio_chip *chip, unsigned pin, int value)
92{
93 struct zevio_gpio *controller = to_zevio_gpio(chip);
94 u32 val;
95
96 spin_lock(&controller->lock);
97 val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT);
98 if (value)
99 val |= BIT(ZEVIO_GPIO_BIT(pin));
100 else
101 val &= ~BIT(ZEVIO_GPIO_BIT(pin));
102
103 zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_OUTPUT, val);
104 spin_unlock(&controller->lock);
105}
106
107static int zevio_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
108{
109 struct zevio_gpio *controller = to_zevio_gpio(chip);
110 u32 val;
111
112 spin_lock(&controller->lock);
113
114 val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION);
115 val |= BIT(ZEVIO_GPIO_BIT(pin));
116 zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_DIRECTION, val);
117
118 spin_unlock(&controller->lock);
119
120 return 0;
121}
122
123static int zevio_gpio_direction_output(struct gpio_chip *chip,
124 unsigned pin, int value)
125{
126 struct zevio_gpio *controller = to_zevio_gpio(chip);
127 u32 val;
128
129 spin_lock(&controller->lock);
130 val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT);
131 if (value)
132 val |= BIT(ZEVIO_GPIO_BIT(pin));
133 else
134 val &= ~BIT(ZEVIO_GPIO_BIT(pin));
135
136 zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_OUTPUT, val);
137 val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION);
138 val &= ~BIT(ZEVIO_GPIO_BIT(pin));
139 zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_DIRECTION, val);
140
141 spin_unlock(&controller->lock);
142
143 return 0;
144}
145
146static int zevio_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
147{
148 /*
149 * TODO: Implement IRQs.
150 * Not implemented yet due to weird lockups
151 */
152
153 return -ENXIO;
154}
155
156static struct gpio_chip zevio_gpio_chip = {
157 .direction_input = zevio_gpio_direction_input,
158 .direction_output = zevio_gpio_direction_output,
159 .set = zevio_gpio_set,
160 .get = zevio_gpio_get,
161 .to_irq = zevio_gpio_to_irq,
162 .base = 0,
163 .owner = THIS_MODULE,
164 .ngpio = 32,
165 .of_gpio_n_cells = 2,
166};
167
168/* Initialization */
169static int zevio_gpio_probe(struct platform_device *pdev)
170{
171 struct zevio_gpio *controller;
172 int status, i;
173
174 controller = devm_kzalloc(&pdev->dev, sizeof(*controller), GFP_KERNEL);
175 if (!controller) {
176 dev_err(&pdev->dev, "not enough free memory\n");
177 return -ENOMEM;
178 }
179
180 /* Copy our reference */
181 controller->chip.gc = zevio_gpio_chip;
182 controller->chip.gc.dev = &pdev->dev;
183
184 status = of_mm_gpiochip_add(pdev->dev.of_node, &(controller->chip));
185 if (status) {
186 dev_err(&pdev->dev, "failed to add gpiochip: %d\n", status);
187 return status;
188 }
189
190 spin_lock_init(&controller->lock);
191
192 /* Disable interrupts, they only cause errors */
193 for (i = 0; i < controller->chip.gc.ngpio; i += 8)
194 zevio_gpio_port_set(controller, i, ZEVIO_GPIO_INT_MASK, 0xFF);
195
196 dev_dbg(controller->chip.gc.dev, "ZEVIO GPIO controller set up!\n");
197
198 return 0;
199}
200
201static struct of_device_id zevio_gpio_of_match[] = {
202 { .compatible = "lsi,zevio-gpio", },
203 { },
204};
205
206MODULE_DEVICE_TABLE(of, zevio_gpio_of_match);
207
208static struct platform_driver zevio_gpio_driver = {
209 .driver = {
210 .name = "gpio-zevio",
211 .owner = THIS_MODULE,
212 .of_match_table = of_match_ptr(zevio_gpio_of_match),
213 },
214 .probe = zevio_gpio_probe,
215};
216module_platform_driver(zevio_gpio_driver);
217
218MODULE_LICENSE("GPL");
219MODULE_AUTHOR("Fabian Vogt <fabian@ritter-vogt.de>");
220MODULE_DESCRIPTION("LSI ZEVIO SoC GPIO driver");