~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to arch/arm/mach-s3c64xx/irq-eint.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* arch/arm/plat-s3c64xx/irq-eint.c
 
2
 *
 
3
 * Copyright 2008 Openmoko, Inc.
 
4
 * Copyright 2008 Simtec Electronics
 
5
 *      Ben Dooks <ben@simtec.co.uk>
 
6
 *      http://armlinux.simtec.co.uk/
 
7
 *
 
8
 * S3C64XX - Interrupt handling for IRQ_EINT(x)
 
9
 *
 
10
 * This program is free software; you can redistribute it and/or modify
 
11
 * it under the terms of the GNU General Public License version 2 as
 
12
 * published by the Free Software Foundation.
 
13
 */
 
14
 
 
15
#include <linux/kernel.h>
 
16
#include <linux/interrupt.h>
 
17
#include <linux/sysdev.h>
 
18
#include <linux/gpio.h>
 
19
#include <linux/irq.h>
 
20
#include <linux/io.h>
 
21
 
 
22
#include <asm/hardware/vic.h>
 
23
 
 
24
#include <plat/regs-irqtype.h>
 
25
#include <mach/regs-gpio.h>
 
26
#include <plat/gpio-cfg.h>
 
27
 
 
28
#include <mach/map.h>
 
29
#include <plat/cpu.h>
 
30
#include <plat/pm.h>
 
31
 
 
32
#define eint_offset(irq)        ((irq) - IRQ_EINT(0))
 
33
#define eint_irq_to_bit(irq)    ((u32)(1 << eint_offset(irq)))
 
34
 
 
35
static inline void s3c_irq_eint_mask(struct irq_data *data)
 
36
{
 
37
        u32 mask;
 
38
 
 
39
        mask = __raw_readl(S3C64XX_EINT0MASK);
 
40
        mask |= (u32)data->chip_data;
 
41
        __raw_writel(mask, S3C64XX_EINT0MASK);
 
42
}
 
43
 
 
44
static void s3c_irq_eint_unmask(struct irq_data *data)
 
45
{
 
46
        u32 mask;
 
47
 
 
48
        mask = __raw_readl(S3C64XX_EINT0MASK);
 
49
        mask &= ~((u32)data->chip_data);
 
50
        __raw_writel(mask, S3C64XX_EINT0MASK);
 
51
}
 
52
 
 
53
static inline void s3c_irq_eint_ack(struct irq_data *data)
 
54
{
 
55
        __raw_writel((u32)data->chip_data, S3C64XX_EINT0PEND);
 
56
}
 
57
 
 
58
static void s3c_irq_eint_maskack(struct irq_data *data)
 
59
{
 
60
        /* compiler should in-line these */
 
61
        s3c_irq_eint_mask(data);
 
62
        s3c_irq_eint_ack(data);
 
63
}
 
64
 
 
65
static int s3c_irq_eint_set_type(struct irq_data *data, unsigned int type)
 
66
{
 
67
        int offs = eint_offset(data->irq);
 
68
        int pin, pin_val;
 
69
        int shift;
 
70
        u32 ctrl, mask;
 
71
        u32 newvalue = 0;
 
72
        void __iomem *reg;
 
73
 
 
74
        if (offs > 27)
 
75
                return -EINVAL;
 
76
 
 
77
        if (offs <= 15)
 
78
                reg = S3C64XX_EINT0CON0;
 
79
        else
 
80
                reg = S3C64XX_EINT0CON1;
 
81
 
 
82
        switch (type) {
 
83
        case IRQ_TYPE_NONE:
 
84
                printk(KERN_WARNING "No edge setting!\n");
 
85
                break;
 
86
 
 
87
        case IRQ_TYPE_EDGE_RISING:
 
88
                newvalue = S3C2410_EXTINT_RISEEDGE;
 
89
                break;
 
90
 
 
91
        case IRQ_TYPE_EDGE_FALLING:
 
92
                newvalue = S3C2410_EXTINT_FALLEDGE;
 
93
                break;
 
94
 
 
95
        case IRQ_TYPE_EDGE_BOTH:
 
96
                newvalue = S3C2410_EXTINT_BOTHEDGE;
 
97
                break;
 
98
 
 
99
        case IRQ_TYPE_LEVEL_LOW:
 
100
                newvalue = S3C2410_EXTINT_LOWLEV;
 
101
                break;
 
102
 
 
103
        case IRQ_TYPE_LEVEL_HIGH:
 
104
                newvalue = S3C2410_EXTINT_HILEV;
 
105
                break;
 
106
 
 
107
        default:
 
108
                printk(KERN_ERR "No such irq type %d", type);
 
109
                return -1;
 
110
        }
 
111
 
 
112
        if (offs <= 15)
 
113
                shift = (offs / 2) * 4;
 
114
        else
 
115
                shift = ((offs - 16) / 2) * 4;
 
116
        mask = 0x7 << shift;
 
117
 
 
118
        ctrl = __raw_readl(reg);
 
119
        ctrl &= ~mask;
 
120
        ctrl |= newvalue << shift;
 
121
        __raw_writel(ctrl, reg);
 
122
 
 
123
        /* set the GPIO pin appropriately */
 
124
 
 
125
        if (offs < 16) {
 
126
                pin = S3C64XX_GPN(offs);
 
127
                pin_val = S3C_GPIO_SFN(2);
 
128
        } else if (offs < 23) {
 
129
                pin = S3C64XX_GPL(offs + 8 - 16);
 
130
                pin_val = S3C_GPIO_SFN(3);
 
131
        } else {
 
132
                pin = S3C64XX_GPM(offs - 23);
 
133
                pin_val = S3C_GPIO_SFN(3);
 
134
        }
 
135
 
 
136
        s3c_gpio_cfgpin(pin, pin_val);
 
137
 
 
138
        return 0;
 
139
}
 
