Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/mfd/max8998-irq.c
15109 views
1
/*
2
* Interrupt controller support for MAX8998
3
*
4
* Copyright (C) 2010 Samsung Electronics Co.Ltd
5
* Author: Joonyoung Shim <[email protected]>
6
*
7
* This program is free software; you can redistribute it and/or modify it
8
* under the terms of the GNU General Public License as published by the
9
* Free Software Foundation; either version 2 of the License, or (at your
10
* option) any later version.
11
*
12
*/
13
14
#include <linux/device.h>
15
#include <linux/interrupt.h>
16
#include <linux/irq.h>
17
#include <linux/mfd/max8998-private.h>
18
19
struct max8998_irq_data {
20
int reg;
21
int mask;
22
};
23
24
static struct max8998_irq_data max8998_irqs[] = {
25
[MAX8998_IRQ_DCINF] = {
26
.reg = 1,
27
.mask = MAX8998_IRQ_DCINF_MASK,
28
},
29
[MAX8998_IRQ_DCINR] = {
30
.reg = 1,
31
.mask = MAX8998_IRQ_DCINR_MASK,
32
},
33
[MAX8998_IRQ_JIGF] = {
34
.reg = 1,
35
.mask = MAX8998_IRQ_JIGF_MASK,
36
},
37
[MAX8998_IRQ_JIGR] = {
38
.reg = 1,
39
.mask = MAX8998_IRQ_JIGR_MASK,
40
},
41
[MAX8998_IRQ_PWRONF] = {
42
.reg = 1,
43
.mask = MAX8998_IRQ_PWRONF_MASK,
44
},
45
[MAX8998_IRQ_PWRONR] = {
46
.reg = 1,
47
.mask = MAX8998_IRQ_PWRONR_MASK,
48
},
49
[MAX8998_IRQ_WTSREVNT] = {
50
.reg = 2,
51
.mask = MAX8998_IRQ_WTSREVNT_MASK,
52
},
53
[MAX8998_IRQ_SMPLEVNT] = {
54
.reg = 2,
55
.mask = MAX8998_IRQ_SMPLEVNT_MASK,
56
},
57
[MAX8998_IRQ_ALARM1] = {
58
.reg = 2,
59
.mask = MAX8998_IRQ_ALARM1_MASK,
60
},
61
[MAX8998_IRQ_ALARM0] = {
62
.reg = 2,
63
.mask = MAX8998_IRQ_ALARM0_MASK,
64
},
65
[MAX8998_IRQ_ONKEY1S] = {
66
.reg = 3,
67
.mask = MAX8998_IRQ_ONKEY1S_MASK,
68
},
69
[MAX8998_IRQ_TOPOFFR] = {
70
.reg = 3,
71
.mask = MAX8998_IRQ_TOPOFFR_MASK,
72
},
73
[MAX8998_IRQ_DCINOVPR] = {
74
.reg = 3,
75
.mask = MAX8998_IRQ_DCINOVPR_MASK,
76
},
77
[MAX8998_IRQ_CHGRSTF] = {
78
.reg = 3,
79
.mask = MAX8998_IRQ_CHGRSTF_MASK,
80
},
81
[MAX8998_IRQ_DONER] = {
82
.reg = 3,
83
.mask = MAX8998_IRQ_DONER_MASK,
84
},
85
[MAX8998_IRQ_CHGFAULT] = {
86
.reg = 3,
87
.mask = MAX8998_IRQ_CHGFAULT_MASK,
88
},
89
[MAX8998_IRQ_LOBAT1] = {
90
.reg = 4,
91
.mask = MAX8998_IRQ_LOBAT1_MASK,
92
},
93
[MAX8998_IRQ_LOBAT2] = {
94
.reg = 4,
95
.mask = MAX8998_IRQ_LOBAT2_MASK,
96
},
97
};
98
99
static inline struct max8998_irq_data *
100
irq_to_max8998_irq(struct max8998_dev *max8998, int irq)
101
{
102
return &max8998_irqs[irq - max8998->irq_base];
103
}
104
105
static void max8998_irq_lock(struct irq_data *data)
106
{
107
struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data);
108
109
mutex_lock(&max8998->irqlock);
110
}
111
112
static void max8998_irq_sync_unlock(struct irq_data *data)
113
{
114
struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data);
115
int i;
116
117
for (i = 0; i < ARRAY_SIZE(max8998->irq_masks_cur); i++) {
118
/*
119
* If there's been a change in the mask write it back
120
* to the hardware.
121
*/
122
if (max8998->irq_masks_cur[i] != max8998->irq_masks_cache[i]) {
123
max8998->irq_masks_cache[i] = max8998->irq_masks_cur[i];
124
max8998_write_reg(max8998->i2c, MAX8998_REG_IRQM1 + i,
125
max8998->irq_masks_cur[i]);
126
}
127
}
128
129
mutex_unlock(&max8998->irqlock);
130
}
131
132
static void max8998_irq_unmask(struct irq_data *data)
133
{
134
struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data);
135
struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998,
136
data->irq);
137
138
max8998->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
139
}
140
141
static void max8998_irq_mask(struct irq_data *data)
142
{
143
struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data);
144
struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998,
145
data->irq);
146
147
max8998->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
148
}
149
150
static struct irq_chip max8998_irq_chip = {
151
.name = "max8998",
152
.irq_bus_lock = max8998_irq_lock,
153
.irq_bus_sync_unlock = max8998_irq_sync_unlock,
154
.irq_mask = max8998_irq_mask,
155
.irq_unmask = max8998_irq_unmask,
156
};
157
158
static irqreturn_t max8998_irq_thread(int irq, void *data)
159
{
160
struct max8998_dev *max8998 = data;
161
u8 irq_reg[MAX8998_NUM_IRQ_REGS];
162
int ret;
163
int i;
164
165
ret = max8998_bulk_read(max8998->i2c, MAX8998_REG_IRQ1,
166
MAX8998_NUM_IRQ_REGS, irq_reg);
167
if (ret < 0) {
168
dev_err(max8998->dev, "Failed to read interrupt register: %d\n",
169
ret);
170
return IRQ_NONE;
171
}
172
173
/* Apply masking */
174
for (i = 0; i < MAX8998_NUM_IRQ_REGS; i++)
175
irq_reg[i] &= ~max8998->irq_masks_cur[i];
176
177
/* Report */
178
for (i = 0; i < MAX8998_IRQ_NR; i++) {
179
if (irq_reg[max8998_irqs[i].reg - 1] & max8998_irqs[i].mask)
180
handle_nested_irq(max8998->irq_base + i);
181
}
182
183
return IRQ_HANDLED;
184
}
185
186
int max8998_irq_resume(struct max8998_dev *max8998)
187
{
188
if (max8998->irq && max8998->irq_base)
189
max8998_irq_thread(max8998->irq_base, max8998);
190
return 0;
191
}
192
193
int max8998_irq_init(struct max8998_dev *max8998)
194
{
195
int i;
196
int cur_irq;
197
int ret;
198
199
if (!max8998->irq) {
200
dev_warn(max8998->dev,
201
"No interrupt specified, no interrupts\n");
202
max8998->irq_base = 0;
203
return 0;
204
}
205
206
if (!max8998->irq_base) {
207
dev_err(max8998->dev,
208
"No interrupt base specified, no interrupts\n");
209
return 0;
210
}
211
212
mutex_init(&max8998->irqlock);
213
214
/* Mask the individual interrupt sources */
215
for (i = 0; i < MAX8998_NUM_IRQ_REGS; i++) {
216
max8998->irq_masks_cur[i] = 0xff;
217
max8998->irq_masks_cache[i] = 0xff;
218
max8998_write_reg(max8998->i2c, MAX8998_REG_IRQM1 + i, 0xff);
219
}
220
221
max8998_write_reg(max8998->i2c, MAX8998_REG_STATUSM1, 0xff);
222
max8998_write_reg(max8998->i2c, MAX8998_REG_STATUSM2, 0xff);
223
224
/* register with genirq */
225
for (i = 0; i < MAX8998_IRQ_NR; i++) {
226
cur_irq = i + max8998->irq_base;
227
irq_set_chip_data(cur_irq, max8998);
228
irq_set_chip_and_handler(cur_irq, &max8998_irq_chip,
229
handle_edge_irq);
230
irq_set_nested_thread(cur_irq, 1);
231
#ifdef CONFIG_ARM
232
set_irq_flags(cur_irq, IRQF_VALID);
233
#else
234
irq_set_noprobe(cur_irq);
235
#endif
236
}
237
238
ret = request_threaded_irq(max8998->irq, NULL, max8998_irq_thread,
239
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
240
"max8998-irq", max8998);
241
if (ret) {
242
dev_err(max8998->dev, "Failed to request IRQ %d: %d\n",
243
max8998->irq, ret);
244
return ret;
245
}
246
247
if (!max8998->ono)
248
return 0;
249
250
ret = request_threaded_irq(max8998->ono, NULL, max8998_irq_thread,
251
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
252
IRQF_ONESHOT, "max8998-ono", max8998);
253
if (ret)
254
dev_err(max8998->dev, "Failed to request IRQ %d: %d\n",
255
max8998->ono, ret);
256
257
return 0;
258
}
259
260
void max8998_irq_exit(struct max8998_dev *max8998)
261
{
262
if (max8998->ono)
263
free_irq(max8998->ono, max8998);
264
265
if (max8998->irq)
266
free_irq(max8998->irq, max8998);
267
}
268
269