aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2016-09-16 07:48:12 -0400
committerLinus Walleij <linus.walleij@linaro.org>2016-09-28 12:28:34 -0400
commit3c6e8d05d60d8106b5cdc730cf220b2a4b521b66 (patch)
treecbad9c3802c81e7c7c8ad829eda925c58a53c3bb /drivers/gpio
parent29b4817d4018df78086157ea3a55c1d9424a7cfc (diff)
mfd/gpio: Move HTC GPIO driver to GPIO subsystem
The HTC GPIO driver is a pure GPIO driver and I just can not see what it is doing inside MFD. Let's just move it to GPIO and take this opportunity to move the platform data to <linux/platform_data/gpio-htc-egpio.h> Cc: arm@kernel.org Cc: Russell King <linux@armlinux.org.uk> Acked-by: Lee Jones <lee.jones@linaro.org> Acked-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/Kconfig8
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/gpio-htc-egpio.c440
3 files changed, 449 insertions, 0 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 98dd47a30fc7..03be200619a4 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -848,6 +848,14 @@ config GPIO_DLN2
848 This driver can also be built as a module. If so, the module 848 This driver can also be built as a module. If so, the module
849 will be called gpio-dln2. 849 will be called gpio-dln2.
850 850
851config HTC_EGPIO
852 bool "HTC EGPIO support"
853 depends on GPIOLIB && ARM
854 help
855 This driver supports the CPLD egpio chip present on
856 several HTC phones. It provides basic support for input
857 pins, output pins, and irqs.
858
851config GPIO_JANZ_TTL 859config GPIO_JANZ_TTL
852 tristate "Janz VMOD-TTL Digital IO Module" 860 tristate "Janz VMOD-TTL Digital IO Module"
853 depends on MFD_JANZ_CMODIO 861 depends on MFD_JANZ_CMODIO
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 2a035ed8f168..32ebc07074ed 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -45,6 +45,7 @@ obj-$(CONFIG_GPIO_ETRAXFS) += gpio-etraxfs.o
45obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o 45obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o
46obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o 46obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
47obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o 47obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o
48obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o
48obj-$(CONFIG_GPIO_ICH) += gpio-ich.o 49obj-$(CONFIG_GPIO_ICH) += gpio-ich.o
49obj-$(CONFIG_GPIO_IOP) += gpio-iop.o 50obj-$(CONFIG_GPIO_IOP) += gpio-iop.o
50obj-$(CONFIG_GPIO_IT87) += gpio-it87.o 51obj-$(CONFIG_GPIO_IT87) += gpio-it87.o
diff --git a/drivers/gpio/gpio-htc-egpio.c b/drivers/gpio/gpio-htc-egpio.c
new file mode 100644
index 000000000000..0b4df6051097
--- /dev/null
+++ b/drivers/gpio/gpio-htc-egpio.c
@@ -0,0 +1,440 @@
1/*
2 * Support for the GPIO/IRQ expander chips present on several HTC phones.
3 * These are implemented in CPLD chips present on the board.
4 *
5 * Copyright (c) 2007 Kevin O'Connor <kevin@koconnor.net>
6 * Copyright (c) 2007 Philipp Zabel <philipp.zabel@gmail.com>
7 *
8 * This file may be distributed under the terms of the GNU GPL license.
9 */
10
11#include <linux/kernel.h>
12#include <linux/errno.h>
13#include <linux/interrupt.h>
14#include <linux/irq.h>
15#include <linux/io.h>
16#include <linux/spinlock.h>
17#include <linux/platform_data/gpio-htc-egpio.h>
18#include <linux/platform_device.h>
19#include <linux/slab.h>
20#include <linux/module.h>
21
22struct egpio_chip {
23 int reg_start;
24 int cached_values;
25 unsigned long is_out;
26 struct device *dev;
27 struct gpio_chip chip;
28};
29
30struct egpio_info {
31 spinlock_t lock;
32
33 /* iomem info */
34 void __iomem *base_addr;
35 int bus_shift; /* byte shift */
36 int reg_shift; /* bit shift */
37 int reg_mask;
38
39 /* irq info */
40 int ack_register;
41 int ack_write;
42 u16 irqs_enabled;
43 uint irq_start;
44 int nirqs;
45 uint chained_irq;
46
47 /* egpio info */
48 struct egpio_chip *chip;
49 int nchips;
50};
51
52static inline void egpio_writew(u16 value, struct egpio_info *ei, int reg)
53{
54 writew(value, ei->base_addr + (reg << ei->bus_shift));
55}
56
57static inline u16 egpio_readw(struct egpio_info *ei, int reg)
58{
59 return readw(ei->base_addr + (reg << ei->bus_shift));
60}
61
62/*
63 * IRQs
64 */
65
66static inline void ack_irqs(struct egpio_info *ei)
67{
68 egpio_writew(ei->ack_write, ei, ei->ack_register);
69 pr_debug("EGPIO ack - write %x to base+%x\n",
70 ei->ack_write, ei->ack_register << ei->bus_shift);
71}
72
73static void egpio_ack(struct irq_data *data)
74{
75}
76
77/* There does not appear to be a way to proactively mask interrupts
78 * on the egpio chip itself. So, we simply ignore interrupts that
79 * aren't desired. */
80static void egpio_mask(struct irq_data *data)
81{
82 struct egpio_info *ei = irq_data_get_irq_chip_data(data);
83 ei->irqs_enabled &= ~(1 << (data->irq - ei->irq_start));
84 pr_debug("EGPIO mask %d %04x\n", data->irq, ei->irqs_enabled);
85}
86
87static void egpio_unmask(struct irq_data *data)
88{
89 struct egpio_info *ei = irq_data_get_irq_chip_data(data);
90 ei->irqs_enabled |= 1 << (data->irq - ei->irq_start);
91 pr_debug("EGPIO unmask %d %04x\n", data->irq, ei->irqs_enabled);
92}
93
94static struct irq_chip egpio_muxed_chip = {
95 .name = "htc-egpio",
96 .irq_ack = egpio_ack,
97 .irq_mask = egpio_mask,
98 .irq_unmask = egpio_unmask,
99};
100
101static void egpio_handler(struct irq_desc *desc)
102{
103 struct egpio_info *ei = irq_desc_get_handler_data(desc);
104 int irqpin;
105
106 /* Read current pins. */
107 unsigned long readval = egpio_readw(ei, ei->ack_register);
108 pr_debug("IRQ reg: %x\n", (unsigned int)readval);
109 /* Ack/unmask interrupts. */
110 ack_irqs(ei);
111 /* Process all set pins. */
112 readval &= ei->irqs_enabled;
113 for_each_set_bit(irqpin, &readval, ei->nirqs) {
114 /* Run irq handler */
115 pr_debug("got IRQ %d\n", irqpin);
116 generic_handle_irq(ei->irq_start + irqpin);
117 }
118}
119
120int htc_egpio_get_wakeup_irq(struct device *dev)
121{
122 struct egpio_info *ei = dev_get_drvdata(dev);
123
124 /* Read current pins. */
125 u16 readval = egpio_readw(ei, ei->ack_register);
126 /* Ack/unmask interrupts. */
127 ack_irqs(ei);
128 /* Return first set pin. */
129 readval &= ei->irqs_enabled;
130 return ei->irq_start + ffs(readval) - 1;
131}
132EXPORT_SYMBOL(htc_egpio_get_wakeup_irq);
133
134static inline int egpio_pos(struct egpio_info *ei, int bit)
135{
136 return bit >> ei->reg_shift;
137}
138
139static inline int egpio_bit(struct egpio_info *ei, int bit)
140{
141 return 1 << (bit & ((1 << ei->reg_shift)-1));
142}
143
144/*
145 * Input pins
146 */
147
148static int egpio_get(struct gpio_chip *chip, unsigned offset)
149{
150 struct egpio_chip *egpio;
151 struct egpio_info *ei;
152 unsigned bit;
153 int reg;
154 int value;
155
156 pr_debug("egpio_get_value(%d)\n", chip->base + offset);
157
158 egpio = gpiochip_get_data(chip);
159 ei = dev_get_drvdata(egpio->dev);
160 bit = egpio_bit(ei, offset);
161 reg = egpio->reg_start + egpio_pos(ei, offset);
162
163 value = egpio_readw(ei, reg);
164 pr_debug("readw(%p + %x) = %x\n",
165 ei->base_addr, reg << ei->bus_shift, value);
166 return !!(value & bit);
167}
168
169static int egpio_direction_input(struct gpio_chip *chip, unsigned offset)
170{
171 struct egpio_chip *egpio;
172
173 egpio = gpiochip_get_data(chip);
174 return test_bit(offset, &egpio->is_out) ? -EINVAL : 0;
175}
176
177
178/*
179 * Output pins
180 */
181
182static void egpio_set(struct gpio_chip *chip, unsigned offset, int value)
183{
184 unsigned long flag;
185 struct egpio_chip *egpio;
186 struct egpio_info *ei;
187 unsigned bit;
188 int pos;
189 int reg;
190 int shift;
191
192 pr_debug("egpio_set(%s, %d(%d), %d)\n",
193 chip->label, offset, offset+chip->base, value);
194
195 egpio = gpiochip_get_data(chip);
196 ei = dev_get_drvdata(egpio->dev);
197 bit = egpio_bit(ei, offset);
198 pos = egpio_pos(ei, offset);
199 reg = egpio->reg_start + pos;
200 shift = pos << ei->reg_shift;
201
202 pr_debug("egpio %s: reg %d = 0x%04x\n", value ? "set" : "clear",
203 reg, (egpio->cached_values >> shift) & ei->reg_mask);
204
205 spin_lock_irqsave(&ei->lock, flag);
206 if (value)
207 egpio->cached_values |= (1 << offset);
208 else
209 egpio->cached_values &= ~(1 << offset);
210 egpio_writew((egpio->cached_values >> shift) & ei->reg_mask, ei, reg);
211 spin_unlock_irqrestore(&ei->lock, flag);
212}
213
214static int egpio_direction_output(struct gpio_chip *chip,
215 unsigned offset, int value)
216{
217 struct egpio_chip *egpio;
218
219 egpio = gpiochip_get_data(chip);
220 if (test_bit(offset, &egpio->is_out)) {
221 egpio_set(chip, offset, value);
222 return 0;
223 } else {
224 return -EINVAL;
225 }
226}
227
228static void egpio_write_cache(struct egpio_info *ei)
229{
230 int i;
231 struct egpio_chip *egpio;
232 int shift;
233
234 for (i = 0; i < ei->nchips; i++) {
235 egpio = &(ei->chip[i]);
236 if (!egpio->is_out)
237 continue;
238
239 for (shift = 0; shift < egpio->chip.ngpio;
240 shift += (1<<ei->reg_shift)) {
241
242 int reg = egpio->reg_start + egpio_pos(ei, shift);
243
244 if (!((egpio->is_out >> shift) & ei->reg_mask))
245 continue;
246
247 pr_debug("EGPIO: setting %x to %x, was %x\n", reg,
248 (egpio->cached_values >> shift) & ei->reg_mask,
249 egpio_readw(ei, reg));
250
251 egpio_writew((egpio->cached_values >> shift)
252 & ei->reg_mask, ei, reg);
253 }
254 }
255}
256
257
258/*
259 * Setup
260 */
261
262static int __init egpio_probe(struct platform_device *pdev)
263{
264 struct htc_egpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
265 struct resource *res;
266 struct egpio_info *ei;
267 struct gpio_chip *chip;
268 unsigned int irq, irq_end;
269 int i;
270 int ret;
271
272 /* Initialize ei data structure. */
273 ei = devm_kzalloc(&pdev->dev, sizeof(*ei), GFP_KERNEL);
274 if (!ei)
275 return -ENOMEM;
276
277 spin_lock_init(&ei->lock);
278
279 /* Find chained irq */
280 ret = -EINVAL;
281 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
282 if (res)
283 ei->chained_irq = res->start;
284
285 /* Map egpio chip into virtual address space. */
286 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
287 if (!res)
288 goto fail;
289 ei->base_addr = devm_ioremap_nocache(&pdev->dev, res->start,
290 resource_size(res));
291 if (!ei->base_addr)
292 goto fail;
293 pr_debug("EGPIO phys=%08x virt=%p\n", (u32)res->start, ei->base_addr);
294
295 if ((pdata->bus_width != 16) && (pdata->bus_width != 32))
296 goto fail;
297 ei->bus_shift = fls(pdata->bus_width - 1) - 3;
298 pr_debug("bus_shift = %d\n", ei->bus_shift);
299
300 if ((pdata->reg_width != 8) && (pdata->reg_width != 16))
301 goto fail;
302 ei->reg_shift = fls(pdata->reg_width - 1);
303 pr_debug("reg_shift = %d\n", ei->reg_shift);
304
305 ei->reg_mask = (1 << pdata->reg_width) - 1;
306
307 platform_set_drvdata(pdev, ei);
308
309 ei->nchips = pdata->num_chips;
310 ei->chip = devm_kzalloc(&pdev->dev,
311 sizeof(struct egpio_chip) * ei->nchips,
312 GFP_KERNEL);
313 if (!ei->chip) {
314 ret = -ENOMEM;
315 goto fail;
316 }
317 for (i = 0; i < ei->nchips; i++) {
318 ei->chip[i].reg_start = pdata->chip[i].reg_start;
319 ei->chip[i].cached_values = pdata->chip[i].initial_values;
320 ei->chip[i].is_out = pdata->chip[i].direction;
321 ei->chip[i].dev = &(pdev->dev);
322 chip = &(ei->chip[i].chip);
323 chip->label = "htc-egpio";
324 chip->parent = &pdev->dev;
325 chip->owner = THIS_MODULE;
326 chip->get = egpio_get;
327 chip->set = egpio_set;
328 chip->direction_input = egpio_direction_input;
329 chip->direction_output = egpio_direction_output;
330 chip->base = pdata->chip[i].gpio_base;
331 chip->ngpio = pdata->chip[i].num_gpios;
332
333 gpiochip_add_data(chip, &ei->chip[i]);
334 }
335
336 /* Set initial pin values */
337 egpio_write_cache(ei);
338
339 ei->irq_start = pdata->irq_base;
340 ei->nirqs = pdata->num_irqs;
341 ei->ack_register = pdata->ack_register;
342
343 if (ei->chained_irq) {
344 /* Setup irq handlers */
345 ei->ack_write = 0xFFFF;
346 if (pdata->invert_acks)
347 ei->ack_write = 0;
348 irq_end = ei->irq_start + ei->nirqs;
349 for (irq = ei->irq_start; irq < irq_end; irq++) {
350 irq_set_chip_and_handler(irq, &egpio_muxed_chip,
351 handle_simple_irq);
352 irq_set_chip_data(irq, ei);
353 irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE);
354 }
355 irq_set_irq_type(ei->chained_irq, IRQ_TYPE_EDGE_RISING);
356 irq_set_chained_handler_and_data(ei->chained_irq,
357 egpio_handler, ei);
358 ack_irqs(ei);
359
360 device_init_wakeup(&pdev->dev, 1);
361 }
362
363 return 0;
364
365fail:
366 printk(KERN_ERR "EGPIO failed to setup\n");
367 return ret;
368}
369
370static int __exit egpio_remove(struct platform_device *pdev)
371{
372 struct egpio_info *ei = platform_get_drvdata(pdev);
373 unsigned int irq, irq_end;
374
375 if (ei->chained_irq) {
376 irq_end = ei->irq_start + ei->nirqs;
377 for (irq = ei->irq_start; irq < irq_end; irq++) {
378 irq_set_chip_and_handler(irq, NULL, NULL);
379 irq_set_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE);
380 }
381 irq_set_chained_handler(ei->chained_irq, NULL);
382 device_init_wakeup(&pdev->dev, 0);
383 }
384
385 return 0;
386}
387
388#ifdef CONFIG_PM
389static int egpio_suspend(struct platform_device *pdev, pm_message_t state)
390{
391 struct egpio_info *ei = platform_get_drvdata(pdev);
392
393 if (ei->chained_irq && device_may_wakeup(&pdev->dev))
394 enable_irq_wake(ei->chained_irq);
395 return 0;
396}
397
398static int egpio_resume(struct platform_device *pdev)
399{
400 struct egpio_info *ei = platform_get_drvdata(pdev);
401
402 if (ei->chained_irq && device_may_wakeup(&pdev->dev))
403 disable_irq_wake(ei->chained_irq);
404
405 /* Update registers from the cache, in case
406 the CPLD was powered off during suspend */
407 egpio_write_cache(ei);
408 return 0;
409}
410#else
411#define egpio_suspend NULL
412#define egpio_resume NULL
413#endif
414
415
416static struct platform_driver egpio_driver = {
417 .driver = {
418 .name = "htc-egpio",
419 },
420 .remove = __exit_p(egpio_remove),
421 .suspend = egpio_suspend,
422 .resume = egpio_resume,
423};
424
425static int __init egpio_init(void)
426{
427 return platform_driver_probe(&egpio_driver, egpio_probe);
428}
429
430static void __exit egpio_exit(void)
431{
432 platform_driver_unregister(&egpio_driver);
433}
434
435/* start early for dependencies */
436subsys_initcall(egpio_init);
437module_exit(egpio_exit)
438
439MODULE_LICENSE("GPL");
440MODULE_AUTHOR("Kevin O'Connor <kevin@koconnor.net>");