aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/max8907c-irq.c
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
commitfcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch)
treea57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/mfd/max8907c-irq.c
parent8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff)
Added missing tegra files.HEADmaster
Diffstat (limited to 'drivers/mfd/max8907c-irq.c')
-rw-r--r--drivers/mfd/max8907c-irq.c425
1 files changed, 425 insertions, 0 deletions
diff --git a/drivers/mfd/max8907c-irq.c b/drivers/mfd/max8907c-irq.c
new file mode 100644
index 00000000000..8d6e9600e7f
--- /dev/null
+++ b/drivers/mfd/max8907c-irq.c
@@ -0,0 +1,425 @@
1/*
2 * Battery driver for Maxim MAX8907C
3 *
4 * Copyright (c) 2011, NVIDIA Corporation.
5 * Based on driver/mfd/max8925-core.c, Copyright (C) 2009-2010 Marvell International Ltd.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/slab.h>
15#include <linux/i2c.h>
16#include <linux/irq.h>
17#include <linux/interrupt.h>
18#include <linux/mfd/core.h>
19#include <linux/mfd/max8907c.h>
20
21struct max8907c_irq_data {
22 int reg;
23 int mask_reg;
24 int enable; /* enable or not */
25 int offs; /* bit offset in mask register */
26 bool is_rtc;
27 int wake;
28};
29
30static struct max8907c_irq_data max8907c_irqs[] = {
31 [MAX8907C_IRQ_VCHG_DC_OVP] = {
32 .reg = MAX8907C_REG_CHG_IRQ1,
33 .mask_reg = MAX8907C_REG_CHG_IRQ1_MASK,
34 .offs = 1 << 0,
35 },
36 [MAX8907C_IRQ_VCHG_DC_F] = {
37 .reg = MAX8907C_REG_CHG_IRQ1,
38 .mask_reg = MAX8907C_REG_CHG_IRQ1_MASK,
39 .offs = 1 << 1,
40 },
41 [MAX8907C_IRQ_VCHG_DC_R] = {
42 .reg = MAX8907C_REG_CHG_IRQ1,
43 .mask_reg = MAX8907C_REG_CHG_IRQ1_MASK,
44 .offs = 1 << 2,
45 },
46 [MAX8907C_IRQ_VCHG_THM_OK_R] = {
47 .reg = MAX8907C_REG_CHG_IRQ2,
48 .mask_reg = MAX8907C_REG_CHG_IRQ2_MASK,
49 .offs = 1 << 0,
50 },
51 [MAX8907C_IRQ_VCHG_THM_OK_F] = {
52 .reg = MAX8907C_REG_CHG_IRQ2,
53 .mask_reg = MAX8907C_REG_CHG_IRQ2_MASK,
54 .offs = 1 << 1,
55 },
56 [MAX8907C_IRQ_VCHG_MBATTLOW_F] = {
57 .reg = MAX8907C_REG_CHG_IRQ2,
58 .mask_reg = MAX8907C_REG_CHG_IRQ2_MASK,
59 .offs = 1 << 2,
60 },
61 [MAX8907C_IRQ_VCHG_MBATTLOW_R] = {
62 .reg = MAX8907C_REG_CHG_IRQ2,
63 .mask_reg = MAX8907C_REG_CHG_IRQ2_MASK,
64 .offs = 1 << 3,
65 },
66 [MAX8907C_IRQ_VCHG_RST] = {
67 .reg = MAX8907C_REG_CHG_IRQ2,
68 .mask_reg = MAX8907C_REG_CHG_IRQ2_MASK,
69 .offs = 1 << 4,
70 },
71 [MAX8907C_IRQ_VCHG_DONE] = {
72 .reg = MAX8907C_REG_CHG_IRQ2,
73 .mask_reg = MAX8907C_REG_CHG_IRQ2_MASK,
74 .offs = 1 << 5,
75 },
76 [MAX8907C_IRQ_VCHG_TOPOFF] = {
77 .reg = MAX8907C_REG_CHG_IRQ2,
78 .mask_reg = MAX8907C_REG_CHG_IRQ2_MASK,
79 .offs = 1 << 6,
80 },
81 [MAX8907C_IRQ_VCHG_TMR_FAULT] = {
82 .reg = MAX8907C_REG_CHG_IRQ2,
83 .mask_reg = MAX8907C_REG_CHG_IRQ2_MASK,
84 .offs = 1 << 7,
85 },
86 [MAX8907C_IRQ_GPM_RSTIN] = {
87 .reg = MAX8907C_REG_ON_OFF_IRQ1,
88 .mask_reg = MAX8907C_REG_ON_OFF_IRQ1_MASK,
89 .offs = 1 << 0,
90 },
91 [MAX8907C_IRQ_GPM_MPL] = {
92 .reg = MAX8907C_REG_ON_OFF_IRQ1,
93 .mask_reg = MAX8907C_REG_ON_OFF_IRQ1_MASK,
94 .offs = 1 << 1,
95 },
96 [MAX8907C_IRQ_GPM_SW_3SEC] = {
97 .reg = MAX8907C_REG_ON_OFF_IRQ1,
98 .mask_reg = MAX8907C_REG_ON_OFF_IRQ1_MASK,
99 .offs = 1 << 2,
100 },
101 [MAX8907C_IRQ_GPM_EXTON_F] = {
102 .reg = MAX8907C_REG_ON_OFF_IRQ1,
103 .mask_reg = MAX8907C_REG_ON_OFF_IRQ1_MASK,
104 .offs = 1 << 3,
105 },
106 [MAX8907C_IRQ_GPM_EXTON_R] = {
107 .reg = MAX8907C_REG_ON_OFF_IRQ1,
108 .mask_reg = MAX8907C_REG_ON_OFF_IRQ1_MASK,
109 .offs = 1 << 4,
110 },
111 [MAX8907C_IRQ_GPM_SW_1SEC] = {
112 .reg = MAX8907C_REG_ON_OFF_IRQ1,
113 .mask_reg = MAX8907C_REG_ON_OFF_IRQ1_MASK,
114 .offs = 1 << 5,
115 },
116 [MAX8907C_IRQ_GPM_SW_F] = {
117 .reg = MAX8907C_REG_ON_OFF_IRQ1,
118 .mask_reg = MAX8907C_REG_ON_OFF_IRQ1_MASK,
119 .offs = 1 << 6,
120 },
121 [MAX8907C_IRQ_GPM_SW_R] = {
122 .reg = MAX8907C_REG_ON_OFF_IRQ1,
123 .mask_reg = MAX8907C_REG_ON_OFF_IRQ1_MASK,
124 .offs = 1 << 7,
125 },
126 [MAX8907C_IRQ_GPM_SYSCKEN_F] = {
127 .reg = MAX8907C_REG_ON_OFF_IRQ2,
128 .mask_reg = MAX8907C_REG_ON_OFF_IRQ2_MASK,
129 .offs = 1 << 0,
130 },
131 [MAX8907C_IRQ_GPM_SYSCKEN_R] = {
132 .reg = MAX8907C_REG_ON_OFF_IRQ2,
133 .mask_reg = MAX8907C_REG_ON_OFF_IRQ2_MASK,
134 .offs = 1 << 1,
135 },
136 [MAX8907C_IRQ_RTC_ALARM1] = {
137 .reg = MAX8907C_REG_RTC_IRQ,
138 .mask_reg = MAX8907C_REG_RTC_IRQ_MASK,
139 .offs = 1 << 2,
140 .is_rtc = true,
141 },
142 [MAX8907C_IRQ_RTC_ALARM0] = {
143 .reg = MAX8907C_REG_RTC_IRQ,
144 .mask_reg = MAX8907C_REG_RTC_IRQ_MASK,
145 .offs = 1 << 3,
146 .is_rtc = true,
147 },
148};
149
150static inline struct max8907c_irq_data *irq_to_max8907c(struct max8907c *chip,
151 int irq)
152{
153 return &max8907c_irqs[irq - chip->irq_base];
154}
155
156static irqreturn_t max8907c_irq(int irq, void *data)
157{
158 struct max8907c *chip = data;
159 struct max8907c_irq_data *irq_data;
160 struct i2c_client *i2c;
161 int read_reg = -1, value = 0;
162 int i;
163
164 for (i = 0; i < ARRAY_SIZE(max8907c_irqs); i++) {
165 irq_data = &max8907c_irqs[i];
166
167 if (irq_data->is_rtc)
168 i2c = chip->i2c_rtc;
169 else
170 i2c = chip->i2c_power;
171
172 if (read_reg != irq_data->reg) {
173 read_reg = irq_data->reg;
174 value = max8907c_reg_read(i2c, irq_data->reg);
175 }
176
177 if (value & irq_data->enable)
178 handle_nested_irq(chip->irq_base + i);
179 }
180 return IRQ_HANDLED;
181}
182
183static void max8907c_irq_lock(struct irq_data *data)
184{
185 struct max8907c *chip = irq_data_get_irq_chip_data(data);
186
187 mutex_lock(&chip->irq_lock);
188}
189
190static void max8907c_irq_sync_unlock(struct irq_data *data)
191{
192 struct max8907c *chip = irq_data_get_irq_chip_data(data);
193 struct max8907c_irq_data *irq_data;
194 unsigned char irq_chg[2], irq_on[2];
195 unsigned char irq_rtc;
196 int i;
197
198 irq_chg[0] = irq_chg[1] = irq_on[0] = irq_on[1] = irq_rtc = 0xFF;
199
200 for (i = 0; i < ARRAY_SIZE(max8907c_irqs); i++) {
201 irq_data = &max8907c_irqs[i];
202 /* 1 -- disable, 0 -- enable */
203 switch (irq_data->mask_reg) {
204 case MAX8907C_REG_CHG_IRQ1_MASK:
205 irq_chg[0] &= ~irq_data->enable;
206 break;
207 case MAX8907C_REG_CHG_IRQ2_MASK:
208 irq_chg[1] &= ~irq_data->enable;
209 break;
210 case MAX8907C_REG_ON_OFF_IRQ1_MASK:
211 irq_on[0] &= ~irq_data->enable;
212 break;
213 case MAX8907C_REG_ON_OFF_IRQ2_MASK:
214 irq_on[1] &= ~irq_data->enable;
215 break;
216 case MAX8907C_REG_RTC_IRQ_MASK:
217 irq_rtc &= ~irq_data->enable;
218 break;
219 default:
220 dev_err(chip->dev, "wrong IRQ\n");
221 break;
222 }
223 }
224 /* update mask into registers */
225 if (chip->cache_chg[0] != irq_chg[0]) {
226 chip->cache_chg[0] = irq_chg[0];
227 max8907c_reg_write(chip->i2c_power, MAX8907C_REG_CHG_IRQ1_MASK,
228 irq_chg[0]);
229 }
230 if (chip->cache_chg[1] != irq_chg[1]) {
231 chip->cache_chg[1] = irq_chg[1];
232 max8907c_reg_write(chip->i2c_power, MAX8907C_REG_CHG_IRQ2_MASK,
233 irq_chg[1]);
234 }
235 if (chip->cache_on[0] != irq_on[0]) {
236 chip->cache_on[0] = irq_on[0];
237 max8907c_reg_write(chip->i2c_power, MAX8907C_REG_ON_OFF_IRQ1_MASK,
238 irq_on[0]);
239 }
240 if (chip->cache_on[1] != irq_on[1]) {
241 chip->cache_on[1] = irq_on[1];
242 max8907c_reg_write(chip->i2c_power, MAX8907C_REG_ON_OFF_IRQ2_MASK,
243 irq_on[1]);
244 }
245 if (chip->cache_rtc != irq_rtc) {
246 chip->cache_rtc = irq_rtc;
247 max8907c_reg_write(chip->i2c_rtc, MAX8907C_REG_RTC_IRQ_MASK,
248 irq_rtc);
249 }
250
251 mutex_unlock(&chip->irq_lock);
252}
253
254static void max8907c_irq_enable(struct irq_data *data)
255{
256 struct max8907c *chip = irq_data_get_irq_chip_data(data);
257 max8907c_irqs[data->irq - chip->irq_base].enable
258 = max8907c_irqs[data->irq - chip->irq_base].offs;
259}
260
261static void max8907c_irq_disable(struct irq_data *data)
262{
263 struct max8907c *chip = irq_data_get_irq_chip_data(data);
264 max8907c_irqs[data->irq - chip->irq_base].enable = 0;
265}
266
267static int max8907c_irq_set_wake(struct irq_data *data, unsigned int on)
268{
269 struct max8907c *chip = irq_data_get_irq_chip_data(data);
270 if (on) {
271 max8907c_irqs[data->irq - chip->irq_base].wake
272 = max8907c_irqs[data->irq - chip->irq_base].enable;
273 } else {
274 max8907c_irqs[data->irq - chip->irq_base].wake = 0;
275 }
276 return 0;
277}
278
279static struct irq_chip max8907c_irq_chip = {
280 .name = "max8907c",
281 .irq_bus_lock = max8907c_irq_lock,
282 .irq_bus_sync_unlock = max8907c_irq_sync_unlock,
283 .irq_enable = max8907c_irq_enable,
284 .irq_disable = max8907c_irq_disable,
285 .irq_set_wake = max8907c_irq_set_wake,
286};
287
288int max8907c_irq_init(struct max8907c *chip, int irq, int irq_base)
289{
290 unsigned long flags = IRQF_ONESHOT;
291 struct irq_desc *desc;
292 int i, ret;
293 int __irq;
294
295 if (!irq_base || !irq) {
296 dev_warn(chip->dev, "No interrupt support\n");
297 return -EINVAL;
298 }
299 /* clear all interrupts */
300 max8907c_reg_read(chip->i2c_power, MAX8907C_REG_CHG_IRQ1);
301 max8907c_reg_read(chip->i2c_power, MAX8907C_REG_CHG_IRQ2);
302 max8907c_reg_read(chip->i2c_power, MAX8907C_REG_ON_OFF_IRQ1);
303 max8907c_reg_read(chip->i2c_power, MAX8907C_REG_ON_OFF_IRQ2);
304 max8907c_reg_read(chip->i2c_rtc, MAX8907C_REG_RTC_IRQ);
305 /* mask all interrupts */
306 max8907c_reg_write(chip->i2c_rtc, MAX8907C_REG_ALARM0_CNTL, 0);
307 max8907c_reg_write(chip->i2c_rtc, MAX8907C_REG_ALARM1_CNTL, 0);
308 max8907c_reg_write(chip->i2c_power, MAX8907C_REG_CHG_IRQ1_MASK, 0xff);
309 max8907c_reg_write(chip->i2c_power, MAX8907C_REG_CHG_IRQ2_MASK, 0xff);
310 max8907c_reg_write(chip->i2c_power, MAX8907C_REG_ON_OFF_IRQ1_MASK, 0xff);
311 max8907c_reg_write(chip->i2c_power, MAX8907C_REG_ON_OFF_IRQ2_MASK, 0xff);
312 max8907c_reg_write(chip->i2c_rtc, MAX8907C_REG_RTC_IRQ_MASK, 0xff);
313
314 chip->cache_chg[0] = chip->cache_chg[1] =
315 chip->cache_on[0] = chip->cache_on[1] =
316 chip->cache_rtc = 0xFF;
317
318 mutex_init(&chip->irq_lock);
319 chip->core_irq = irq;
320 chip->irq_base = irq_base;
321 desc = irq_to_desc(chip->core_irq);
322
323 /* register with genirq */
324 for (i = 0; i < ARRAY_SIZE(max8907c_irqs); i++) {
325 __irq = i + chip->irq_base;
326 irq_set_chip_data(__irq, chip);
327 irq_set_chip_and_handler(__irq, &max8907c_irq_chip,
328 handle_edge_irq);
329 irq_set_nested_thread(__irq, 1);
330#ifdef CONFIG_ARM
331 /* ARM requires an extra step to clear IRQ_NOREQUEST, which it
332 * sets on behalf of every irq_chip.
333 */
334 set_irq_flags(__irq, IRQF_VALID);
335#else
336 irq_set_noprobe(__irq);
337#endif
338 }
339
340 ret = request_threaded_irq(irq, NULL, max8907c_irq, flags,
341 "max8907c", chip);
342 if (ret) {
343 dev_err(chip->dev, "Failed to request core IRQ: %d\n", ret);
344 chip->core_irq = 0;
345 }
346
347 device_init_wakeup(chip->dev, 1);
348
349 return ret;
350}
351
352int max8907c_suspend(struct i2c_client *i2c, pm_message_t state)
353{
354 struct max8907c *chip = i2c_get_clientdata(i2c);
355
356 struct max8907c_irq_data *irq_data;
357 unsigned char irq_chg[2], irq_on[2];
358 unsigned char irq_rtc;
359 int i;
360
361 irq_chg[0] = irq_chg[1] = irq_on[0] = irq_on[1] = irq_rtc = 0xFF;
362
363 for (i = 0; i < ARRAY_SIZE(max8907c_irqs); i++) {
364 irq_data = &max8907c_irqs[i];
365 /* 1 -- disable, 0 -- enable */
366 switch (irq_data->mask_reg) {
367 case MAX8907C_REG_CHG_IRQ1_MASK:
368 irq_chg[0] &= ~irq_data->wake;
369 break;
370 case MAX8907C_REG_CHG_IRQ2_MASK:
371 irq_chg[1] &= ~irq_data->wake;
372 break;
373 case MAX8907C_REG_ON_OFF_IRQ1_MASK:
374 irq_on[0] &= ~irq_data->wake;
375 break;
376 case MAX8907C_REG_ON_OFF_IRQ2_MASK:
377 irq_on[1] &= ~irq_data->wake;
378 break;
379 case MAX8907C_REG_RTC_IRQ_MASK:
380 irq_rtc &= ~irq_data->wake;
381 break;
382 default:
383 dev_err(chip->dev, "wrong IRQ\n");
384 break;
385 }
386 }
387
388 max8907c_reg_write(chip->i2c_power, MAX8907C_REG_CHG_IRQ1_MASK, irq_chg[0]);
389 max8907c_reg_write(chip->i2c_power, MAX8907C_REG_CHG_IRQ2_MASK, irq_chg[1]);
390 max8907c_reg_write(chip->i2c_power, MAX8907C_REG_ON_OFF_IRQ1_MASK, irq_on[0]);
391 max8907c_reg_write(chip->i2c_power, MAX8907C_REG_ON_OFF_IRQ2_MASK, irq_on[1]);
392 max8907c_reg_write(chip->i2c_rtc, MAX8907C_REG_RTC_IRQ_MASK, irq_rtc);
393
394 if (device_may_wakeup(chip->dev))
395 enable_irq_wake(chip->core_irq);
396 else
397 disable_irq(chip->core_irq);
398
399 return 0;
400}
401
402int max8907c_resume(struct i2c_client *i2c)
403{
404 struct max8907c *chip = i2c_get_clientdata(i2c);
405
406 if (device_may_wakeup(chip->dev))
407 disable_irq_wake(chip->core_irq);
408 else
409 enable_irq(chip->core_irq);
410
411 max8907c_reg_write(chip->i2c_power, MAX8907C_REG_CHG_IRQ1_MASK, chip->cache_chg[0]);
412 max8907c_reg_write(chip->i2c_power, MAX8907C_REG_CHG_IRQ2_MASK, chip->cache_chg[1]);
413 max8907c_reg_write(chip->i2c_power, MAX8907C_REG_ON_OFF_IRQ1_MASK, chip->cache_on[0]);
414 max8907c_reg_write(chip->i2c_power, MAX8907C_REG_ON_OFF_IRQ2_MASK, chip->cache_on[1]);
415 max8907c_reg_write(chip->i2c_rtc, MAX8907C_REG_RTC_IRQ_MASK, chip->cache_rtc);
416
417 return 0;
418}
419
420void max8907c_irq_free(struct max8907c *chip)
421{
422 if (chip->core_irq)
423 free_irq(chip->core_irq, chip);
424}
425