]>
Commit | Line | Data |
---|---|---|
9af4d80b FV |
1 | /* |
2 | * GPIO controller in LSI ZEVIO SoCs. | |
3 | * | |
4 | * Author: Fabian Vogt <[email protected]> | |
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> | |
a90295b4 | 13 | #include <linux/init.h> |
9af4d80b FV |
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 | ||
9af4d80b FV |
55 | /* Bit number of GPIO in its section */ |
56 | #define ZEVIO_GPIO_BIT(gpio) (gpio&7) | |
57 | ||
58 | struct zevio_gpio { | |
59 | spinlock_t lock; | |
60 | struct of_mm_gpio_chip chip; | |
61 | }; | |
62 | ||
63 | static inline u32 zevio_gpio_port_get(struct zevio_gpio *c, unsigned pin, | |
64 | unsigned port_offset) | |
65 | { | |
66 | unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE; | |
67 | return readl(IOMEM(c->chip.regs + section_offset + port_offset)); | |
68 | } | |
69 | ||
70 | static inline void zevio_gpio_port_set(struct zevio_gpio *c, unsigned pin, | |
71 | unsigned port_offset, u32 val) | |
72 | { | |
73 | unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE; | |
74 | writel(val, IOMEM(c->chip.regs + section_offset + port_offset)); | |
75 | } | |
76 | ||
77 | /* Functions for struct gpio_chip */ | |
78 | static int zevio_gpio_get(struct gpio_chip *chip, unsigned pin) | |
79 | { | |
9a3ad668 | 80 | struct zevio_gpio *controller = gpiochip_get_data(chip); |
ef7de262 | 81 | u32 val, dir; |
9af4d80b | 82 | |
ef7de262 AL |
83 | spin_lock(&controller->lock); |
84 | dir = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION); | |
85 | if (dir & BIT(ZEVIO_GPIO_BIT(pin))) | |
86 | val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_INPUT); | |
87 | else | |
88 | val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT); | |
89 | spin_unlock(&controller->lock); | |
9af4d80b FV |
90 | |
91 | return (val >> ZEVIO_GPIO_BIT(pin)) & 0x1; | |
92 | } | |
93 | ||
94 | static void zevio_gpio_set(struct gpio_chip *chip, unsigned pin, int value) | |
95 | { | |
9a3ad668 | 96 | struct zevio_gpio *controller = gpiochip_get_data(chip); |
9af4d80b FV |
97 | u32 val; |
98 | ||
99 | spin_lock(&controller->lock); | |
100 | val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT); | |
101 | if (value) | |
102 | val |= BIT(ZEVIO_GPIO_BIT(pin)); | |
103 | else | |
104 | val &= ~BIT(ZEVIO_GPIO_BIT(pin)); | |
105 | ||
106 | zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_OUTPUT, val); | |
107 | spin_unlock(&controller->lock); | |
108 | } | |
109 | ||
110 | static int zevio_gpio_direction_input(struct gpio_chip *chip, unsigned pin) | |
111 | { | |
9a3ad668 | 112 | struct zevio_gpio *controller = gpiochip_get_data(chip); |
9af4d80b FV |
113 | u32 val; |
114 | ||
115 | spin_lock(&controller->lock); | |
116 | ||
117 | val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION); | |
118 | val |= BIT(ZEVIO_GPIO_BIT(pin)); | |
119 | zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_DIRECTION, val); | |
120 | ||
121 | spin_unlock(&controller->lock); | |
122 | ||
123 | return 0; | |
124 | } | |
125 | ||
126 | static int zevio_gpio_direction_output(struct gpio_chip *chip, | |
127 | unsigned pin, int value) | |
128 | { | |
9a3ad668 | 129 | struct zevio_gpio *controller = gpiochip_get_data(chip); |
9af4d80b FV |
130 | u32 val; |
131 | ||
132 | spin_lock(&controller->lock); | |
133 | val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT); | |
134 | if (value) | |
135 | val |= BIT(ZEVIO_GPIO_BIT(pin)); | |
136 | else | |
137 | val &= ~BIT(ZEVIO_GPIO_BIT(pin)); | |
138 | ||
139 | zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_OUTPUT, val); | |
140 | val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION); | |
141 | val &= ~BIT(ZEVIO_GPIO_BIT(pin)); | |
142 | zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_DIRECTION, val); | |
143 | ||
144 | spin_unlock(&controller->lock); | |
145 | ||
146 | return 0; | |
147 | } | |
148 | ||
149 | static int zevio_gpio_to_irq(struct gpio_chip *chip, unsigned pin) | |
150 | { | |
151 | /* | |
152 | * TODO: Implement IRQs. | |
153 | * Not implemented yet due to weird lockups | |
154 | */ | |
155 | ||
156 | return -ENXIO; | |
157 | } | |
158 | ||
159 | static struct gpio_chip zevio_gpio_chip = { | |
160 | .direction_input = zevio_gpio_direction_input, | |
161 | .direction_output = zevio_gpio_direction_output, | |
162 | .set = zevio_gpio_set, | |
163 | .get = zevio_gpio_get, | |
164 | .to_irq = zevio_gpio_to_irq, | |
165 | .base = 0, | |
166 | .owner = THIS_MODULE, | |
167 | .ngpio = 32, | |
168 | .of_gpio_n_cells = 2, | |
169 | }; | |
170 | ||
171 | /* Initialization */ | |
172 | static int zevio_gpio_probe(struct platform_device *pdev) | |
173 | { | |
174 | struct zevio_gpio *controller; | |
175 | int status, i; | |
176 | ||
177 | controller = devm_kzalloc(&pdev->dev, sizeof(*controller), GFP_KERNEL); | |
50908d61 | 178 | if (!controller) |
9af4d80b | 179 | return -ENOMEM; |
9af4d80b | 180 | |
ff00be69 RR |
181 | platform_set_drvdata(pdev, controller); |
182 | ||
9af4d80b FV |
183 | /* Copy our reference */ |
184 | controller->chip.gc = zevio_gpio_chip; | |
58383c78 | 185 | controller->chip.gc.parent = &pdev->dev; |
9af4d80b | 186 | |
9a3ad668 LW |
187 | status = of_mm_gpiochip_add_data(pdev->dev.of_node, |
188 | &(controller->chip), | |
189 | controller); | |
9af4d80b FV |
190 | if (status) { |
191 | dev_err(&pdev->dev, "failed to add gpiochip: %d\n", status); | |
192 | return status; | |
193 | } | |
194 | ||
195 | spin_lock_init(&controller->lock); | |
196 | ||
197 | /* Disable interrupts, they only cause errors */ | |
198 | for (i = 0; i < controller->chip.gc.ngpio; i += 8) | |
199 | zevio_gpio_port_set(controller, i, ZEVIO_GPIO_INT_MASK, 0xFF); | |
200 | ||
58383c78 | 201 | dev_dbg(controller->chip.gc.parent, "ZEVIO GPIO controller set up!\n"); |
9af4d80b FV |
202 | |
203 | return 0; | |
204 | } | |
205 | ||
a49f2e74 | 206 | static const struct of_device_id zevio_gpio_of_match[] = { |
9af4d80b FV |
207 | { .compatible = "lsi,zevio-gpio", }, |
208 | { }, | |
209 | }; | |
210 | ||
9af4d80b FV |
211 | static struct platform_driver zevio_gpio_driver = { |
212 | .driver = { | |
213 | .name = "gpio-zevio", | |
9ea8d810 | 214 | .of_match_table = zevio_gpio_of_match, |
a90295b4 | 215 | .suppress_bind_attrs = true, |
9af4d80b FV |
216 | }, |
217 | .probe = zevio_gpio_probe, | |
218 | }; | |
a90295b4 | 219 | builtin_platform_driver(zevio_gpio_driver); |