Root/target/linux/cns3xxx/files/arch/arm/mach-cns3xxx/gpio.c

1/*
2 * Copyright 2012 Gateworks Corporation
3 * Chris Lang <clang@gateworks.com>
4 * Tim Harvey <tharvey@gateworks.com>
5 *
6 * This file 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/module.h>
12#include <linux/init.h>
13#include <linux/interrupt.h>
14#include <linux/io.h>
15#include <linux/gpio.h>
16#include <linux/irq.h>
17
18#include <asm/mach/irq.h>
19
20/*
21 * Registers
22 */
23#define GPIO_INPUT 0x04
24#define GPIO_DIR 0x08
25#define GPIO_SET 0x10
26#define GPIO_CLEAR 0x14
27#define GPIO_INTERRUPT_ENABLE 0x20
28#define GPIO_INTERRUPT_RAW_STATUS 0x24
29#define GPIO_INTERRUPT_MASKED_STATUS 0x28
30#define GPIO_INTERRUPT_MASK 0x2C
31#define GPIO_INTERRUPT_CLEAR 0x30
32#define GPIO_INTERRUPT_TRIGGER_METHOD 0x34
33#define GPIO_INTERRUPT_TRIGGER_BOTH_EDGES 0x38
34#define GPIO_INTERRUPT_TRIGGER_TYPE 0x3C
35
36#define GPIO_INTERRUPT_TRIGGER_METHOD_EDGE 0
37#define GPIO_INTERRUPT_TRIGGER_METHOD_LEVEL 1
38#define GPIO_INTERRUPT_TRIGGER_EDGE_SINGLE 0
39#define GPIO_INTERRUPT_TRIGGER_EDGE_BOTH 1
40#define GPIO_INTERRUPT_TRIGGER_TYPE_RISING 0
41#define GPIO_INTERRUPT_TRIGGER_TYPE_FALLING 1
42#define GPIO_INTERRUPT_TRIGGER_TYPE_HIGH 0
43#define GPIO_INTERRUPT_TRIGGER_TYPE_LOW 1
44
45struct cns3xxx_gpio_chip {
46    struct gpio_chip chip;
47    spinlock_t lock;
48    void __iomem *base;
49    int secondary_irq_base;
50};
51
52static struct cns3xxx_gpio_chip cns3xxx_gpio_chips[2];
53static int cns3xxx_gpio_chip_count;
54
55static inline void
56__set_direction(struct cns3xxx_gpio_chip *cchip, unsigned pin, int input)
57{
58    u32 reg;
59
60    reg = __raw_readl(cchip->base + GPIO_DIR);
61    if (input)
62        reg |= 1 << pin;
63    else
64        reg &= !(1 << pin);
65    __raw_writel(reg, cchip->base + GPIO_DIR);
66}
67
68/*
69 * GENERIC_GPIO primatives
70 */
71static int cns3xxx_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
72{
73    struct cns3xxx_gpio_chip *cchip =
74        container_of(chip, struct cns3xxx_gpio_chip, chip);
75    unsigned long flags;
76
77    spin_lock_irqsave(&cchip->lock, flags);
78    __set_direction(cchip, pin, 1);
79    spin_unlock_irqrestore(&cchip->lock, flags);
80
81    return 0;
82}
83
84static int cns3xxx_gpio_get(struct gpio_chip *chip, unsigned pin)
85{
86    struct cns3xxx_gpio_chip *cchip =
87        container_of(chip, struct cns3xxx_gpio_chip, chip);
88    int val;
89
90    val = ((__raw_readl(cchip->base + GPIO_INPUT) >> pin) & 0x1);
91
92    return val;
93}
94
95static int cns3xxx_gpio_direction_output(struct gpio_chip *chip, unsigned pin, int level)
96{
97    struct cns3xxx_gpio_chip *cchip =
98        container_of(chip, struct cns3xxx_gpio_chip, chip);
99    unsigned long flags;
100
101    spin_lock_irqsave(&cchip->lock, flags);
102    if (level)
103        __raw_writel(1 << pin, cchip->base + GPIO_SET);
104    else
105        __raw_writel(1 << pin, cchip->base + GPIO_CLEAR);
106    __set_direction(cchip, pin, 0);
107    spin_unlock_irqrestore(&cchip->lock, flags);
108
109    return 0;
110}
111
112static void cns3xxx_gpio_set(struct gpio_chip *chip, unsigned pin,
113    int level)
114{
115    struct cns3xxx_gpio_chip *cchip =
116        container_of(chip, struct cns3xxx_gpio_chip, chip);
117
118    if (level)
119        __raw_writel(1 << pin, cchip->base + GPIO_SET);
120    else
121        __raw_writel(1 << pin, cchip->base + GPIO_CLEAR);
122}
123
124static int cns3xxx_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
125{
126    struct cns3xxx_gpio_chip *cchip =
127        container_of(chip, struct cns3xxx_gpio_chip, chip);
128
129    return cchip->secondary_irq_base + pin;
130}
131
132
133/*
134 * IRQ support
135 */
136
137/* one interrupt per GPIO controller (GPIOA/GPIOB)
138 * this is called in task context, with IRQs enabled
139 */
140static void cns3xxx_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
141{
142    struct cns3xxx_gpio_chip *cchip = irq_get_handler_data(irq);
143    struct irq_chip *chip = irq_get_chip(irq);
144    struct irq_chip_generic *gc = irq_desc_get_chip_data(desc);
145    struct irq_chip_type *ct = gc->chip_types;
146    u16 i;
147    u32 reg;
148
149    chained_irq_enter(chip, desc); /* mask and ack the base interrupt */
150
151    /* see which pin(s) triggered the interrupt */
152    reg = __raw_readl(cchip->base + GPIO_INTERRUPT_RAW_STATUS);
153    for (i = 0; i < 32; i++) {
154        if (reg & (1 << i)) {
155            /* let the generic IRQ layer handle an interrupt */
156            generic_handle_irq(cchip->secondary_irq_base + i);
157        }
158    }
159
160    chained_irq_exit(chip, desc); /* unmask the base interrupt */
161}
162
163static int cns3xxx_gpio_irq_set_type(struct irq_data *d, u32 irqtype)
164{
165    struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
166    struct cns3xxx_gpio_chip *cchip = gc->private;
167    u32 gpio = d->irq - cchip->secondary_irq_base;
168    unsigned long flags;
169    u32 method, edges, type;
170
171    spin_lock_irqsave(&cchip->lock, flags);
172    method = __raw_readl(cchip->base + GPIO_INTERRUPT_TRIGGER_METHOD);
173    edges = __raw_readl(cchip->base + GPIO_INTERRUPT_TRIGGER_BOTH_EDGES);
174    type = __raw_readl(cchip->base + GPIO_INTERRUPT_TRIGGER_TYPE);
175    method &= ~(1 << gpio);
176    edges &= ~(1 << gpio);
177    type &= ~(1 << gpio);
178
179    switch(irqtype) {
180    case IRQ_TYPE_EDGE_RISING:
181        method |= (GPIO_INTERRUPT_TRIGGER_METHOD_EDGE << gpio);
182        edges |= (GPIO_INTERRUPT_TRIGGER_EDGE_SINGLE << gpio);
183        type |= (GPIO_INTERRUPT_TRIGGER_TYPE_RISING << gpio);
184        break;
185    case IRQ_TYPE_EDGE_FALLING:
186        method |= (GPIO_INTERRUPT_TRIGGER_METHOD_EDGE << gpio);
187        edges |= (GPIO_INTERRUPT_TRIGGER_EDGE_SINGLE << gpio);
188        type |= (GPIO_INTERRUPT_TRIGGER_TYPE_FALLING << gpio);
189        break;
190    case IRQ_TYPE_EDGE_BOTH:
191        method |= (GPIO_INTERRUPT_TRIGGER_METHOD_EDGE << gpio);
192        edges |= (GPIO_INTERRUPT_TRIGGER_EDGE_BOTH << gpio);
193        break;
194    case IRQ_TYPE_LEVEL_LOW:
195        method |= (GPIO_INTERRUPT_TRIGGER_METHOD_LEVEL << gpio);
196        type |= (GPIO_INTERRUPT_TRIGGER_TYPE_LOW << gpio);
197        break;
198    case IRQ_TYPE_LEVEL_HIGH:
199        method |= (GPIO_INTERRUPT_TRIGGER_METHOD_LEVEL << gpio);
200        type |= (GPIO_INTERRUPT_TRIGGER_TYPE_HIGH << gpio);
201        break;
202    default:
203        printk(KERN_WARNING "No irq type\n");
204        spin_unlock_irqrestore(&cchip->lock, flags);
205        return -EINVAL;
206    }
207
208    __raw_writel(method, cchip->base + GPIO_INTERRUPT_TRIGGER_METHOD);
209    __raw_writel(edges, cchip->base + GPIO_INTERRUPT_TRIGGER_BOTH_EDGES);
210    __raw_writel(type, cchip->base + GPIO_INTERRUPT_TRIGGER_TYPE);
211    spin_unlock_irqrestore(&cchip->lock, flags);
212
213    if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
214        __irq_set_handler_locked(d->irq, handle_level_irq);
215    else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
216        __irq_set_handler_locked(d->irq, handle_edge_irq);
217
218    return 0;
219}
220
221void __init cns3xxx_gpio_init(int gpio_base, int ngpio,
222    u32 base, int irq, int secondary_irq_base)
223{
224    struct cns3xxx_gpio_chip *cchip;
225    struct irq_chip_generic *gc;
226    struct irq_chip_type *ct;
227    char gc_label[16];
228
229    if (cns3xxx_gpio_chip_count == ARRAY_SIZE(cns3xxx_gpio_chips))
230        return;
231
232    snprintf(gc_label, sizeof(gc_label), "cns3xxx_gpio%d",
233        cns3xxx_gpio_chip_count);
234
235    cchip = cns3xxx_gpio_chips + cns3xxx_gpio_chip_count;
236    cchip->chip.label = kstrdup(gc_label, GFP_KERNEL);
237    cchip->chip.direction_input = cns3xxx_gpio_direction_input;
238    cchip->chip.get = cns3xxx_gpio_get;
239    cchip->chip.direction_output = cns3xxx_gpio_direction_output;
240    cchip->chip.set = cns3xxx_gpio_set;
241    cchip->chip.to_irq = cns3xxx_gpio_to_irq;
242    cchip->chip.base = gpio_base;
243    cchip->chip.ngpio = ngpio;
244    cchip->chip.can_sleep = 0;
245    spin_lock_init(&cchip->lock);
246    cchip->base = (void __iomem *)base;
247    cchip->secondary_irq_base = secondary_irq_base;
248
249    BUG_ON(gpiochip_add(&cchip->chip) < 0);
250    cns3xxx_gpio_chip_count++;
251
252    /* clear GPIO interrupts */
253    __raw_writel(0xffff, cchip->base + GPIO_INTERRUPT_CLEAR);
254
255    /*
256     * IRQ chip init
257     */
258    gc = irq_alloc_generic_chip("cns3xxx_gpio_irq", 1, secondary_irq_base,
259        cchip->base, handle_edge_irq);
260    gc->private = cchip;
261
262    ct = gc->chip_types;
263    ct->type = IRQ_TYPE_EDGE_FALLING;
264    ct->regs.ack = GPIO_INTERRUPT_CLEAR;
265    ct->regs.enable = GPIO_INTERRUPT_ENABLE;
266    ct->chip.irq_ack = irq_gc_ack_set_bit;
267    ct->chip.irq_enable = irq_gc_unmask_enable_reg;
268    ct->chip.irq_disable = irq_gc_mask_disable_reg;
269    ct->chip.irq_set_type = cns3xxx_gpio_irq_set_type;
270    ct->handler = handle_edge_irq;
271
272    irq_setup_generic_chip(gc, IRQ_MSK(ngpio), IRQ_GC_INIT_MASK_CACHE,
273        IRQ_NOREQUEST, 0);
274
275    irq_set_chained_handler(irq, cns3xxx_gpio_irq_handler);
276    irq_set_handler_data(irq, cchip);
277}
278

Archive Download this file



interactive