diff options
Diffstat (limited to 'drivers/gpio/gpio-zevio.c')
-rw-r--r-- | drivers/gpio/gpio-zevio.c | 220 |
1 files changed, 220 insertions, 0 deletions
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 | |||
61 | struct zevio_gpio { | ||
62 | spinlock_t lock; | ||
63 | struct of_mm_gpio_chip chip; | ||
64 | }; | ||
65 | |||
66 | static 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 | |||
73 | static 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 */ | ||
81 | static 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 | |||
91 | static 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 | |||
107 | static 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 | |||
123 | static 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 | |||
146 | static 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 | |||
156 | static 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 */ | ||
169 | static 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 | |||
201 | static struct of_device_id zevio_gpio_of_match[] = { | ||
202 | { .compatible = "lsi,zevio-gpio", }, | ||
203 | { }, | ||
204 | }; | ||
205 | |||
206 | MODULE_DEVICE_TABLE(of, zevio_gpio_of_match); | ||
207 | |||
208 | static 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 | }; | ||
216 | module_platform_driver(zevio_gpio_driver); | ||
217 | |||
218 | MODULE_LICENSE("GPL"); | ||
219 | MODULE_AUTHOR("Fabian Vogt <fabian@ritter-vogt.de>"); | ||
220 | MODULE_DESCRIPTION("LSI ZEVIO SoC GPIO driver"); | ||