~ubuntu-branches/debian/wheezy/linux-2.6/wheezy

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Ben Hutchings, Ben Hutchings, Aurelien Jarno, Martin Michlmayr
  • Date: 2011-04-06 13:53:30 UTC
  • mfrom: (43.1.5 sid)
  • Revision ID: james.westby@ubuntu.com-20110406135330-wjufxhd0tvn3zx4z
Tags: 2.6.38-3
[ Ben Hutchings ]
* [ppc64] Add to linux-tools package architectures (Closes: #620124)
* [amd64] Save cr4 to mmu_cr4_features at boot time (Closes: #620284)
* appletalk: Fix bugs introduced when removing use of BKL
* ALSA: Fix yet another race in disconnection
* cciss: Fix lost command issue
* ath9k: Fix kernel panic in AR2427
* ses: Avoid kernel panic when lun 0 is not mapped
* PCI/ACPI: Report ASPM support to BIOS if not disabled from command line

[ Aurelien Jarno ]
* rtlwifi: fix build when PCI is not enabled.

[ Martin Michlmayr ]
* rtlwifi: Eliminate udelay calls with too large values (Closes: #620204)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* linux/arch/arm/mach-s5pv310/irq-eint.c
 
2
 *
 
3
 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
 
4
 *              http://www.samsung.com
 
5
 *
 
6
 * S5PV310 - IRQ EINT support
 
7
 *
 
8
 * This program is free software; you can redistribute it and/or modify
 
9
 * it under the terms of the GNU General Public License version 2 as
 
10
 * published by the Free Software Foundation.
 
11
*/
 
12
 
 
13
#include <linux/kernel.h>
 
14
#include <linux/interrupt.h>
 
15
#include <linux/irq.h>
 
16
#include <linux/io.h>
 
17
#include <linux/sysdev.h>
 
18
#include <linux/gpio.h>
 
19
 
 
20
#include <plat/pm.h>
 
21
#include <plat/cpu.h>
 
22
#include <plat/gpio-cfg.h>
 
23
 
 
24
#include <mach/regs-gpio.h>
 
25
 
 
26
static DEFINE_SPINLOCK(eint_lock);
 
27
 
 
28
static unsigned int eint0_15_data[16];
 
29
 
 
30
static unsigned int s5pv310_get_irq_nr(unsigned int number)
 
31
{
 
32
        u32 ret = 0;
 
33
 
 
34
        switch (number) {
 
35
        case 0 ... 3:
 
36
                ret = (number + IRQ_EINT0);
 
37
                break;
 
38
        case 4 ... 7:
 
39
                ret = (number + (IRQ_EINT4 - 4));
 
40
                break;
 
41
        case 8 ... 15:
 
42
                ret = (number + (IRQ_EINT8 - 8));
 
43
                break;
 
44
        default:
 
45
                printk(KERN_ERR "number available : %d\n", number);
 
46
        }
 
47
 
 
48
        return ret;
 
49
}
 
50
 
 
51
static inline void s5pv310_irq_eint_mask(struct irq_data *data)
 
52
{
 
53
        u32 mask;
 
54
 
 
55
        spin_lock(&eint_lock);
 
56
        mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq)));
 
57
        mask |= eint_irq_to_bit(data->irq);
 
58
        __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq)));
 
59
        spin_unlock(&eint_lock);
 
60
}
 
61
 
 
62
static void s5pv310_irq_eint_unmask(struct irq_data *data)
 
63
{
 
64
        u32 mask;
 
65
 
 
66
        spin_lock(&eint_lock);
 
67
        mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq)));
 
68
        mask &= ~(eint_irq_to_bit(data->irq));
 
69
        __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq)));
 
70
        spin_unlock(&eint_lock);
 
71
}
 
72
 
 
73
static inline void s5pv310_irq_eint_ack(struct irq_data *data)
 
74
{
 
75
        __raw_writel(eint_irq_to_bit(data->irq),
 
76
                     S5P_EINT_PEND(EINT_REG_NR(data->irq)));
 
77
}
 
78
 
 
79
static void s5pv310_irq_eint_maskack(struct irq_data *data)
 
80
{
 
81
        s5pv310_irq_eint_mask(data);
 
82
        s5pv310_irq_eint_ack(data);
 
83
}
 
84
 
 
85
static int s5pv310_irq_eint_set_type(struct irq_data *data, unsigned int type)
 
