blob: fb807ab8a2c7efb40d0ab667610f9ee28ed58573 [file] [log] [blame]
Rabin Vincent62579262010-05-19 11:39:02 +02001/*
2 * Copyright (C) ST-Ericsson SA 2010
3 *
4 * License Terms: GNU General Public License v2
5 * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
6 * Author: Rabin Vincent <rabin.vincent@stericsson.com>
Mattias Wallinadceed62011-03-02 11:51:11 +01007 * Author: Mattias Wallin <mattias.wallin@stericsson.com>
Rabin Vincent62579262010-05-19 11:39:02 +02008 */
9
10#include <linux/kernel.h>
11#include <linux/slab.h>
12#include <linux/init.h>
13#include <linux/irq.h>
14#include <linux/delay.h>
15#include <linux/interrupt.h>
16#include <linux/module.h>
17#include <linux/platform_device.h>
18#include <linux/mfd/core.h>
Mattias Wallin47c16972010-09-10 17:47:56 +020019#include <linux/mfd/abx500.h>
Linus Walleijee66e652011-12-02 14:16:33 +010020#include <linux/mfd/abx500/ab8500.h>
Lee Jonesd28f1db2012-05-19 17:21:37 +020021#include <linux/mfd/dbx500-prcmu.h>
Sundar R Iyer549931f2010-07-13 11:51:28 +053022#include <linux/regulator/ab8500.h>
Rabin Vincent62579262010-05-19 11:39:02 +020023
24/*
25 * Interrupt register offsets
26 * Bank : 0x0E
27 */
Mattias Wallin47c16972010-09-10 17:47:56 +020028#define AB8500_IT_SOURCE1_REG 0x00
29#define AB8500_IT_SOURCE2_REG 0x01
30#define AB8500_IT_SOURCE3_REG 0x02
31#define AB8500_IT_SOURCE4_REG 0x03
32#define AB8500_IT_SOURCE5_REG 0x04
33#define AB8500_IT_SOURCE6_REG 0x05
34#define AB8500_IT_SOURCE7_REG 0x06
35#define AB8500_IT_SOURCE8_REG 0x07
Linus Walleijd6255522012-02-20 21:42:24 +010036#define AB9540_IT_SOURCE13_REG 0x0C
Mattias Wallin47c16972010-09-10 17:47:56 +020037#define AB8500_IT_SOURCE19_REG 0x12
38#define AB8500_IT_SOURCE20_REG 0x13
39#define AB8500_IT_SOURCE21_REG 0x14
40#define AB8500_IT_SOURCE22_REG 0x15
41#define AB8500_IT_SOURCE23_REG 0x16
42#define AB8500_IT_SOURCE24_REG 0x17
Rabin Vincent62579262010-05-19 11:39:02 +020043
44/*
45 * latch registers
46 */
Mattias Wallin47c16972010-09-10 17:47:56 +020047#define AB8500_IT_LATCH1_REG 0x20
48#define AB8500_IT_LATCH2_REG 0x21
49#define AB8500_IT_LATCH3_REG 0x22
50#define AB8500_IT_LATCH4_REG 0x23
51#define AB8500_IT_LATCH5_REG 0x24
52#define AB8500_IT_LATCH6_REG 0x25
53#define AB8500_IT_LATCH7_REG 0x26
54#define AB8500_IT_LATCH8_REG 0x27
55#define AB8500_IT_LATCH9_REG 0x28
56#define AB8500_IT_LATCH10_REG 0x29
Mattias Wallin92d50a42010-12-07 11:20:47 +010057#define AB8500_IT_LATCH12_REG 0x2B
Linus Walleijd6255522012-02-20 21:42:24 +010058#define AB9540_IT_LATCH13_REG 0x2C
Mattias Wallin47c16972010-09-10 17:47:56 +020059#define AB8500_IT_LATCH19_REG 0x32
60#define AB8500_IT_LATCH20_REG 0x33
61#define AB8500_IT_LATCH21_REG 0x34
62#define AB8500_IT_LATCH22_REG 0x35
63#define AB8500_IT_LATCH23_REG 0x36
64#define AB8500_IT_LATCH24_REG 0x37
Rabin Vincent62579262010-05-19 11:39:02 +020065
66/*
67 * mask registers
68 */
69
Mattias Wallin47c16972010-09-10 17:47:56 +020070#define AB8500_IT_MASK1_REG 0x40
71#define AB8500_IT_MASK2_REG 0x41
72#define AB8500_IT_MASK3_REG 0x42
73#define AB8500_IT_MASK4_REG 0x43
74#define AB8500_IT_MASK5_REG 0x44
75#define AB8500_IT_MASK6_REG 0x45
76#define AB8500_IT_MASK7_REG 0x46
77#define AB8500_IT_MASK8_REG 0x47
78#define AB8500_IT_MASK9_REG 0x48
79#define AB8500_IT_MASK10_REG 0x49
80#define AB8500_IT_MASK11_REG 0x4A
81#define AB8500_IT_MASK12_REG 0x4B
82#define AB8500_IT_MASK13_REG 0x4C
83#define AB8500_IT_MASK14_REG 0x4D
84#define AB8500_IT_MASK15_REG 0x4E
85#define AB8500_IT_MASK16_REG 0x4F
86#define AB8500_IT_MASK17_REG 0x50
87#define AB8500_IT_MASK18_REG 0x51
88#define AB8500_IT_MASK19_REG 0x52
89#define AB8500_IT_MASK20_REG 0x53
90#define AB8500_IT_MASK21_REG 0x54
91#define AB8500_IT_MASK22_REG 0x55
92#define AB8500_IT_MASK23_REG 0x56
93#define AB8500_IT_MASK24_REG 0x57
Rabin Vincent62579262010-05-19 11:39:02 +020094
Michel JAOUEN7ccfe9b2012-05-07 15:02:03 +020095/*
96 * latch hierarchy registers
97 */
98#define AB8500_IT_LATCHHIER1_REG 0x60
99#define AB8500_IT_LATCHHIER2_REG 0x61
100#define AB8500_IT_LATCHHIER3_REG 0x62
101
102#define AB8500_IT_LATCHHIER_NUM 3
103
Mattias Wallin47c16972010-09-10 17:47:56 +0200104#define AB8500_REV_REG 0x80
Linus Walleij0f6208372012-02-20 21:42:10 +0100105#define AB8500_IC_NAME_REG 0x82
Mattias Walline5c238c2011-03-02 11:52:36 +0100106#define AB8500_SWITCH_OFF_STATUS 0x00
Rabin Vincent62579262010-05-19 11:39:02 +0200107
Andrew Lynnb4a31032011-10-11 10:49:47 +0200108#define AB8500_TURN_ON_STATUS 0x00
109
Rickard Andersson6ef94182012-04-17 09:30:57 +0200110static bool no_bm; /* No battery management */
111module_param(no_bm, bool, S_IRUGO);
112
Linus Walleijd6255522012-02-20 21:42:24 +0100113#define AB9540_MODEM_CTRL2_REG 0x23
114#define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT BIT(2)
115
Rabin Vincent62579262010-05-19 11:39:02 +0200116/*
117 * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt
Linus Walleij2ced4452012-02-20 21:42:17 +0100118 * numbers are indexed into this array with (num / 8). The interupts are
119 * defined in linux/mfd/ab8500.h
Rabin Vincent62579262010-05-19 11:39:02 +0200120 *
121 * This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at
122 * offset 0.
123 */
Linus Walleij2ced4452012-02-20 21:42:17 +0100124/* AB8500 support */
Rabin Vincent62579262010-05-19 11:39:02 +0200125static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = {
Mattias Wallin92d50a42010-12-07 11:20:47 +0100126 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21,
Rabin Vincent62579262010-05-19 11:39:02 +0200127};
128
Linus Walleijd6255522012-02-20 21:42:24 +0100129/* AB9540 support */
130static const int ab9540_irq_regoffset[AB9540_NUM_IRQ_REGS] = {
131 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24,
132};
133
Linus Walleij0f6208372012-02-20 21:42:10 +0100134static const char ab8500_version_str[][7] = {
135 [AB8500_VERSION_AB8500] = "AB8500",
136 [AB8500_VERSION_AB8505] = "AB8505",
137 [AB8500_VERSION_AB9540] = "AB9540",
138 [AB8500_VERSION_AB8540] = "AB8540",
139};
140
Lee Jonesd28f1db2012-05-19 17:21:37 +0200141static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data)
142{
143 int ret;
144
145 ret = prcmu_abb_write((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1);
146 if (ret < 0)
147 dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
148 return ret;
149}
150
151static int ab8500_i2c_write_masked(struct ab8500 *ab8500, u16 addr, u8 mask,
152 u8 data)
153{
154 int ret;
155
156 ret = prcmu_abb_write_masked((u8)(addr >> 8), (u8)(addr & 0xFF), &data,
157 &mask, 1);
158 if (ret < 0)
159 dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
160 return ret;
161}
162
163static int ab8500_i2c_read(struct ab8500 *ab8500, u16 addr)
164{
165 int ret;
166 u8 data;
167
168 ret = prcmu_abb_read((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1);
169 if (ret < 0) {
170 dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
171 return ret;
172 }
173 return (int)data;
174}
175
Mattias Wallin47c16972010-09-10 17:47:56 +0200176static int ab8500_get_chip_id(struct device *dev)
177{
Mattias Wallin6bce7bf2010-12-02 15:08:32 +0100178 struct ab8500 *ab8500;
179
180 if (!dev)
181 return -EINVAL;
182 ab8500 = dev_get_drvdata(dev->parent);
183 return ab8500 ? (int)ab8500->chip_id : -EINVAL;
Mattias Wallin47c16972010-09-10 17:47:56 +0200184}
185
186static int set_register_interruptible(struct ab8500 *ab8500, u8 bank,
187 u8 reg, u8 data)
Rabin Vincent62579262010-05-19 11:39:02 +0200188{
189 int ret;
Mattias Wallin47c16972010-09-10 17:47:56 +0200190 /*
191 * Put the u8 bank and u8 register together into a an u16.
192 * The bank on higher 8 bits and register in lower 8 bits.
193 * */
194 u16 addr = ((u16)bank) << 8 | reg;
Rabin Vincent62579262010-05-19 11:39:02 +0200195
196 dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data);
197
Rabin Vincent392cbd12012-03-08 14:01:46 +0100198 mutex_lock(&ab8500->lock);
Mattias Wallin47c16972010-09-10 17:47:56 +0200199
200 ret = ab8500->write(ab8500, addr, data);
201 if (ret < 0)
202 dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
203 addr, ret);
204 mutex_unlock(&ab8500->lock);
205
206 return ret;
207}
208
209static int ab8500_set_register(struct device *dev, u8 bank,
210 u8 reg, u8 value)
211{
Jonas Aaberg112a80d2012-04-17 09:30:33 +0200212 int ret;
Mattias Wallin47c16972010-09-10 17:47:56 +0200213 struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
214
Jonas Aaberg112a80d2012-04-17 09:30:33 +0200215 atomic_inc(&ab8500->transfer_ongoing);
216 ret = set_register_interruptible(ab8500, bank, reg, value);
217 atomic_dec(&ab8500->transfer_ongoing);
218 return ret;
Mattias Wallin47c16972010-09-10 17:47:56 +0200219}
220
221static int get_register_interruptible(struct ab8500 *ab8500, u8 bank,
222 u8 reg, u8 *value)
223{
224 int ret;
225 /* put the u8 bank and u8 reg together into a an u16.
226 * bank on higher 8 bits and reg in lower */
227 u16 addr = ((u16)bank) << 8 | reg;
228
Rabin Vincent392cbd12012-03-08 14:01:46 +0100229 mutex_lock(&ab8500->lock);
Mattias Wallin47c16972010-09-10 17:47:56 +0200230
231 ret = ab8500->read(ab8500, addr);
232 if (ret < 0)
233 dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
234 addr, ret);
235 else
236 *value = ret;
237
238 mutex_unlock(&ab8500->lock);
239 dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret);
240
241 return ret;
242}
243
244static int ab8500_get_register(struct device *dev, u8 bank,
245 u8 reg, u8 *value)
246{
Jonas Aaberg112a80d2012-04-17 09:30:33 +0200247 int ret;
Mattias Wallin47c16972010-09-10 17:47:56 +0200248 struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
249
Jonas Aaberg112a80d2012-04-17 09:30:33 +0200250 atomic_inc(&ab8500->transfer_ongoing);
251 ret = get_register_interruptible(ab8500, bank, reg, value);
252 atomic_dec(&ab8500->transfer_ongoing);
253 return ret;
Mattias Wallin47c16972010-09-10 17:47:56 +0200254}
255
256static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank,
257 u8 reg, u8 bitmask, u8 bitvalues)
258{
259 int ret;
Mattias Wallin47c16972010-09-10 17:47:56 +0200260 /* put the u8 bank and u8 reg together into a an u16.
261 * bank on higher 8 bits and reg in lower */
262 u16 addr = ((u16)bank) << 8 | reg;
263
Rabin Vincent392cbd12012-03-08 14:01:46 +0100264 mutex_lock(&ab8500->lock);
Mattias Wallin47c16972010-09-10 17:47:56 +0200265
Mattias Nilssonbc628fd2012-03-08 14:02:20 +0100266 if (ab8500->write_masked == NULL) {
267 u8 data;
268
269 ret = ab8500->read(ab8500, addr);
270 if (ret < 0) {
271 dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
272 addr, ret);
273 goto out;
274 }
275
276 data = (u8)ret;
277 data = (~bitmask & data) | (bitmask & bitvalues);
278
279 ret = ab8500->write(ab8500, addr, data);
280 if (ret < 0)
281 dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
282 addr, ret);
283
284 dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr,
285 data);
Mattias Wallin47c16972010-09-10 17:47:56 +0200286 goto out;
287 }
Mattias Nilssonbc628fd2012-03-08 14:02:20 +0100288 ret = ab8500->write_masked(ab8500, addr, bitmask, bitvalues);
Rabin Vincent62579262010-05-19 11:39:02 +0200289 if (ret < 0)
Mattias Nilssonbc628fd2012-03-08 14:02:20 +0100290 dev_err(ab8500->dev, "failed to modify reg %#x: %d\n", addr,
291 ret);
Rabin Vincent62579262010-05-19 11:39:02 +0200292out:
293 mutex_unlock(&ab8500->lock);
294 return ret;
295}
Mattias Wallin47c16972010-09-10 17:47:56 +0200296
297static int ab8500_mask_and_set_register(struct device *dev,
298 u8 bank, u8 reg, u8 bitmask, u8 bitvalues)
299{
Jonas Aaberg112a80d2012-04-17 09:30:33 +0200300 int ret;
Mattias Wallin47c16972010-09-10 17:47:56 +0200301 struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
302
Jonas Aaberg112a80d2012-04-17 09:30:33 +0200303 atomic_inc(&ab8500->transfer_ongoing);
304 ret= mask_and_set_register_interruptible(ab8500, bank, reg,
305 bitmask, bitvalues);
306 atomic_dec(&ab8500->transfer_ongoing);
307 return ret;
Mattias Wallin47c16972010-09-10 17:47:56 +0200308}
309
310static struct abx500_ops ab8500_ops = {
311 .get_chip_id = ab8500_get_chip_id,
312 .get_register = ab8500_get_register,
313 .set_register = ab8500_set_register,
314 .get_register_page = NULL,
315 .set_register_page = NULL,
316 .mask_and_set_register = ab8500_mask_and_set_register,
317 .event_registers_startup_state_get = NULL,
318 .startup_irq_enabled = NULL,
319};
Rabin Vincent62579262010-05-19 11:39:02 +0200320
Mark Brown9505a0a2010-12-11 13:16:08 +0000321static void ab8500_irq_lock(struct irq_data *data)
Rabin Vincent62579262010-05-19 11:39:02 +0200322{
Mark Brown9505a0a2010-12-11 13:16:08 +0000323 struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
Rabin Vincent62579262010-05-19 11:39:02 +0200324
325 mutex_lock(&ab8500->irq_lock);
Jonas Aaberg112a80d2012-04-17 09:30:33 +0200326 atomic_inc(&ab8500->transfer_ongoing);
Rabin Vincent62579262010-05-19 11:39:02 +0200327}
328
Mark Brown9505a0a2010-12-11 13:16:08 +0000329static void ab8500_irq_sync_unlock(struct irq_data *data)
Rabin Vincent62579262010-05-19 11:39:02 +0200330{
Mark Brown9505a0a2010-12-11 13:16:08 +0000331 struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
Rabin Vincent62579262010-05-19 11:39:02 +0200332 int i;
333
Linus Walleij2ced4452012-02-20 21:42:17 +0100334 for (i = 0; i < ab8500->mask_size; i++) {
Rabin Vincent62579262010-05-19 11:39:02 +0200335 u8 old = ab8500->oldmask[i];
336 u8 new = ab8500->mask[i];
337 int reg;
338
339 if (new == old)
340 continue;
341
Linus Walleij0f6208372012-02-20 21:42:10 +0100342 /*
343 * Interrupt register 12 doesn't exist prior to AB8500 version
344 * 2.0
345 */
346 if (ab8500->irq_reg_offset[i] == 11 &&
347 is_ab8500_1p1_or_earlier(ab8500))
Mattias Wallin92d50a42010-12-07 11:20:47 +0100348 continue;
349
Rabin Vincent62579262010-05-19 11:39:02 +0200350 ab8500->oldmask[i] = new;
351
Linus Walleij2ced4452012-02-20 21:42:17 +0100352 reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i];
Mattias Wallin47c16972010-09-10 17:47:56 +0200353 set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new);
Rabin Vincent62579262010-05-19 11:39:02 +0200354 }
Jonas Aaberg112a80d2012-04-17 09:30:33 +0200355 atomic_dec(&ab8500->transfer_ongoing);
Rabin Vincent62579262010-05-19 11:39:02 +0200356 mutex_unlock(&ab8500->irq_lock);
357}
358
Mark Brown9505a0a2010-12-11 13:16:08 +0000359static void ab8500_irq_mask(struct irq_data *data)
Rabin Vincent62579262010-05-19 11:39:02 +0200360{
Mark Brown9505a0a2010-12-11 13:16:08 +0000361 struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
362 int offset = data->irq - ab8500->irq_base;
Rabin Vincent62579262010-05-19 11:39:02 +0200363 int index = offset / 8;
364 int mask = 1 << (offset % 8);
365
366 ab8500->mask[index] |= mask;
367}
368
Mark Brown9505a0a2010-12-11 13:16:08 +0000369static void ab8500_irq_unmask(struct irq_data *data)
Rabin Vincent62579262010-05-19 11:39:02 +0200370{
Mark Brown9505a0a2010-12-11 13:16:08 +0000371 struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
372 int offset = data->irq - ab8500->irq_base;
Rabin Vincent62579262010-05-19 11:39:02 +0200373 int index = offset / 8;
374 int mask = 1 << (offset % 8);
375
376 ab8500->mask[index] &= ~mask;
377}
378
379static struct irq_chip ab8500_irq_chip = {
380 .name = "ab8500",
Mark Brown9505a0a2010-12-11 13:16:08 +0000381 .irq_bus_lock = ab8500_irq_lock,
382 .irq_bus_sync_unlock = ab8500_irq_sync_unlock,
383 .irq_mask = ab8500_irq_mask,
Virupax Sadashivpetimathe6f93062011-10-11 10:49:17 +0200384 .irq_disable = ab8500_irq_mask,
Mark Brown9505a0a2010-12-11 13:16:08 +0000385 .irq_unmask = ab8500_irq_unmask,
Rabin Vincent62579262010-05-19 11:39:02 +0200386};
387
Michel JAOUEN7ccfe9b2012-05-07 15:02:03 +0200388static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500,
389 int latch_offset, u8 latch_val)
390{
391 int int_bit = __ffs(latch_val);
392 int line, i;
393
394 do {
395 int_bit = __ffs(latch_val);
396
397 for (i = 0; i < ab8500->mask_size; i++)
398 if (ab8500->irq_reg_offset[i] == latch_offset)
399 break;
400
401 if (i >= ab8500->mask_size) {
402 dev_err(ab8500->dev, "Register offset 0x%2x not declared\n",
403 latch_offset);
404 return -ENXIO;
405 }
406
407 line = (i << 3) + int_bit;
408 latch_val &= ~(1 << int_bit);
409
410 handle_nested_irq(ab8500->irq_base + line);
411 } while (latch_val);
412
413 return 0;
414}
415
416static int ab8500_handle_hierarchical_latch(struct ab8500 *ab8500,
417 int hier_offset, u8 hier_val)
418{
419 int latch_bit, status;
420 u8 latch_offset, latch_val;
421
422 do {
423 latch_bit = __ffs(hier_val);
424 latch_offset = (hier_offset << 3) + latch_bit;
425
426 /* Fix inconsistent ITFromLatch25 bit mapping... */
427 if (unlikely(latch_offset == 17))
428 latch_offset = 24;
429
430 status = get_register_interruptible(ab8500,
431 AB8500_INTERRUPT,
432 AB8500_IT_LATCH1_REG + latch_offset,
433 &latch_val);
434 if (status < 0 || latch_val == 0)
435 goto discard;
436
437 status = ab8500_handle_hierarchical_line(ab8500,
438 latch_offset, latch_val);
439 if (status < 0)
440 return status;
441discard:
442 hier_val &= ~(1 << latch_bit);
443 } while (hier_val);
444
445 return 0;
446}
447
448static irqreturn_t ab8500_hierarchical_irq(int irq, void *dev)
449{
450 struct ab8500 *ab8500 = dev;
451 u8 i;
452
453 dev_vdbg(ab8500->dev, "interrupt\n");
454
455 /* Hierarchical interrupt version */
456 for (i = 0; i < AB8500_IT_LATCHHIER_NUM; i++) {
457 int status;
458 u8 hier_val;
459
460 status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
461 AB8500_IT_LATCHHIER1_REG + i, &hier_val);
462 if (status < 0 || hier_val == 0)
463 continue;
464
465 status = ab8500_handle_hierarchical_latch(ab8500, i, hier_val);
466 if (status < 0)
467 break;
468 }
469 return IRQ_HANDLED;
470}
471
Rabin Vincent62579262010-05-19 11:39:02 +0200472static irqreturn_t ab8500_irq(int irq, void *dev)
473{
474 struct ab8500 *ab8500 = dev;
475 int i;
476
477 dev_vdbg(ab8500->dev, "interrupt\n");
478
Jonas Aaberg112a80d2012-04-17 09:30:33 +0200479 atomic_inc(&ab8500->transfer_ongoing);
480
Linus Walleij2ced4452012-02-20 21:42:17 +0100481 for (i = 0; i < ab8500->mask_size; i++) {
482 int regoffset = ab8500->irq_reg_offset[i];
Rabin Vincent62579262010-05-19 11:39:02 +0200483 int status;
Mattias Wallin47c16972010-09-10 17:47:56 +0200484 u8 value;
Rabin Vincent62579262010-05-19 11:39:02 +0200485
Linus Walleij0f6208372012-02-20 21:42:10 +0100486 /*
487 * Interrupt register 12 doesn't exist prior to AB8500 version
488 * 2.0
489 */
490 if (regoffset == 11 && is_ab8500_1p1_or_earlier(ab8500))
Mattias Wallin92d50a42010-12-07 11:20:47 +0100491 continue;
492
Mattias Wallin47c16972010-09-10 17:47:56 +0200493 status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
494 AB8500_IT_LATCH1_REG + regoffset, &value);
495 if (status < 0 || value == 0)
Rabin Vincent62579262010-05-19 11:39:02 +0200496 continue;
497
498 do {
Mattias Wallin88aec4f2010-12-02 15:06:49 +0100499 int bit = __ffs(value);
Rabin Vincent62579262010-05-19 11:39:02 +0200500 int line = i * 8 + bit;
501
502 handle_nested_irq(ab8500->irq_base + line);
Mattias Wallin47c16972010-09-10 17:47:56 +0200503 value &= ~(1 << bit);
Jonas Aaberg112a80d2012-04-17 09:30:33 +0200504
Mattias Wallin47c16972010-09-10 17:47:56 +0200505 } while (value);
Rabin Vincent62579262010-05-19 11:39:02 +0200506 }
Jonas Aaberg112a80d2012-04-17 09:30:33 +0200507 atomic_dec(&ab8500->transfer_ongoing);
Rabin Vincent62579262010-05-19 11:39:02 +0200508 return IRQ_HANDLED;
509}
510
511static int ab8500_irq_init(struct ab8500 *ab8500)
512{
513 int base = ab8500->irq_base;
514 int irq;
Linus Walleij2ced4452012-02-20 21:42:17 +0100515 int num_irqs;
Rabin Vincent62579262010-05-19 11:39:02 +0200516
Linus Walleijd6255522012-02-20 21:42:24 +0100517 if (is_ab9540(ab8500))
518 num_irqs = AB9540_NR_IRQS;
Bengt Jonssona9823622012-03-08 14:01:57 +0100519 else if (is_ab8505(ab8500))
520 num_irqs = AB8505_NR_IRQS;
Linus Walleijd6255522012-02-20 21:42:24 +0100521 else
522 num_irqs = AB8500_NR_IRQS;
Linus Walleij2ced4452012-02-20 21:42:17 +0100523
524 for (irq = base; irq < base + num_irqs; irq++) {
Thomas Gleixnerd5bb1222011-03-25 11:12:32 +0000525 irq_set_chip_data(irq, ab8500);
526 irq_set_chip_and_handler(irq, &ab8500_irq_chip,
Rabin Vincent62579262010-05-19 11:39:02 +0200527 handle_simple_irq);
Thomas Gleixnerd5bb1222011-03-25 11:12:32 +0000528 irq_set_nested_thread(irq, 1);
Rabin Vincent62579262010-05-19 11:39:02 +0200529#ifdef CONFIG_ARM
530 set_irq_flags(irq, IRQF_VALID);
531#else
Thomas Gleixnerd5bb1222011-03-25 11:12:32 +0000532 irq_set_noprobe(irq);
Rabin Vincent62579262010-05-19 11:39:02 +0200533#endif
534 }
535
536 return 0;
537}
538
539static void ab8500_irq_remove(struct ab8500 *ab8500)
540{
541 int base = ab8500->irq_base;
542 int irq;
Linus Walleij2ced4452012-02-20 21:42:17 +0100543 int num_irqs;
Rabin Vincent62579262010-05-19 11:39:02 +0200544
Linus Walleijd6255522012-02-20 21:42:24 +0100545 if (is_ab9540(ab8500))
546 num_irqs = AB9540_NR_IRQS;
Bengt Jonssona9823622012-03-08 14:01:57 +0100547 else if (is_ab8505(ab8500))
548 num_irqs = AB8505_NR_IRQS;
Linus Walleijd6255522012-02-20 21:42:24 +0100549 else
550 num_irqs = AB8500_NR_IRQS;
Linus Walleij2ced4452012-02-20 21:42:17 +0100551
552 for (irq = base; irq < base + num_irqs; irq++) {
Rabin Vincent62579262010-05-19 11:39:02 +0200553#ifdef CONFIG_ARM
554 set_irq_flags(irq, 0);
555#endif
Thomas Gleixnerd5bb1222011-03-25 11:12:32 +0000556 irq_set_chip_and_handler(irq, NULL, NULL);
557 irq_set_chip_data(irq, NULL);
Rabin Vincent62579262010-05-19 11:39:02 +0200558 }
559}
560
Jonas Aaberg112a80d2012-04-17 09:30:33 +0200561int ab8500_suspend(struct ab8500 *ab8500)
562{
563 if (atomic_read(&ab8500->transfer_ongoing))
564 return -EINVAL;
565 else
566 return 0;
567}
568
Linus Walleijd6255522012-02-20 21:42:24 +0100569/* AB8500 GPIO Resources */
Robert Rosengren5cef8df2011-06-09 23:57:33 +0200570static struct resource __devinitdata ab8500_gpio_resources[] = {
Bibek Basu0cb3fcd2011-02-09 11:02:35 +0530571 {
572 .name = "GPIO_INT6",
573 .start = AB8500_INT_GPIO6R,
574 .end = AB8500_INT_GPIO41F,
575 .flags = IORESOURCE_IRQ,
576 }
577};
578
Linus Walleijd6255522012-02-20 21:42:24 +0100579/* AB9540 GPIO Resources */
580static struct resource __devinitdata ab9540_gpio_resources[] = {
581 {
582 .name = "GPIO_INT6",
583 .start = AB8500_INT_GPIO6R,
584 .end = AB8500_INT_GPIO41F,
585 .flags = IORESOURCE_IRQ,
586 },
587 {
588 .name = "GPIO_INT14",
589 .start = AB9540_INT_GPIO50R,
590 .end = AB9540_INT_GPIO54R,
591 .flags = IORESOURCE_IRQ,
592 },
593 {
594 .name = "GPIO_INT15",
595 .start = AB9540_INT_GPIO50F,
596 .end = AB9540_INT_GPIO54F,
597 .flags = IORESOURCE_IRQ,
598 }
599};
600
Robert Rosengren5cef8df2011-06-09 23:57:33 +0200601static struct resource __devinitdata ab8500_gpadc_resources[] = {
Rabin Vincent62579262010-05-19 11:39:02 +0200602 {
603 .name = "HW_CONV_END",
604 .start = AB8500_INT_GP_HW_ADC_CONV_END,
605 .end = AB8500_INT_GP_HW_ADC_CONV_END,
606 .flags = IORESOURCE_IRQ,
607 },
608 {
609 .name = "SW_CONV_END",
610 .start = AB8500_INT_GP_SW_ADC_CONV_END,
611 .end = AB8500_INT_GP_SW_ADC_CONV_END,
612 .flags = IORESOURCE_IRQ,
613 },
614};
615
Robert Rosengren5cef8df2011-06-09 23:57:33 +0200616static struct resource __devinitdata ab8500_rtc_resources[] = {
Rabin Vincent62579262010-05-19 11:39:02 +0200617 {
618 .name = "60S",
619 .start = AB8500_INT_RTC_60S,
620 .end = AB8500_INT_RTC_60S,
621 .flags = IORESOURCE_IRQ,
622 },
623 {
624 .name = "ALARM",
625 .start = AB8500_INT_RTC_ALARM,
626 .end = AB8500_INT_RTC_ALARM,
627 .flags = IORESOURCE_IRQ,
628 },
629};
630
Robert Rosengren5cef8df2011-06-09 23:57:33 +0200631static struct resource __devinitdata ab8500_poweronkey_db_resources[] = {
Sundar R Iyer77686512010-09-05 12:18:47 -0700632 {
633 .name = "ONKEY_DBF",
634 .start = AB8500_INT_PON_KEY1DB_F,
635 .end = AB8500_INT_PON_KEY1DB_F,
636 .flags = IORESOURCE_IRQ,
637 },
638 {
639 .name = "ONKEY_DBR",
640 .start = AB8500_INT_PON_KEY1DB_R,
641 .end = AB8500_INT_PON_KEY1DB_R,
642 .flags = IORESOURCE_IRQ,
643 },
644};
645
Linus Walleij6af75ec2011-06-09 23:57:45 +0200646static struct resource __devinitdata ab8500_av_acc_detect_resources[] = {
Mattias Walline098aded72010-12-02 15:40:31 +0100647 {
Linus Walleij6af75ec2011-06-09 23:57:45 +0200648 .name = "ACC_DETECT_1DB_F",
649 .start = AB8500_INT_ACC_DETECT_1DB_F,
650 .end = AB8500_INT_ACC_DETECT_1DB_F,
651 .flags = IORESOURCE_IRQ,
Mattias Walline098aded72010-12-02 15:40:31 +0100652 },
653 {
Linus Walleij6af75ec2011-06-09 23:57:45 +0200654 .name = "ACC_DETECT_1DB_R",
655 .start = AB8500_INT_ACC_DETECT_1DB_R,
656 .end = AB8500_INT_ACC_DETECT_1DB_R,
657 .flags = IORESOURCE_IRQ,
Mattias Walline098aded72010-12-02 15:40:31 +0100658 },
659 {
Linus Walleij6af75ec2011-06-09 23:57:45 +0200660 .name = "ACC_DETECT_21DB_F",
661 .start = AB8500_INT_ACC_DETECT_21DB_F,
662 .end = AB8500_INT_ACC_DETECT_21DB_F,
663 .flags = IORESOURCE_IRQ,
664 },
665 {
666 .name = "ACC_DETECT_21DB_R",
667 .start = AB8500_INT_ACC_DETECT_21DB_R,
668 .end = AB8500_INT_ACC_DETECT_21DB_R,
669 .flags = IORESOURCE_IRQ,
670 },
671 {
672 .name = "ACC_DETECT_22DB_F",
673 .start = AB8500_INT_ACC_DETECT_22DB_F,
674 .end = AB8500_INT_ACC_DETECT_22DB_F,
675 .flags = IORESOURCE_IRQ,
676 },
677 {
678 .name = "ACC_DETECT_22DB_R",
679 .start = AB8500_INT_ACC_DETECT_22DB_R,
680 .end = AB8500_INT_ACC_DETECT_22DB_R,
681 .flags = IORESOURCE_IRQ,
682 },
683};
684
685static struct resource __devinitdata ab8500_charger_resources[] = {
686 {
Mattias Walline098aded72010-12-02 15:40:31 +0100687 .name = "MAIN_CH_UNPLUG_DET",
688 .start = AB8500_INT_MAIN_CH_UNPLUG_DET,
689 .end = AB8500_INT_MAIN_CH_UNPLUG_DET,
690 .flags = IORESOURCE_IRQ,
691 },
692 {
693 .name = "MAIN_CHARGE_PLUG_DET",
694 .start = AB8500_INT_MAIN_CH_PLUG_DET,
695 .end = AB8500_INT_MAIN_CH_PLUG_DET,
696 .flags = IORESOURCE_IRQ,
697 },
698 {
Mattias Walline098aded72010-12-02 15:40:31 +0100699 .name = "VBUS_DET_R",
700 .start = AB8500_INT_VBUS_DET_R,
701 .end = AB8500_INT_VBUS_DET_R,
702 .flags = IORESOURCE_IRQ,
703 },
704 {
Linus Walleij6af75ec2011-06-09 23:57:45 +0200705 .name = "VBUS_DET_F",
706 .start = AB8500_INT_VBUS_DET_F,
707 .end = AB8500_INT_VBUS_DET_F,
Mattias Walline098aded72010-12-02 15:40:31 +0100708 .flags = IORESOURCE_IRQ,
709 },
710 {
Linus Walleij6af75ec2011-06-09 23:57:45 +0200711 .name = "USB_LINK_STATUS",
712 .start = AB8500_INT_USB_LINK_STATUS,
713 .end = AB8500_INT_USB_LINK_STATUS,
714 .flags = IORESOURCE_IRQ,
715 },
716 {
Mattias Walline098aded72010-12-02 15:40:31 +0100717 .name = "VBUS_OVV",
718 .start = AB8500_INT_VBUS_OVV,
719 .end = AB8500_INT_VBUS_OVV,
720 .flags = IORESOURCE_IRQ,
721 },
722 {
Linus Walleij6af75ec2011-06-09 23:57:45 +0200723 .name = "USB_CH_TH_PROT_R",
724 .start = AB8500_INT_USB_CH_TH_PROT_R,
725 .end = AB8500_INT_USB_CH_TH_PROT_R,
Mattias Walline098aded72010-12-02 15:40:31 +0100726 .flags = IORESOURCE_IRQ,
727 },
728 {
Linus Walleij6af75ec2011-06-09 23:57:45 +0200729 .name = "USB_CH_TH_PROT_F",
730 .start = AB8500_INT_USB_CH_TH_PROT_F,
731 .end = AB8500_INT_USB_CH_TH_PROT_F,
Mattias Walline098aded72010-12-02 15:40:31 +0100732 .flags = IORESOURCE_IRQ,
733 },
734 {
Linus Walleij6af75ec2011-06-09 23:57:45 +0200735 .name = "MAIN_EXT_CH_NOT_OK",
736 .start = AB8500_INT_MAIN_EXT_CH_NOT_OK,
737 .end = AB8500_INT_MAIN_EXT_CH_NOT_OK,
738 .flags = IORESOURCE_IRQ,
739 },
740 {
741 .name = "MAIN_CH_TH_PROT_R",
742 .start = AB8500_INT_MAIN_CH_TH_PROT_R,
743 .end = AB8500_INT_MAIN_CH_TH_PROT_R,
744 .flags = IORESOURCE_IRQ,
745 },
746 {
747 .name = "MAIN_CH_TH_PROT_F",
748 .start = AB8500_INT_MAIN_CH_TH_PROT_F,
749 .end = AB8500_INT_MAIN_CH_TH_PROT_F,
750 .flags = IORESOURCE_IRQ,
751 },
752 {
753 .name = "USB_CHARGER_NOT_OKR",
Bengt Jonssona9823622012-03-08 14:01:57 +0100754 .start = AB8500_INT_USB_CHARGER_NOT_OKR,
755 .end = AB8500_INT_USB_CHARGER_NOT_OKR,
Linus Walleij6af75ec2011-06-09 23:57:45 +0200756 .flags = IORESOURCE_IRQ,
757 },
758 {
759 .name = "CH_WD_EXP",
760 .start = AB8500_INT_CH_WD_EXP,
761 .end = AB8500_INT_CH_WD_EXP,
762 .flags = IORESOURCE_IRQ,
763 },
764};
765
766static struct resource __devinitdata ab8500_btemp_resources[] = {
767 {
768 .name = "BAT_CTRL_INDB",
769 .start = AB8500_INT_BAT_CTRL_INDB,
770 .end = AB8500_INT_BAT_CTRL_INDB,
Mattias Walline098aded72010-12-02 15:40:31 +0100771 .flags = IORESOURCE_IRQ,
772 },
773 {
774 .name = "BTEMP_LOW",
775 .start = AB8500_INT_BTEMP_LOW,
776 .end = AB8500_INT_BTEMP_LOW,
777 .flags = IORESOURCE_IRQ,
778 },
779 {
780 .name = "BTEMP_HIGH",
781 .start = AB8500_INT_BTEMP_HIGH,
782 .end = AB8500_INT_BTEMP_HIGH,
783 .flags = IORESOURCE_IRQ,
784 },
785 {
Linus Walleij6af75ec2011-06-09 23:57:45 +0200786 .name = "BTEMP_LOW_MEDIUM",
787 .start = AB8500_INT_BTEMP_LOW_MEDIUM,
788 .end = AB8500_INT_BTEMP_LOW_MEDIUM,
Mattias Walline098aded72010-12-02 15:40:31 +0100789 .flags = IORESOURCE_IRQ,
790 },
791 {
Linus Walleij6af75ec2011-06-09 23:57:45 +0200792 .name = "BTEMP_MEDIUM_HIGH",
793 .start = AB8500_INT_BTEMP_MEDIUM_HIGH,
794 .end = AB8500_INT_BTEMP_MEDIUM_HIGH,
Mattias Walline098aded72010-12-02 15:40:31 +0100795 .flags = IORESOURCE_IRQ,
796 },
797};
798
Linus Walleij6af75ec2011-06-09 23:57:45 +0200799static struct resource __devinitdata ab8500_fg_resources[] = {
800 {
801 .name = "NCONV_ACCU",
802 .start = AB8500_INT_CCN_CONV_ACC,
803 .end = AB8500_INT_CCN_CONV_ACC,
804 .flags = IORESOURCE_IRQ,
805 },
806 {
807 .name = "BATT_OVV",
808 .start = AB8500_INT_BATT_OVV,
809 .end = AB8500_INT_BATT_OVV,
810 .flags = IORESOURCE_IRQ,
811 },
812 {
813 .name = "LOW_BAT_F",
814 .start = AB8500_INT_LOW_BAT_F,
815 .end = AB8500_INT_LOW_BAT_F,
816 .flags = IORESOURCE_IRQ,
817 },
818 {
819 .name = "LOW_BAT_R",
820 .start = AB8500_INT_LOW_BAT_R,
821 .end = AB8500_INT_LOW_BAT_R,
822 .flags = IORESOURCE_IRQ,
823 },
824 {
825 .name = "CC_INT_CALIB",
826 .start = AB8500_INT_CC_INT_CALIB,
827 .end = AB8500_INT_CC_INT_CALIB,
828 .flags = IORESOURCE_IRQ,
829 },
Bengt Jonssona9823622012-03-08 14:01:57 +0100830 {
831 .name = "CCEOC",
832 .start = AB8500_INT_CCEOC,
833 .end = AB8500_INT_CCEOC,
834 .flags = IORESOURCE_IRQ,
835 },
Linus Walleij6af75ec2011-06-09 23:57:45 +0200836};
837
838static struct resource __devinitdata ab8500_chargalg_resources[] = {};
839
Axel Lindf720642011-11-10 09:56:18 +0800840#ifdef CONFIG_DEBUG_FS
Robert Rosengren5cef8df2011-06-09 23:57:33 +0200841static struct resource __devinitdata ab8500_debug_resources[] = {
Mattias Walline098aded72010-12-02 15:40:31 +0100842 {
843 .name = "IRQ_FIRST",
844 .start = AB8500_INT_MAIN_EXT_CH_NOT_OK,
845 .end = AB8500_INT_MAIN_EXT_CH_NOT_OK,
846 .flags = IORESOURCE_IRQ,
847 },
848 {
849 .name = "IRQ_LAST",
Bengt Jonssona9823622012-03-08 14:01:57 +0100850 .start = AB8500_INT_XTAL32K_KO,
851 .end = AB8500_INT_XTAL32K_KO,
Mattias Walline098aded72010-12-02 15:40:31 +0100852 .flags = IORESOURCE_IRQ,
853 },
854};
Axel Lindf720642011-11-10 09:56:18 +0800855#endif
Mattias Walline098aded72010-12-02 15:40:31 +0100856
Robert Rosengren5cef8df2011-06-09 23:57:33 +0200857static struct resource __devinitdata ab8500_usb_resources[] = {
Mattias Walline098aded72010-12-02 15:40:31 +0100858 {
859 .name = "ID_WAKEUP_R",
860 .start = AB8500_INT_ID_WAKEUP_R,
861 .end = AB8500_INT_ID_WAKEUP_R,
862 .flags = IORESOURCE_IRQ,
863 },
864 {
865 .name = "ID_WAKEUP_F",
866 .start = AB8500_INT_ID_WAKEUP_F,
867 .end = AB8500_INT_ID_WAKEUP_F,
868 .flags = IORESOURCE_IRQ,
869 },
870 {
871 .name = "VBUS_DET_F",
872 .start = AB8500_INT_VBUS_DET_F,
873 .end = AB8500_INT_VBUS_DET_F,
874 .flags = IORESOURCE_IRQ,
875 },
876 {
877 .name = "VBUS_DET_R",
878 .start = AB8500_INT_VBUS_DET_R,
879 .end = AB8500_INT_VBUS_DET_R,
880 .flags = IORESOURCE_IRQ,
881 },
Mattias Wallin92d50a42010-12-07 11:20:47 +0100882 {
883 .name = "USB_LINK_STATUS",
884 .start = AB8500_INT_USB_LINK_STATUS,
885 .end = AB8500_INT_USB_LINK_STATUS,
886 .flags = IORESOURCE_IRQ,
887 },
Linus Walleij6af75ec2011-06-09 23:57:45 +0200888 {
889 .name = "USB_ADP_PROBE_PLUG",
890 .start = AB8500_INT_ADP_PROBE_PLUG,
891 .end = AB8500_INT_ADP_PROBE_PLUG,
892 .flags = IORESOURCE_IRQ,
893 },
894 {
895 .name = "USB_ADP_PROBE_UNPLUG",
896 .start = AB8500_INT_ADP_PROBE_UNPLUG,
897 .end = AB8500_INT_ADP_PROBE_UNPLUG,
898 .flags = IORESOURCE_IRQ,
899 },
Mattias Walline098aded72010-12-02 15:40:31 +0100900};
901
Virupax Sadashivpetimath44f72e52012-04-17 09:30:14 +0200902static struct resource __devinitdata ab8505_iddet_resources[] = {
903 {
904 .name = "KeyDeglitch",
905 .start = AB8505_INT_KEYDEGLITCH,
906 .end = AB8505_INT_KEYDEGLITCH,
907 .flags = IORESOURCE_IRQ,
908 },
909 {
910 .name = "KP",
911 .start = AB8505_INT_KP,
912 .end = AB8505_INT_KP,
913 .flags = IORESOURCE_IRQ,
914 },
915 {
916 .name = "IKP",
917 .start = AB8505_INT_IKP,
918 .end = AB8505_INT_IKP,
919 .flags = IORESOURCE_IRQ,
920 },
921 {
922 .name = "IKR",
923 .start = AB8505_INT_IKR,
924 .end = AB8505_INT_IKR,
925 .flags = IORESOURCE_IRQ,
926 },
927 {
928 .name = "KeyStuck",
929 .start = AB8505_INT_KEYSTUCK,
930 .end = AB8505_INT_KEYSTUCK,
931 .flags = IORESOURCE_IRQ,
932 },
933};
934
Robert Rosengren5cef8df2011-06-09 23:57:33 +0200935static struct resource __devinitdata ab8500_temp_resources[] = {
Mattias Walline098aded72010-12-02 15:40:31 +0100936 {
937 .name = "AB8500_TEMP_WARM",
938 .start = AB8500_INT_TEMP_WARM,
939 .end = AB8500_INT_TEMP_WARM,
940 .flags = IORESOURCE_IRQ,
941 },
942};
943
Linus Walleijd6255522012-02-20 21:42:24 +0100944static struct mfd_cell __devinitdata abx500_common_devs[] = {
Mattias Wallin5814fc32010-09-13 16:05:04 +0200945#ifdef CONFIG_DEBUG_FS
946 {
947 .name = "ab8500-debug",
Mattias Walline098aded72010-12-02 15:40:31 +0100948 .num_resources = ARRAY_SIZE(ab8500_debug_resources),
949 .resources = ab8500_debug_resources,
Mattias Wallin5814fc32010-09-13 16:05:04 +0200950 },
951#endif
Rabin Vincent62579262010-05-19 11:39:02 +0200952 {
Mattias Walline098aded72010-12-02 15:40:31 +0100953 .name = "ab8500-sysctrl",
954 },
955 {
956 .name = "ab8500-regulator",
957 },
958 {
Rabin Vincent62579262010-05-19 11:39:02 +0200959 .name = "ab8500-gpadc",
960 .num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
961 .resources = ab8500_gpadc_resources,
962 },
963 {
964 .name = "ab8500-rtc",
965 .num_resources = ARRAY_SIZE(ab8500_rtc_resources),
966 .resources = ab8500_rtc_resources,
967 },
Arun Murthyf0f05b12010-09-06 12:24:52 +0530968 {
Linus Walleij6af75ec2011-06-09 23:57:45 +0200969 .name = "ab8500-acc-det",
970 .num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources),
971 .resources = ab8500_av_acc_detect_resources,
972 },
973 {
Mattias Walline098aded72010-12-02 15:40:31 +0100974 .name = "ab8500-poweron-key",
975 .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
976 .resources = ab8500_poweronkey_db_resources,
977 },
978 {
Arun Murthyf0f05b12010-09-06 12:24:52 +0530979 .name = "ab8500-pwm",
980 .id = 1,
981 },
982 {
983 .name = "ab8500-pwm",
984 .id = 2,
985 },
986 {
987 .name = "ab8500-pwm",
988 .id = 3,
989 },
Mattias Walline098aded72010-12-02 15:40:31 +0100990 { .name = "ab8500-leds", },
Sundar R Iyer77686512010-09-05 12:18:47 -0700991 {
Mattias Walline098aded72010-12-02 15:40:31 +0100992 .name = "ab8500-denc",
993 },
994 {
995 .name = "ab8500-temp",
996 .num_resources = ARRAY_SIZE(ab8500_temp_resources),
997 .resources = ab8500_temp_resources,
Sundar R Iyer77686512010-09-05 12:18:47 -0700998 },
Rabin Vincent62579262010-05-19 11:39:02 +0200999};
1000
Rickard Andersson6ef94182012-04-17 09:30:57 +02001001static struct mfd_cell __devinitdata ab8500_bm_devs[] = {
1002 {
1003 .name = "ab8500-charger",
1004 .num_resources = ARRAY_SIZE(ab8500_charger_resources),
1005 .resources = ab8500_charger_resources,
1006 },
1007 {
1008 .name = "ab8500-btemp",
1009 .num_resources = ARRAY_SIZE(ab8500_btemp_resources),
1010 .resources = ab8500_btemp_resources,
1011 },
1012 {
1013 .name = "ab8500-fg",
1014 .num_resources = ARRAY_SIZE(ab8500_fg_resources),
1015 .resources = ab8500_fg_resources,
1016 },
1017 {
1018 .name = "ab8500-chargalg",
1019 .num_resources = ARRAY_SIZE(ab8500_chargalg_resources),
1020 .resources = ab8500_chargalg_resources,
1021 },
1022};
1023
Linus Walleijd6255522012-02-20 21:42:24 +01001024static struct mfd_cell __devinitdata ab8500_devs[] = {
1025 {
1026 .name = "ab8500-gpio",
1027 .num_resources = ARRAY_SIZE(ab8500_gpio_resources),
1028 .resources = ab8500_gpio_resources,
1029 },
1030 {
1031 .name = "ab8500-usb",
1032 .num_resources = ARRAY_SIZE(ab8500_usb_resources),
1033 .resources = ab8500_usb_resources,
1034 },
Virupax Sadashivpetimath44f72e52012-04-17 09:30:14 +02001035 {
1036 .name = "ab8500-codec",
1037 },
Linus Walleijd6255522012-02-20 21:42:24 +01001038};
1039
1040static struct mfd_cell __devinitdata ab9540_devs[] = {
1041 {
1042 .name = "ab8500-gpio",
1043 .num_resources = ARRAY_SIZE(ab9540_gpio_resources),
1044 .resources = ab9540_gpio_resources,
1045 },
1046 {
1047 .name = "ab9540-usb",
1048 .num_resources = ARRAY_SIZE(ab8500_usb_resources),
1049 .resources = ab8500_usb_resources,
1050 },
Virupax Sadashivpetimath44f72e52012-04-17 09:30:14 +02001051 {
1052 .name = "ab9540-codec",
1053 },
1054};
1055
1056/* Device list common to ab9540 and ab8505 */
1057static struct mfd_cell __devinitdata ab9540_ab8505_devs[] = {
1058 {
1059 .name = "ab-iddet",
1060 .num_resources = ARRAY_SIZE(ab8505_iddet_resources),
1061 .resources = ab8505_iddet_resources,
1062 },
Linus Walleijd6255522012-02-20 21:42:24 +01001063};
1064
Mattias Wallincca69b62010-12-02 15:09:36 +01001065static ssize_t show_chip_id(struct device *dev,
1066 struct device_attribute *attr, char *buf)
1067{
1068 struct ab8500 *ab8500;
1069
1070 ab8500 = dev_get_drvdata(dev);
1071 return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL);
1072}
1073
Mattias Walline5c238c2011-03-02 11:52:36 +01001074/*
1075 * ab8500 has switched off due to (SWITCH_OFF_STATUS):
1076 * 0x01 Swoff bit programming
1077 * 0x02 Thermal protection activation
1078 * 0x04 Vbat lower then BattOk falling threshold
1079 * 0x08 Watchdog expired
1080 * 0x10 Non presence of 32kHz clock
1081 * 0x20 Battery level lower than power on reset threshold
1082 * 0x40 Power on key 1 pressed longer than 10 seconds
1083 * 0x80 DB8500 thermal shutdown
1084 */
1085static ssize_t show_switch_off_status(struct device *dev,
1086 struct device_attribute *attr, char *buf)
1087{
1088 int ret;
1089 u8 value;
1090 struct ab8500 *ab8500;
1091
1092 ab8500 = dev_get_drvdata(dev);
1093 ret = get_register_interruptible(ab8500, AB8500_RTC,
1094 AB8500_SWITCH_OFF_STATUS, &value);
1095 if (ret < 0)
1096 return ret;
1097 return sprintf(buf, "%#x\n", value);
1098}
1099
Andrew Lynnb4a31032011-10-11 10:49:47 +02001100/*
1101 * ab8500 has turned on due to (TURN_ON_STATUS):
1102 * 0x01 PORnVbat
1103 * 0x02 PonKey1dbF
1104 * 0x04 PonKey2dbF
1105 * 0x08 RTCAlarm
1106 * 0x10 MainChDet
1107 * 0x20 VbusDet
1108 * 0x40 UsbIDDetect
1109 * 0x80 Reserved
1110 */
1111static ssize_t show_turn_on_status(struct device *dev,
1112 struct device_attribute *attr, char *buf)
1113{
1114 int ret;
1115 u8 value;
1116 struct ab8500 *ab8500;
1117
1118 ab8500 = dev_get_drvdata(dev);
1119 ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK,
1120 AB8500_TURN_ON_STATUS, &value);
1121 if (ret < 0)
1122 return ret;
1123 return sprintf(buf, "%#x\n", value);
1124}
1125
Linus Walleijd6255522012-02-20 21:42:24 +01001126static ssize_t show_ab9540_dbbrstn(struct device *dev,
1127 struct device_attribute *attr, char *buf)
1128{
1129 struct ab8500 *ab8500;
1130 int ret;
1131 u8 value;
1132
1133 ab8500 = dev_get_drvdata(dev);
1134
1135 ret = get_register_interruptible(ab8500, AB8500_REGU_CTRL2,
1136 AB9540_MODEM_CTRL2_REG, &value);
1137 if (ret < 0)
1138 return ret;
1139
1140 return sprintf(buf, "%d\n",
1141 (value & AB9540_MODEM_CTRL2_SWDBBRSTN_BIT) ? 1 : 0);
1142}
1143
1144static ssize_t store_ab9540_dbbrstn(struct device *dev,
1145 struct device_attribute *attr, const char *buf, size_t count)
1146{
1147 struct ab8500 *ab8500;
1148 int ret = count;
1149 int err;
1150 u8 bitvalues;
1151
1152 ab8500 = dev_get_drvdata(dev);
1153
1154 if (count > 0) {
1155 switch (buf[0]) {
1156 case '0':
1157 bitvalues = 0;
1158 break;
1159 case '1':
1160 bitvalues = AB9540_MODEM_CTRL2_SWDBBRSTN_BIT;
1161 break;
1162 default:
1163 goto exit;
1164 }
1165
1166 err = mask_and_set_register_interruptible(ab8500,
1167 AB8500_REGU_CTRL2, AB9540_MODEM_CTRL2_REG,
1168 AB9540_MODEM_CTRL2_SWDBBRSTN_BIT, bitvalues);
1169 if (err)
1170 dev_info(ab8500->dev,
1171 "Failed to set DBBRSTN %c, err %#x\n",
1172 buf[0], err);
1173 }
1174
1175exit:
1176 return ret;
1177}
1178
Mattias Wallincca69b62010-12-02 15:09:36 +01001179static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL);
Mattias Walline5c238c2011-03-02 11:52:36 +01001180static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL);
Andrew Lynnb4a31032011-10-11 10:49:47 +02001181static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL);
Linus Walleijd6255522012-02-20 21:42:24 +01001182static DEVICE_ATTR(dbbrstn, S_IRUGO | S_IWUSR,
1183 show_ab9540_dbbrstn, store_ab9540_dbbrstn);
Mattias Wallincca69b62010-12-02 15:09:36 +01001184
1185static struct attribute *ab8500_sysfs_entries[] = {
1186 &dev_attr_chip_id.attr,
Mattias Walline5c238c2011-03-02 11:52:36 +01001187 &dev_attr_switch_off_status.attr,
Andrew Lynnb4a31032011-10-11 10:49:47 +02001188 &dev_attr_turn_on_status.attr,
Mattias Wallincca69b62010-12-02 15:09:36 +01001189 NULL,
1190};
1191
Linus Walleijd6255522012-02-20 21:42:24 +01001192static struct attribute *ab9540_sysfs_entries[] = {
1193 &dev_attr_chip_id.attr,
1194 &dev_attr_switch_off_status.attr,
1195 &dev_attr_turn_on_status.attr,
1196 &dev_attr_dbbrstn.attr,
1197 NULL,
1198};
1199
Mattias Wallincca69b62010-12-02 15:09:36 +01001200static struct attribute_group ab8500_attr_group = {
1201 .attrs = ab8500_sysfs_entries,
1202};
1203
Linus Walleijd6255522012-02-20 21:42:24 +01001204static struct attribute_group ab9540_attr_group = {
1205 .attrs = ab9540_sysfs_entries,
1206};
1207
Lee Jonesd28f1db2012-05-19 17:21:37 +02001208static int __devinit ab8500_probe(struct platform_device *pdev)
Rabin Vincent62579262010-05-19 11:39:02 +02001209{
Lee Jonesd28f1db2012-05-19 17:21:37 +02001210 struct ab8500_platform_data *plat = dev_get_platdata(&pdev->dev);
1211 const struct platform_device_id *platid = platform_get_device_id(pdev);
1212 enum ab8500_version version = platid->driver_data;
1213 struct ab8500 *ab8500;
1214 struct resource *resource;
Rabin Vincent62579262010-05-19 11:39:02 +02001215 int ret;
1216 int i;
Mattias Wallin47c16972010-09-10 17:47:56 +02001217 u8 value;
Rabin Vincent62579262010-05-19 11:39:02 +02001218
Lee Jonesd28f1db2012-05-19 17:21:37 +02001219 ab8500 = kzalloc(sizeof *ab8500, GFP_KERNEL);
1220 if (!ab8500)
1221 return -ENOMEM;
1222
Rabin Vincent62579262010-05-19 11:39:02 +02001223 if (plat)
1224 ab8500->irq_base = plat->irq_base;
1225
Lee Jonesd28f1db2012-05-19 17:21:37 +02001226 ab8500->dev = &pdev->dev;
1227
1228 resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
1229 if (!resource) {
1230 ret = -ENODEV;
1231 goto out_free_ab8500;
1232 }
1233
1234 ab8500->irq = resource->start;
1235
1236 ab8500->read = ab8500_i2c_read;
1237 ab8500->write = ab8500_i2c_write;
1238 ab8500->write_masked = ab8500_i2c_write_masked;
1239
Rabin Vincent62579262010-05-19 11:39:02 +02001240 mutex_init(&ab8500->lock);
1241 mutex_init(&ab8500->irq_lock);
Jonas Aaberg112a80d2012-04-17 09:30:33 +02001242 atomic_set(&ab8500->transfer_ongoing, 0);
Rabin Vincent62579262010-05-19 11:39:02 +02001243
Lee Jonesd28f1db2012-05-19 17:21:37 +02001244 platform_set_drvdata(pdev, ab8500);
1245
Linus Walleij0f6208372012-02-20 21:42:10 +01001246 if (version != AB8500_VERSION_UNDEFINED)
1247 ab8500->version = version;
1248 else {
1249 ret = get_register_interruptible(ab8500, AB8500_MISC,
1250 AB8500_IC_NAME_REG, &value);
1251 if (ret < 0)
Lee Jonesd28f1db2012-05-19 17:21:37 +02001252 goto out_free_ab8500;
Linus Walleij0f6208372012-02-20 21:42:10 +01001253
1254 ab8500->version = value;
1255 }
1256
Mattias Wallin47c16972010-09-10 17:47:56 +02001257 ret = get_register_interruptible(ab8500, AB8500_MISC,
1258 AB8500_REV_REG, &value);
Rabin Vincent62579262010-05-19 11:39:02 +02001259 if (ret < 0)
Lee Jonesd28f1db2012-05-19 17:21:37 +02001260 goto out_free_ab8500;
Rabin Vincent62579262010-05-19 11:39:02 +02001261
Mattias Wallin47c16972010-09-10 17:47:56 +02001262 ab8500->chip_id = value;
Rabin Vincent62579262010-05-19 11:39:02 +02001263
Linus Walleij0f6208372012-02-20 21:42:10 +01001264 dev_info(ab8500->dev, "detected chip, %s rev. %1x.%1x\n",
1265 ab8500_version_str[ab8500->version],
1266 ab8500->chip_id >> 4,
1267 ab8500->chip_id & 0x0F);
1268
Linus Walleijd6255522012-02-20 21:42:24 +01001269 /* Configure AB8500 or AB9540 IRQ */
Bengt Jonssona9823622012-03-08 14:01:57 +01001270 if (is_ab9540(ab8500) || is_ab8505(ab8500)) {
Linus Walleijd6255522012-02-20 21:42:24 +01001271 ab8500->mask_size = AB9540_NUM_IRQ_REGS;
1272 ab8500->irq_reg_offset = ab9540_irq_regoffset;
1273 } else {
1274 ab8500->mask_size = AB8500_NUM_IRQ_REGS;
1275 ab8500->irq_reg_offset = ab8500_irq_regoffset;
1276 }
Linus Walleij2ced4452012-02-20 21:42:17 +01001277 ab8500->mask = kzalloc(ab8500->mask_size, GFP_KERNEL);
1278 if (!ab8500->mask)
1279 return -ENOMEM;
1280 ab8500->oldmask = kzalloc(ab8500->mask_size, GFP_KERNEL);
1281 if (!ab8500->oldmask) {
1282 ret = -ENOMEM;
1283 goto out_freemask;
1284 }
Mattias Walline5c238c2011-03-02 11:52:36 +01001285 /*
1286 * ab8500 has switched off due to (SWITCH_OFF_STATUS):
1287 * 0x01 Swoff bit programming
1288 * 0x02 Thermal protection activation
1289 * 0x04 Vbat lower then BattOk falling threshold
1290 * 0x08 Watchdog expired
1291 * 0x10 Non presence of 32kHz clock
1292 * 0x20 Battery level lower than power on reset threshold
1293 * 0x40 Power on key 1 pressed longer than 10 seconds
1294 * 0x80 DB8500 thermal shutdown
1295 */
1296
1297 ret = get_register_interruptible(ab8500, AB8500_RTC,
1298 AB8500_SWITCH_OFF_STATUS, &value);
1299 if (ret < 0)
1300 return ret;
1301 dev_info(ab8500->dev, "switch off status: %#x", value);
1302
Rabin Vincent62579262010-05-19 11:39:02 +02001303 if (plat && plat->init)
1304 plat->init(ab8500);
1305
1306 /* Clear and mask all interrupts */
Linus Walleij2ced4452012-02-20 21:42:17 +01001307 for (i = 0; i < ab8500->mask_size; i++) {
Linus Walleij0f6208372012-02-20 21:42:10 +01001308 /*
1309 * Interrupt register 12 doesn't exist prior to AB8500 version
1310 * 2.0
1311 */
1312 if (ab8500->irq_reg_offset[i] == 11 &&
1313 is_ab8500_1p1_or_earlier(ab8500))
Mattias Wallin92d50a42010-12-07 11:20:47 +01001314 continue;
Rabin Vincent62579262010-05-19 11:39:02 +02001315
Mattias Wallin47c16972010-09-10 17:47:56 +02001316 get_register_interruptible(ab8500, AB8500_INTERRUPT,
Linus Walleij2ced4452012-02-20 21:42:17 +01001317 AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i],
Mattias Wallin92d50a42010-12-07 11:20:47 +01001318 &value);
Mattias Wallin47c16972010-09-10 17:47:56 +02001319 set_register_interruptible(ab8500, AB8500_INTERRUPT,
Linus Walleij2ced4452012-02-20 21:42:17 +01001320 AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i], 0xff);
Rabin Vincent62579262010-05-19 11:39:02 +02001321 }
1322
Mattias Wallin47c16972010-09-10 17:47:56 +02001323 ret = abx500_register_ops(ab8500->dev, &ab8500_ops);
1324 if (ret)
Linus Walleij2ced4452012-02-20 21:42:17 +01001325 goto out_freeoldmask;
Mattias Wallin47c16972010-09-10 17:47:56 +02001326
Linus Walleij2ced4452012-02-20 21:42:17 +01001327 for (i = 0; i < ab8500->mask_size; i++)
Rabin Vincent62579262010-05-19 11:39:02 +02001328 ab8500->mask[i] = ab8500->oldmask[i] = 0xff;
1329
1330 if (ab8500->irq_base) {
1331 ret = ab8500_irq_init(ab8500);
1332 if (ret)
Linus Walleij2ced4452012-02-20 21:42:17 +01001333 goto out_freeoldmask;
Rabin Vincent62579262010-05-19 11:39:02 +02001334
Michel JAOUEN7ccfe9b2012-05-07 15:02:03 +02001335 /* Activate this feature only in ab9540 */
1336 /* till tests are done on ab8500 1p2 or later*/
1337 if (is_ab9540(ab8500))
1338 ret = request_threaded_irq(ab8500->irq, NULL,
1339 ab8500_hierarchical_irq,
1340 IRQF_ONESHOT | IRQF_NO_SUSPEND,
1341 "ab8500", ab8500);
1342 else
1343 ret = request_threaded_irq(ab8500->irq, NULL,
1344 ab8500_irq,
1345 IRQF_ONESHOT | IRQF_NO_SUSPEND,
1346 "ab8500", ab8500);
Rabin Vincent62579262010-05-19 11:39:02 +02001347 if (ret)
1348 goto out_removeirq;
1349 }
1350
Linus Walleijd6255522012-02-20 21:42:24 +01001351 ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs,
1352 ARRAY_SIZE(abx500_common_devs), NULL,
1353 ab8500->irq_base);
1354
1355 if (ret)
1356 goto out_freeirq;
1357
1358 if (is_ab9540(ab8500))
1359 ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs,
1360 ARRAY_SIZE(ab9540_devs), NULL,
1361 ab8500->irq_base);
1362 else
1363 ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
Virupax Sadashivpetimath44f72e52012-04-17 09:30:14 +02001364 ARRAY_SIZE(ab8500_devs), NULL,
Rabin Vincent62579262010-05-19 11:39:02 +02001365 ab8500->irq_base);
Virupax Sadashivpetimath44f72e52012-04-17 09:30:14 +02001366
1367 if (is_ab9540(ab8500) || is_ab8505(ab8500))
1368 ret = mfd_add_devices(ab8500->dev, 0, ab9540_ab8505_devs,
1369 ARRAY_SIZE(ab9540_ab8505_devs), NULL,
1370 ab8500->irq_base);
1371
Rabin Vincent62579262010-05-19 11:39:02 +02001372 if (ret)
1373 goto out_freeirq;
1374
Rickard Andersson6ef94182012-04-17 09:30:57 +02001375 if (!no_bm) {
1376 /* Add battery management devices */
1377 ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs,
1378 ARRAY_SIZE(ab8500_bm_devs), NULL,
1379 ab8500->irq_base);
1380 if (ret)
1381 dev_err(ab8500->dev, "error adding bm devices\n");
1382 }
1383
Linus Walleijd6255522012-02-20 21:42:24 +01001384 if (is_ab9540(ab8500))
1385 ret = sysfs_create_group(&ab8500->dev->kobj,
1386 &ab9540_attr_group);
1387 else
1388 ret = sysfs_create_group(&ab8500->dev->kobj,
1389 &ab8500_attr_group);
Mattias Wallincca69b62010-12-02 15:09:36 +01001390 if (ret)
1391 dev_err(ab8500->dev, "error creating sysfs entries\n");
Linus Walleijd6255522012-02-20 21:42:24 +01001392 else
1393 return ret;
Rabin Vincent62579262010-05-19 11:39:02 +02001394
1395out_freeirq:
Linus Walleij6d95b7f2012-02-20 21:42:03 +01001396 if (ab8500->irq_base)
Rabin Vincent62579262010-05-19 11:39:02 +02001397 free_irq(ab8500->irq, ab8500);
1398out_removeirq:
Linus Walleij6d95b7f2012-02-20 21:42:03 +01001399 if (ab8500->irq_base)
Rabin Vincent62579262010-05-19 11:39:02 +02001400 ab8500_irq_remove(ab8500);
Linus Walleij2ced4452012-02-20 21:42:17 +01001401out_freeoldmask:
1402 kfree(ab8500->oldmask);
1403out_freemask:
1404 kfree(ab8500->mask);
Lee Jonesd28f1db2012-05-19 17:21:37 +02001405out_free_ab8500:
1406 kfree(ab8500);
Linus Walleij6d95b7f2012-02-20 21:42:03 +01001407
Rabin Vincent62579262010-05-19 11:39:02 +02001408 return ret;
1409}
1410
Lee Jonesd28f1db2012-05-19 17:21:37 +02001411static int __devexit ab8500_remove(struct platform_device *pdev)
Rabin Vincent62579262010-05-19 11:39:02 +02001412{
Lee Jonesd28f1db2012-05-19 17:21:37 +02001413 struct ab8500 *ab8500 = platform_get_drvdata(pdev);
1414
Linus Walleijd6255522012-02-20 21:42:24 +01001415 if (is_ab9540(ab8500))
1416 sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group);
1417 else
1418 sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
Rabin Vincent62579262010-05-19 11:39:02 +02001419 mfd_remove_devices(ab8500->dev);
1420 if (ab8500->irq_base) {
1421 free_irq(ab8500->irq, ab8500);
1422 ab8500_irq_remove(ab8500);
1423 }
Linus Walleij2ced4452012-02-20 21:42:17 +01001424 kfree(ab8500->oldmask);
1425 kfree(ab8500->mask);
Lee Jonesd28f1db2012-05-19 17:21:37 +02001426 kfree(ab8500);
Rabin Vincent62579262010-05-19 11:39:02 +02001427
1428 return 0;
1429}
1430
Lee Jonesd28f1db2012-05-19 17:21:37 +02001431static const struct platform_device_id ab8500_id[] = {
1432 { "ab8500-core", AB8500_VERSION_AB8500 },
1433 { "ab8505-i2c", AB8500_VERSION_AB8505 },
1434 { "ab9540-i2c", AB8500_VERSION_AB9540 },
1435 { "ab8540-i2c", AB8500_VERSION_AB8540 },
1436 { }
1437};
1438
1439static struct platform_driver ab8500_core_driver = {
1440 .driver = {
1441 .name = "ab8500-core",
1442 .owner = THIS_MODULE,
1443 },
1444 .probe = ab8500_probe,
1445 .remove = __devexit_p(ab8500_remove),
1446 .id_table = ab8500_id,
1447};
1448
1449static int __init ab8500_core_init(void)
1450{
1451 return platform_driver_register(&ab8500_core_driver);
1452}
1453
1454static void __exit ab8500_core_exit(void)
1455{
1456 platform_driver_unregister(&ab8500_core_driver);
1457}
1458arch_initcall(ab8500_core_init);
1459module_exit(ab8500_core_exit);
1460
Mattias Wallinadceed62011-03-02 11:51:11 +01001461MODULE_AUTHOR("Mattias Wallin, Srinidhi Kasagar, Rabin Vincent");
Rabin Vincent62579262010-05-19 11:39:02 +02001462MODULE_DESCRIPTION("AB8500 MFD core");
1463MODULE_LICENSE("GPL v2");