aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpio-vt8500.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpio/gpio-vt8500.c')
-rw-r--r--drivers/gpio/gpio-vt8500.c316
1 files changed, 316 insertions, 0 deletions
diff --git a/drivers/gpio/gpio-vt8500.c b/drivers/gpio/gpio-vt8500.c
new file mode 100644
index 000000000000..bcd8e4aa7c7d
--- /dev/null
+++ b/drivers/gpio/gpio-vt8500.c
@@ -0,0 +1,316 @@
1/* drivers/gpio/gpio-vt8500.c
2 *
3 * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
4 * Based on arch/arm/mach-vt8500/gpio.c:
5 * - Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
6 *
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
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 */
17
18#include <linux/module.h>
19#include <linux/err.h>
20#include <linux/io.h>
21#include <linux/gpio.h>
22#include <linux/platform_device.h>
23#include <linux/bitops.h>
24#include <linux/of.h>
25#include <linux/of_address.h>
26#include <linux/of_irq.h>
27#include <linux/of_device.h>
28
29/*
30 We handle GPIOs by bank, each bank containing up to 32 GPIOs covered
31 by one set of registers (although not all may be valid).
32
33 Because different SoC's have different register offsets, we pass the
34 register offsets as data in vt8500_gpio_dt_ids[].
35
36 A value of NO_REG is used to indicate that this register is not
37 supported. Only used for ->en at the moment.
38*/
39
40#define NO_REG 0xFFFF
41
42/*
43 * struct vt8500_gpio_bank_regoffsets
44 * @en: offset to enable register of the bank
45 * @dir: offset to direction register of the bank
46 * @data_out: offset to the data out register of the bank
47 * @data_in: offset to the data in register of the bank
48 * @ngpio: highest valid pin in this bank
49 */
50
51struct vt8500_gpio_bank_regoffsets {
52 unsigned int en;
53 unsigned int dir;
54 unsigned int data_out;
55 unsigned int data_in;
56 unsigned char ngpio;
57};
58
59struct vt8500_gpio_data {
60 unsigned int num_banks;
61 struct vt8500_gpio_bank_regoffsets banks[];
62};
63
64#define VT8500_BANK(__en, __dir, __out, __in, __ngpio) \
65{ \
66 .en = __en, \
67 .dir = __dir, \
68 .data_out = __out, \
69 .data_in = __in, \
70 .ngpio = __ngpio, \
71}
72
73static struct vt8500_gpio_data vt8500_data = {
74 .num_banks = 7,
75 .banks = {
76 VT8500_BANK(0x00, 0x20, 0x40, 0x60, 26),
77 VT8500_BANK(0x04, 0x24, 0x44, 0x64, 28),
78 VT8500_BANK(0x08, 0x28, 0x48, 0x68, 31),
79 VT8500_BANK(0x0C, 0x2C, 0x4C, 0x6C, 19),
80 VT8500_BANK(0x10, 0x30, 0x50, 0x70, 19),
81 VT8500_BANK(0x14, 0x34, 0x54, 0x74, 23),
82 VT8500_BANK(NO_REG, 0x3C, 0x5C, 0x7C, 9),
83 },
84};
85
86static struct vt8500_gpio_data wm8505_data = {
87 .num_banks = 10,
88 .banks = {
89 VT8500_BANK(0x40, 0x68, 0x90, 0xB8, 8),
90 VT8500_BANK(0x44, 0x6C, 0x94, 0xBC, 32),
91 VT8500_BANK(0x48, 0x70, 0x98, 0xC0, 6),
92 VT8500_BANK(0x4C, 0x74, 0x9C, 0xC4, 16),
93 VT8500_BANK(0x50, 0x78, 0xA0, 0xC8, 25),
94 VT8500_BANK(0x54, 0x7C, 0xA4, 0xCC, 5),
95 VT8500_BANK(0x58, 0x80, 0xA8, 0xD0, 5),
96 VT8500_BANK(0x5C, 0x84, 0xAC, 0xD4, 12),
97 VT8500_BANK(0x60, 0x88, 0xB0, 0xD8, 16),
98 VT8500_BANK(0x64, 0x8C, 0xB4, 0xDC, 22),
99 },
100};
101
102/*
103 * No information about which bits are valid so we just make
104 * them all available until its figured out.
105 */
106static struct vt8500_gpio_data wm8650_data = {
107 .num_banks = 9,
108 .banks = {
109 VT8500_BANK(0x40, 0x80, 0xC0, 0x00, 32),
110 VT8500_BANK(0x44, 0x84, 0xC4, 0x04, 32),
111 VT8500_BANK(0x48, 0x88, 0xC8, 0x08, 32),
112 VT8500_BANK(0x4C, 0x8C, 0xCC, 0x0C, 32),
113 VT8500_BANK(0x50, 0x90, 0xD0, 0x10, 32),
114 VT8500_BANK(0x54, 0x94, 0xD4, 0x14, 32),
115 VT8500_BANK(0x58, 0x98, 0xD8, 0x18, 32),
116 VT8500_BANK(0x5C, 0x9C, 0xDC, 0x1C, 32),
117 VT8500_BANK(0x7C, 0xBC, 0xFC, 0x3C, 32),
118 },
119};
120
121struct vt8500_gpio_chip {
122 struct gpio_chip chip;
123
124 const struct vt8500_gpio_bank_regoffsets *regs;
125 void __iomem *base;
126};
127
128
129#define to_vt8500(__chip) container_of(__chip, struct vt8500_gpio_chip, chip)
130
131static int vt8500_gpio_request(struct gpio_chip *chip, unsigned offset)
132{
133 u32 val;
134 struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
135
136 if (vt8500_chip->regs->en == NO_REG)
137 return 0;
138
139 val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->en);
140 val |= BIT(offset);
141 writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->en);
142
143 return 0;
144}
145
146static void vt8500_gpio_free(struct gpio_chip *chip, unsigned offset)
147{
148 struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
149 u32 val;
150
151 if (vt8500_chip->regs->en == NO_REG)
152 return;
153
154 val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->en);
155 val &= ~BIT(offset);
156 writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->en);
157}
158
159static int vt8500_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
160{
161 struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
162
163 u32 val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->dir);
164 val &= ~BIT(offset);
165 writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->dir);
166
167 return 0;
168}
169
170static int vt8500_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
171 int value)
172{
173 struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
174
175 u32 val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->dir);
176 val |= BIT(offset);
177 writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->dir);
178
179 if (value) {
180 val = readl_relaxed(vt8500_chip->base +
181 vt8500_chip->regs->data_out);
182 val |= BIT(offset);
183 writel_relaxed(val, vt8500_chip->base +
184 vt8500_chip->regs->data_out);
185 }
186 return 0;
187}
188
189static int vt8500_gpio_get_value(struct gpio_chip *chip, unsigned offset)
190{
191 struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
192
193 return (readl_relaxed(vt8500_chip->base + vt8500_chip->regs->data_in) >>
194 offset) & 1;
195}
196
197static void vt8500_gpio_set_value(struct gpio_chip *chip, unsigned offset,
198 int value)
199{
200 struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
201
202 u32 val = readl_relaxed(vt8500_chip->base +
203 vt8500_chip->regs->data_out);
204 if (value)
205 val |= BIT(offset);
206 else
207 val &= ~BIT(offset);
208
209 writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->data_out);
210}
211
212static int vt8500_of_xlate(struct gpio_chip *gc,
213 const struct of_phandle_args *gpiospec, u32 *flags)
214{
215 /* bank if specificed in gpiospec->args[0] */
216 if (flags)
217 *flags = gpiospec->args[2];
218
219 return gpiospec->args[1];
220}
221
222static int vt8500_add_chips(struct platform_device *pdev, void __iomem *base,
223 const struct vt8500_gpio_data *data)
224{
225 struct vt8500_gpio_chip *vtchip;
226 struct gpio_chip *chip;
227 int i;
228 int pin_cnt = 0;
229
230 vtchip = devm_kzalloc(&pdev->dev,
231 sizeof(struct vt8500_gpio_chip) * data->num_banks,
232 GFP_KERNEL);
233 if (!vtchip) {
234 pr_err("%s: failed to allocate chip memory\n", __func__);
235 return -ENOMEM;
236 }
237
238 for (i = 0; i < data->num_banks; i++) {
239 vtchip[i].base = base;
240 vtchip[i].regs = &data->banks[i];
241
242 chip = &vtchip[i].chip;
243
244 chip->of_xlate = vt8500_of_xlate;
245 chip->of_gpio_n_cells = 3;
246 chip->of_node = pdev->dev.of_node;
247
248 chip->request = vt8500_gpio_request;
249 chip->free = vt8500_gpio_free;
250 chip->direction_input = vt8500_gpio_direction_input;
251 chip->direction_output = vt8500_gpio_direction_output;
252 chip->get = vt8500_gpio_get_value;
253 chip->set = vt8500_gpio_set_value;
254 chip->can_sleep = 0;
255 chip->base = pin_cnt;
256 chip->ngpio = data->banks[i].ngpio;
257
258 pin_cnt += data->banks[i].ngpio;
259
260 gpiochip_add(chip);
261 }
262 return 0;
263}
264
265static struct of_device_id vt8500_gpio_dt_ids[] = {
266 { .compatible = "via,vt8500-gpio", .data = &vt8500_data, },
267 { .compatible = "wm,wm8505-gpio", .data = &wm8505_data, },
268 { .compatible = "wm,wm8650-gpio", .data = &wm8650_data, },
269 { /* Sentinel */ },
270};
271
272static int __devinit vt8500_gpio_probe(struct platform_device *pdev)
273{
274 void __iomem *gpio_base;
275 struct device_node *np;
276 const struct of_device_id *of_id =
277 of_match_device(vt8500_gpio_dt_ids, &pdev->dev);
278
279 if (!of_id) {
280 dev_err(&pdev->dev, "Failed to find gpio controller\n");
281 return -ENODEV;
282 }
283
284 np = pdev->dev.of_node;
285 if (!np) {
286 dev_err(&pdev->dev, "Missing GPIO description in devicetree\n");
287 return -EFAULT;
288 }
289
290 gpio_base = of_iomap(np, 0);
291 if (!gpio_base) {
292 dev_err(&pdev->dev, "Unable to map GPIO registers\n");
293 of_node_put(np);
294 return -ENOMEM;
295 }
296
297 vt8500_add_chips(pdev, gpio_base, of_id->data);
298
299 return 0;
300}
301
302static struct platform_driver vt8500_gpio_driver = {
303 .probe = vt8500_gpio_probe,
304 .driver = {
305 .name = "vt8500-gpio",
306 .owner = THIS_MODULE,
307 .of_match_table = vt8500_gpio_dt_ids,
308 },
309};
310
311module_platform_driver(vt8500_gpio_driver);
312
313MODULE_DESCRIPTION("VT8500 GPIO Driver");
314MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
315MODULE_LICENSE("GPL v2");
316MODULE_DEVICE_TABLE(of, vt8500_gpio_dt_ids);