86
{
 
87
        int offs = EINT_OFFSET(data->irq);
 
88
        int shift;
 
89
        u32 ctrl, mask;
 
90
        u32 newvalue = 0;
 
91
 
 
92
        switch (type) {
 
93
        case IRQ_TYPE_EDGE_RISING:
 
94
                newvalue = S5P_IRQ_TYPE_EDGE_RISING;
 
95
                break;
 
96
 
 
97
        case IRQ_TYPE_EDGE_FALLING:
 
98
                newvalue = S5P_IRQ_TYPE_EDGE_FALLING;
 
99
                break;
 
100
 
 
101
        case IRQ_TYPE_EDGE_BOTH:
 
102
                newvalue = S5P_IRQ_TYPE_EDGE_BOTH;
 
103
                break;
 
104
 
 
105
        case IRQ_TYPE_LEVEL_LOW:
 
106
                newvalue = S5P_IRQ_TYPE_LEVEL_LOW;
 
107
                break;
 
108
 
 
109
        case IRQ_TYPE_LEVEL_HIGH:
 
110
                newvalue = S5P_IRQ_TYPE_LEVEL_HIGH;
 
111
                break;
 
112
 
 
113
        default:
 
114
                printk(KERN_ERR "No such irq type %d", type);
 
115
                return -EINVAL;
 
116
        }
 
117
 
 
118
        shift = (offs & 0x7) * 4;
 
119
        mask = 0x7 << shift;
 
120
 
 
121
        spin_lock(&eint_lock);
 
122
        ctrl = __raw_readl(S5P_EINT_CON(EINT_REG_NR(data->irq)));
 
123
        ctrl &= ~mask;
 
124
        ctrl |= newvalue << shift;
 
125
        __raw_writel(ctrl, S5P_EINT_CON(EINT_REG_NR(data->irq)));
 
126
        spin_unlock(&eint_lock);
 
127
 
 
128
        switch (offs) {
 
129
        case 0 ... 7:
 
130
                s3c_gpio_cfgpin(EINT_GPIO_0(offs & 0x7), EINT_MODE);
 
131
                break;
 
132
        case 8 ... 15:
 
133
                s3c_gpio_cfgpin(EINT_GPIO_1(offs & 0x7), EINT_MODE);
 
134
                break;
 
135
        case 16 ... 23:
 
136
                s3c_gpio_cfgpin(EINT_GPIO_2(offs & 0x7), EINT_MODE);
 
137
                break;
 
138
        case 24 ... 31:
 
139
                s3c_gpio_cfgpin(EINT_GPIO_3(offs & 0x7), EINT_MODE);
 
140
                break;
 
141
        default:
 
142
                printk(KERN_ERR "No such irq number %d", offs);
 
143
        }
 
144
 
 
145
        return 0;
 
146
}
 
147
 
 
148
static struct irq_chip s5pv310_irq_eint = {
 
149
        .name           = "s5pv310-eint",
 
150
        .irq_mask       = s5pv310_irq_eint_mask,
 
151
        .irq_unmask     = s5pv310_irq_eint_unmask,
 
152
        .irq_mask_ack   = s5pv310_irq_eint_maskack,
 
153
        .irq_ack        = s5pv310_irq_eint_ack,
 
154
        .irq_set_type   = s5pv310_irq_eint_set_type,
 
155
#ifdef CONFIG_PM
 
156
        .irq_set_wake   = s3c_irqext_wake,
 
157
#endif
 
158
};
 
159
 
 
160
/* s5pv310_irq_demux_eint
 
161
 *
 
162
 * This function demuxes the IRQ from from EINTs 16 to 31.
 
163
 * It is designed to be inlined into the specific handler
 
164
 * s5p_irq_demux_eintX_Y.
 
165
 *
 
166
 * Each EINT pend/mask registers handle eight of them.
 
167
 */
 
168
static inline void s5pv310_irq_demux_eint(unsigned int start)
 
169
{
 
170
        unsigned int irq;
 
171
 
 
172
        u32 status = __raw_readl(S5P_EINT_PEND(EINT_REG_NR(start)));
 
173
        u32 mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(start)));
 
174
 
 
175
        status &= ~mask;
 
176
        status &= 0xff;
 
177
 
 
178
        while (status) {
 
179
                irq = fls(status) - 1;
 
180
                generic_handle_irq(irq + start);
 
181
                status &= ~(1 << irq);
 
182
        }
 
183
}
 
184
 
 
185
static void s5pv310_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
 
186
{
 
187
        s5pv310_irq_demux_eint(IRQ_EINT(16));
 
188
        s5pv310_irq_demux_eint(IRQ_EINT(24));
 
189
}
 
190
 
 
191
static void s5pv310_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
 
192
{
 
193
        u32 *irq_data = get_irq_data(irq);
 
194
        struct irq_chip *chip = get_irq_chip(irq);
 
195
 
 
196
        chip->irq_mask(&desc->irq_data);
 
197
 
 
198
        if (chip->irq_ack)
 
199
                chip->irq_ack(&desc->irq_data);
 
200
 
 
201
        generic_handle_irq(*irq_data);
 
202
 
 
203
        chip->irq_unmask(&desc->irq_data);
 
204
}
 
205
 
 
206
int __init s5pv310_init_irq_eint(void)
 
207
{
 
208
        int irq;
 
209
 
 
210
        for (irq = 0 ; irq <= 31 ; irq++) {
 
211
                set_irq_chip(IRQ_EINT(irq), &s5pv310_irq_eint);
 
212
                set_irq_handler(IRQ_EINT(irq), handle_level_irq);
 
213
                set_irq_flags(IRQ_EINT(irq), IRQF_VALID);
 
214
        }
 
215
 
 
216
        set_irq_chained_handler(IRQ_EINT16_31, s5pv310_irq_demux_eint16_31);
 
217
 
 
218
        for (irq = 0 ; irq <= 15 ; irq++) {
 
219
                eint0_15_data[irq] = IRQ_EINT(irq);
 
220
 
 
221
                set_irq_data(s5pv310_get_irq_nr(irq), &eint0_15_data[irq]);
 
222
                set_irq_chained_handler(s5pv310_get_irq_nr(irq),
 
223
                                        s5pv310_irq_eint0_15);
 
224
        }
 
225
 
 
226
        return 0;
 
227
}
 
228
 
 
229
arch_initcall(s5pv310_init_irq_eint);