Root/target/linux/lantiq/files/arch/mips/lantiq/svip/gpio.c

1/*
2 * This program is free software; you can redistribute it and/or modify it
3 * under the terms of the GNU General Public License version 2 as published
4 * by the Free Software Foundation.
5 *
6 * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
7 */
8
9#include <linux/module.h>
10#include <linux/slab.h>
11#include <linux/gpio.h>
12#include <linux/ioport.h>
13#include <linux/io.h>
14#include <linux/types.h>
15#include <linux/errno.h>
16#include <linux/proc_fs.h>
17#include <linux/init.h>
18#include <linux/ioctl.h>
19#include <linux/timer.h>
20#include <linux/interrupt.h>
21#include <linux/kobject.h>
22#include <linux/workqueue.h>
23#include <linux/skbuff.h>
24#include <linux/netlink.h>
25#include <linux/platform_device.h>
26#include <net/sock.h>
27#include <linux/uaccess.h>
28#include <linux/version.h>
29#include <linux/semaphore.h>
30
31#include <lantiq_soc.h>
32#include <svip_mux.h>
33#include <base_reg.h>
34#include <port_reg.h>
35
36#define DRV_NAME "ifxmips_gpio"
37
38int gpio_to_irq(unsigned int gpio)
39{
40    return -EINVAL;
41}
42EXPORT_SYMBOL(gpio_to_irq);
43
44int irq_to_gpio(unsigned int gpio)
45{
46    return -EINVAL;
47}
48EXPORT_SYMBOL(irq_to_gpio);
49
50struct ltq_port_base {
51    struct svip_reg_port *base;
52    u32 pins;
53};
54
55/* Base addresses for ports */
56static const struct ltq_port_base ltq_port_base[] = {
57    { (struct svip_reg_port *)LTQ_PORT_P0_BASE, 20 },
58    { (struct svip_reg_port *)LTQ_PORT_P1_BASE, 20 },
59    { (struct svip_reg_port *)LTQ_PORT_P2_BASE, 19 },
60    { (struct svip_reg_port *)LTQ_PORT_P3_BASE, 20 },
61    { (struct svip_reg_port *)LTQ_PORT_P4_BASE, 24 }
62};
63
64#define MAX_PORTS ARRAY_SIZE(ltq_port_base)
65#define PINS_PER_PORT(port) (ltq_port_base[port].pins)
66
67static inline
68void ltq_port_set_exintcr0(unsigned int port, unsigned int pin)
69{
70    if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
71        return;
72
73    port_w32(port_r32(ltq_port_base[port].base->exintcr0) | (1 << pin),
74         ltq_port_base[port].base->exintcr0);
75}
76
77static inline
78void ltq_port_clear_exintcr0(unsigned int port, unsigned int pin)
79{
80    if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
81        return;
82
83    port_w32(port_r32(ltq_port_base[port].base->exintcr0) & ~(1 << pin),
84         ltq_port_base[port].base->exintcr0);
85}
86
87static inline
88void ltq_port_set_exintcr1(unsigned int port, unsigned int pin)
89{
90    if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
91        return;
92
93    port_w32(port_r32(ltq_port_base[port].base->exintcr1) | (1 << pin),
94         ltq_port_base[port].base->exintcr1);
95}
96
97static inline
98void ltq_port_clear_exintcr1(unsigned int port, unsigned int pin)
99{
100    if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
101        return;
102
103    port_w32(port_r32(ltq_port_base[port].base->exintcr1) & ~(1 << pin),
104         ltq_port_base[port].base->exintcr1);
105}
106
107static inline
108void ltq_port_set_irncfg(unsigned int port, unsigned int pin)
109{
110    if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
111        return;
112
113    port_w32(port_r32(ltq_port_base[port].base->irncfg) | (1 << pin),
114         ltq_port_base[port].base->irncfg);
115}
116
117static inline
118void ltq_port_clear_irncfg(unsigned int port, unsigned int pin)
119{
120    if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
121        return;
122
123    port_w32(port_r32(ltq_port_base[port].base->irncfg) & ~(1 << pin),
124         ltq_port_base[port].base->irncfg);
125}
126
127static inline
128void ltq_port_set_irnen(unsigned int port, unsigned int pin)
129{
130    if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
131        return;
132
133    port_w32(1 << pin, ltq_port_base[port].base->irnenset);
134}
135
136static inline
137void ltq_port_clear_irnen(unsigned int port, unsigned int pin)
138{
139    if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
140        return;
141
142    port_w32(1 << pin, ltq_port_base[port].base->irnenclr);
143}
144
145static inline
146void ltq_port_set_dir_out(unsigned int port, unsigned int pin)
147{
148    if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
149        return;
150
151    port_w32(port_r32(ltq_port_base[port].base->dir) | (1 << pin),
152         ltq_port_base[port].base->dir);
153}
154
155static inline
156void ltq_port_set_dir_in(unsigned int port, unsigned int pin)
157{
158    if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
159        return;
160
161    port_w32(port_r32(ltq_port_base[port].base->dir) & ~(1 << pin),
162         ltq_port_base[port].base->dir);
163}
164
165static inline
166void ltq_port_set_output(unsigned int port, unsigned int pin)
167{
168    if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
169        return;
170
171    port_w32(port_r32(ltq_port_base[port].base->out) | (1 << pin),
172         ltq_port_base[port].base->out);
173}
174
175static inline
176void ltq_port_clear_output(unsigned int port, unsigned int pin)
177{
178    if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
179        return;
180
181    port_w32(port_r32(ltq_port_base[port].base->out) & ~(1 << pin),
182         ltq_port_base[port].base->out);
183}
184
185static inline
186int ltq_port_get_input(unsigned int port, unsigned int pin)
187{
188    if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
189        return -EINVAL;
190
191    return (port_r32(ltq_port_base[port].base->in) & (1 << pin)) == 0;
192}
193
194static inline
195void ltq_port_set_puen(unsigned int port, unsigned int pin)
196{
197    if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
198        return;
199
200    port_w32(port_r32(ltq_port_base[port].base->puen) | (1 << pin),
201         ltq_port_base[port].base->puen);
202}
203
204static inline
205void ltq_port_clear_puen(unsigned int port, unsigned int pin)
206{
207    if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
208        return;
209
210    port_w32(port_r32(ltq_port_base[port].base->puen) & ~(1 << pin),
211         ltq_port_base[port].base->puen);
212}
213
214static inline
215void ltq_port_set_altsel0(unsigned int port, unsigned int pin)
216{
217    if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
218        return;
219
220    port_w32(port_r32(ltq_port_base[port].base->altsel0) | (1 << pin),
221         ltq_port_base[port].base->altsel0);
222}
223
224static inline
225void ltq_port_clear_altsel0(unsigned int port, unsigned int pin)
226{
227    if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
228        return;
229
230    port_w32(port_r32(ltq_port_base[port].base->altsel0) & ~(1 << pin),
231         ltq_port_base[port].base->altsel0);
232}
233
234static inline
235void ltq_port_set_altsel1(unsigned int port, unsigned int pin)
236{
237    if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
238        return;
239
240    port_w32(port_r32(ltq_port_base[port].base->altsel1) | (1 << pin),
241         ltq_port_base[port].base->altsel1);
242}
243
244static inline
245void ltq_port_clear_altsel1(unsigned int port, unsigned int pin)
246{
247    if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
248        return;
249
250    port_w32(port_r32(ltq_port_base[port].base->altsel1) & ~(1 << pin),
251         ltq_port_base[port].base->altsel1);
252}
253
254void ltq_gpio_configure(int port, int pin, bool dirin, bool puen,
255            bool altsel0, bool altsel1)
256{
257    if (dirin)
258        ltq_port_set_dir_in(port, pin);
259    else
260        ltq_port_set_dir_out(port, pin);
261
262    if (puen)
263        ltq_port_set_puen(port, pin);
264    else
265        ltq_port_clear_puen(port, pin);
266
267    if (altsel0)
268        ltq_port_set_altsel0(port, pin);
269    else
270        ltq_port_clear_altsel0(port, pin);
271
272    if (altsel1)
273        ltq_port_set_altsel1(port, pin);
274    else
275        ltq_port_clear_altsel1(port, pin);
276}
277
278int ltq_port_get_dir(unsigned int port, unsigned int pin)
279{
280    if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
281        return -EINVAL;
282
283    return (port_r32(ltq_port_base[port].base->dir) & (1 << pin)) != 0;
284}
285
286int ltq_port_get_puden(unsigned int port, unsigned int pin)
287{
288    if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
289        return -EINVAL;
290
291    return (port_r32(ltq_port_base[port].base->puen) & (1 << pin)) != 0;
292}
293
294int ltq_port_get_altsel0(unsigned int port, unsigned int pin)
295{
296    if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
297        return -EINVAL;
298
299    return (port_r32(ltq_port_base[port].base->altsel0) & (1 << pin)) != 0;
300}
301
302int ltq_port_get_altsel1(unsigned int port, unsigned int pin)
303{
304    if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
305        return -EINVAL;
306
307    return (port_r32(ltq_port_base[port].base->altsel1) & (1 << pin)) != 0;
308}
309
310struct ltq_gpio_port {
311    struct gpio_chip gpio_chip;
312    unsigned int irq_base;
313    unsigned int chained_irq;
314};
315
316static struct ltq_gpio_port ltq_gpio_port[MAX_PORTS];
317
318static int gpio_exported;
319static int __init gpio_export_setup(char *str)
320{
321    get_option(&str, &gpio_exported);
322    return 1;
323}
324__setup("gpio_exported=", gpio_export_setup);
325
326static inline unsigned int offset2port(unsigned int offset)
327{
328    unsigned int i;
329    unsigned int prev = 0;
330
331    for (i = 0; i < ARRAY_SIZE(ltq_port_base); i++) {
332        if (offset >= prev &&
333            offset < prev + ltq_port_base[i].pins)
334            return i;
335
336        prev = ltq_port_base[i].pins;
337    }
338
339    return 0;
340}
341
342static inline unsigned int offset2pin(unsigned int offset)
343{
344    unsigned int i;
345    unsigned int prev = 0;
346
347    for (i = 0; i < ARRAY_SIZE(ltq_port_base); i++) {
348        if (offset >= prev &&
349            offset < prev + ltq_port_base[i].pins)
350            return offset - prev;
351
352        prev = ltq_port_base[i].pins;
353    }
354
355    return 0;
356}
357
358static int ltq_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
359{
360    ltq_port_set_dir_in(offset2port(offset), offset2pin(offset));
361    return 0;
362}
363
364static int ltq_gpio_direction_output(struct gpio_chip *chip,
365                     unsigned int offset, int value)
366{
367    ltq_port_set_dir_out(offset2port(offset), offset2pin(offset));
368    return 0;
369}
370
371static int ltq_gpio_get(struct gpio_chip *chip, unsigned int offset)
372{
373    return ltq_port_get_input(offset2port(offset), offset2pin(offset));
374}
375
376static void ltq_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
377{
378    if (value)
379        ltq_port_set_output(offset2port(offset), offset2pin(offset));
380    else
381        ltq_port_clear_output(offset2port(offset), offset2pin(offset));
382}
383
384static int svip_gpio_request(struct gpio_chip *chip, unsigned offset)
385{
386    return 0;
387}
388
389static void ltq_gpio_free(struct gpio_chip *chip, unsigned offset)
390{
391}
392
393static int ltq_gpio_probe(struct platform_device *pdev)
394{
395    int ret = 0;
396    struct ltq_gpio_port *gpio_port;
397
398    if (pdev->id >= MAX_PORTS)
399        return -ENODEV;
400
401    gpio_port = &ltq_gpio_port[pdev->id];
402    gpio_port->gpio_chip.label = "ltq-gpio";
403
404    gpio_port->gpio_chip.direction_input = ltq_gpio_direction_input;
405    gpio_port->gpio_chip.direction_output = ltq_gpio_direction_output;
406    gpio_port->gpio_chip.get = ltq_gpio_get;
407    gpio_port->gpio_chip.set = ltq_gpio_set;
408    gpio_port->gpio_chip.request = svip_gpio_request;
409    gpio_port->gpio_chip.free = ltq_gpio_free;
410    gpio_port->gpio_chip.base = 100 * pdev->id;
411    gpio_port->gpio_chip.ngpio = 32;
412    gpio_port->gpio_chip.dev = &pdev->dev;
413    gpio_port->gpio_chip.exported = gpio_exported;
414
415    ret = gpiochip_add(&gpio_port->gpio_chip);
416    if (ret < 0) {
417        dev_err(&pdev->dev, "Could not register gpiochip %d, %d\n",
418            pdev->id, ret);
419        goto err;
420    }
421    platform_set_drvdata(pdev, gpio_port);
422
423    return 0;
424
425err:
426    return ret;
427}
428
429static int ltq_gpio_remove(struct platform_device *pdev)
430{
431    struct ltq_gpio_port *gpio_port = platform_get_drvdata(pdev);
432    int ret;
433
434    ret = gpiochip_remove(&gpio_port->gpio_chip);
435
436    return ret;
437}
438
439static struct platform_driver ltq_gpio_driver = {
440    .probe = ltq_gpio_probe,
441    .remove = __devexit_p(ltq_gpio_remove),
442    .driver = {
443        .name = DRV_NAME,
444        .owner = THIS_MODULE,
445    },
446};
447
448int __init ltq_gpio_init(void)
449{
450    int ret = platform_driver_register(&ltq_gpio_driver);
451    if (ret)
452        printk(KERN_INFO DRV_NAME
453               ": Error registering platform driver!");
454    return ret;
455}
456
457postcore_initcall(ltq_gpio_init);
458
459/**
460 * Convert interrupt number to corresponding port/pin pair
461 * Returns the port/pin pair serving the selected external interrupt;
462 * needed since mapping not linear.
463 *
464 * \param exint External interrupt number
465 * \param port Pointer for resulting port
466 * \param pin Pointer for resutling pin
467 * \return -EINVAL Invalid exint
468 * \return 0 port/pin updated
469 * \ingroup API
470 */
471static int ltq_exint2port(u32 exint, int *port, int *pin)
472{
473    if ((exint >= 0) && (exint <= 10)) {
474        *port = 0;
475        *pin = exint + 7;
476    } else if ((exint >= 11) && (exint <= 14)) {
477        *port = 1;
478        *pin = 18 - (exint - 11) ;
479    } else if (exint == 15) {
480        *port = 1;
481        *pin = 19;
482    } else if (exint == 16) {
483        *port = 0;
484        *pin = 19;
485    } else {
486        return -EINVAL;
487    }
488    return 0;
489}
490
491/**
492 * Enable external interrupt.
493 * This function enables an external interrupt and sets the given mode.
494 * valid values for mode are:
495 * - 0 = Interrupt generation disabled
496 * - 1 = Interrupt on rising edge
497 * - 2 = Interrupt on falling edge
498 * - 3 = Interrupt on rising and falling edge
499 * - 5 = Interrupt on high level detection
500 * - 6 = Interrupt on low level detection
501 *
502 * \param exint - Number of external interrupt
503 * \param mode - Trigger mode
504 * \return 0 on success
505 * \ingroup API
506 */
507int ifx_enable_external_int(u32 exint, u32 mode)
508{
509    int port;
510    int pin;
511
512    if ((mode < 0) || (mode > 6))
513        return -EINVAL;
514
515    if (ltq_exint2port(exint, &port, &pin))
516        return -EINVAL;
517
518    ltq_port_clear_exintcr0(port, pin);
519    ltq_port_clear_exintcr1(port, pin);
520    ltq_port_clear_irncfg(port, pin);
521
522    if (mode & 0x1)
523        ltq_port_set_exintcr0(port, pin);
524    if (mode & 0x2)
525        ltq_port_set_exintcr1(port, pin);
526    if (mode & 0x4)
527        ltq_port_set_irncfg(port, pin);
528
529    ltq_port_set_irnen(port, pin);
530    return 0;
531}
532EXPORT_SYMBOL(ifx_enable_external_int);
533
534/**
535 * Disable external interrupt.
536 * This function disables an external interrupt and sets mode to 0x00.
537 *
538 * \param exint - Number of external interrupt
539 * \return 0 on success
540 * \ingroup API
541 */
542int ifx_disable_external_int(u32 exint)
543{
544    int port;
545    int pin;
546
547    if (ltq_exint2port(exint, &port, &pin))
548        return -EINVAL;
549
550    ltq_port_clear_irnen(port, pin);
551    return 0;
552}
553EXPORT_SYMBOL(ifx_disable_external_int);
554

Archive Download this file



interactive