140
 
 
141
static struct irq_chip s3c_irq_eint = {
 
142
        .name           = "s3c-eint",
 
143
        .irq_mask       = s3c_irq_eint_mask,
 
144
        .irq_unmask     = s3c_irq_eint_unmask,
 
145
        .irq_mask_ack   = s3c_irq_eint_maskack,
 
146
        .irq_ack        = s3c_irq_eint_ack,
 
147
        .irq_set_type   = s3c_irq_eint_set_type,
 
148
        .irq_set_wake   = s3c_irqext_wake,
 
149
};
 
150
 
 
151
/* s3c_irq_demux_eint
 
152
 *
 
153
 * This function demuxes the IRQ from the group0 external interrupts,
 
154
 * from IRQ_EINT(0) to IRQ_EINT(27). It is designed to be inlined into
 
155
 * the specific handlers s3c_irq_demux_eintX_Y.
 
156
 */
 
157
static inline void s3c_irq_demux_eint(unsigned int start, unsigned int end)
 
158
{
 
159
        u32 status = __raw_readl(S3C64XX_EINT0PEND);
 
160
        u32 mask = __raw_readl(S3C64XX_EINT0MASK);
 
161
        unsigned int irq;
 
162
 
 
163
        status &= ~mask;
 
164
        status >>= start;
 
165
        status &= (1 << (end - start + 1)) - 1;
 
166
 
 
167
        for (irq = IRQ_EINT(start); irq <= IRQ_EINT(end); irq++) {
 
168
                if (status & 1)
 
169
                        generic_handle_irq(irq);
 
170
 
 
171
                status >>= 1;
 
172
        }
 
173
}
 
174
 
 
175
static void s3c_irq_demux_eint0_3(unsigned int irq, struct irq_desc *desc)
 
176
{
 
177
        s3c_irq_demux_eint(0, 3);
 
178
}
 
179
 
 
180
static void s3c_irq_demux_eint4_11(unsigned int irq, struct irq_desc *desc)
 
181
{
 
182
        s3c_irq_demux_eint(4, 11);
 
183
}
 
184
 
 
185
static void s3c_irq_demux_eint12_19(unsigned int irq, struct irq_desc *desc)
 
186
{
 
187
        s3c_irq_demux_eint(12, 19);
 
188
}
 
189
 
 
190
static void s3c_irq_demux_eint20_27(unsigned int irq, struct irq_desc *desc)
 
191
{
 
192
        s3c_irq_demux_eint(20, 27);
 
193
}
 
194
 
 
195
static int __init s3c64xx_init_irq_eint(void)
 
196
{
 
197
        int irq;
 
198
 
 
199
        for (irq = IRQ_EINT(0); irq <= IRQ_EINT(27); irq++) {
 
200
                irq_set_chip_and_handler(irq, &s3c_irq_eint, handle_level_irq);
 
201
                irq_set_chip_data(irq, (void *)eint_irq_to_bit(irq));
 
202
                set_irq_flags(irq, IRQF_VALID);
 
203
        }
 
204
 
 
205
        irq_set_chained_handler(IRQ_EINT0_3, s3c_irq_demux_eint0_3);
 
206
        irq_set_chained_handler(IRQ_EINT4_11, s3c_irq_demux_eint4_11);
 
207
        irq_set_chained_handler(IRQ_EINT12_19, s3c_irq_demux_eint12_19);
 
208
        irq_set_chained_handler(IRQ_EINT20_27, s3c_irq_demux_eint20_27);
 
209
 
 
210
        return 0;
 
211
}
 
212
 
 
213
arch_initcall(s3c64xx_init_irq_eint);