blob: 15a18fee971309734d0b54c0dcba6139e37bd0a7 [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>
Sundar R Iyer549931f2010-07-13 11:51:28 +053021#include <linux/regulator/ab8500.h>
Rabin Vincent62579262010-05-19 11:39:02 +020022
23/*
24 * Interrupt register offsets
25 * Bank : 0x0E
26 */
Mattias Wallin47c16972010-09-10 17:47:56 +020027#define AB8500_IT_SOURCE1_REG 0x00
28#define AB8500_IT_SOURCE2_REG 0x01
29#define AB8500_IT_SOURCE3_REG 0x02
30#define AB8500_IT_SOURCE4_REG 0x03
31#define AB8500_IT_SOURCE5_REG 0x04
32#define AB8500_IT_SOURCE6_REG 0x05
33#define AB8500_IT_SOURCE7_REG 0x06
34#define AB8500_IT_SOURCE8_REG 0x07
Linus Walleijd6255522012-02-20 21:42:24 +010035#define AB9540_IT_SOURCE13_REG 0x0C
Mattias Wallin47c16972010-09-10 17:47:56 +020036#define AB8500_IT_SOURCE19_REG 0x12
37#define AB8500_IT_SOURCE20_REG 0x13
38#define AB8500_IT_SOURCE21_REG 0x14
39#define AB8500_IT_SOURCE22_REG 0x15
40#define AB8500_IT_SOURCE23_REG 0x16
41#define AB8500_IT_SOURCE24_REG 0x17
Rabin Vincent62579262010-05-19 11:39:02 +020042
43/*
44 * latch registers
45 */
Mattias Wallin47c16972010-09-10 17:47:56 +020046#define AB8500_IT_LATCH1_REG 0x20
47#define AB8500_IT_LATCH2_REG 0x21
48#define AB8500_IT_LATCH3_REG 0x22
49#define AB8500_IT_LATCH4_REG 0x23
50#define AB8500_IT_LATCH5_REG 0x24
51#define AB8500_IT_LATCH6_REG 0x25
52#define AB8500_IT_LATCH7_REG 0x26
53#define AB8500_IT_LATCH8_REG 0x27
54#define AB8500_IT_LATCH9_REG 0x28
55#define AB8500_IT_LATCH10_REG 0x29
Mattias Wallin92d50a42010-12-07 11:20:47 +010056#define AB8500_IT_LATCH12_REG 0x2B
Linus Walleijd6255522012-02-20 21:42:24 +010057#define AB9540_IT_LATCH13_REG 0x2C
Mattias Wallin47c16972010-09-10 17:47:56 +020058#define AB8500_IT_LATCH19_REG 0x32
59#define AB8500_IT_LATCH20_REG 0x33
60#define AB8500_IT_LATCH21_REG 0x34
61#define AB8500_IT_LATCH22_REG 0x35
62#define AB8500_IT_LATCH23_REG 0x36
63#define AB8500_IT_LATCH24_REG 0x37
Rabin Vincent62579262010-05-19 11:39:02 +020064
65/*
66 * mask registers
67 */
68
Mattias Wallin47c16972010-09-10 17:47:56 +020069#define AB8500_IT_MASK1_REG 0x40
70#define AB8500_IT_MASK2_REG 0x41
71#define AB8500_IT_MASK3_REG 0x42
72#define AB8500_IT_MASK4_REG 0x43
73#define AB8500_IT_MASK5_REG 0x44
74#define AB8500_IT_MASK6_REG 0x45
75#define AB8500_IT_MASK7_REG 0x46
76#define AB8500_IT_MASK8_REG 0x47
77#define AB8500_IT_MASK9_REG 0x48
78#define AB8500_IT_MASK10_REG 0x49
79#define AB8500_IT_MASK11_REG 0x4A
80#define AB8500_IT_MASK12_REG 0x4B
81#define AB8500_IT_MASK13_REG 0x4C
82#define AB8500_IT_MASK14_REG 0x4D
83#define AB8500_IT_MASK15_REG 0x4E
84#define AB8500_IT_MASK16_REG 0x4F
85#define AB8500_IT_MASK17_REG 0x50
86#define AB8500_IT_MASK18_REG 0x51
87#define AB8500_IT_MASK19_REG 0x52
88#define AB8500_IT_MASK20_REG 0x53
89#define AB8500_IT_MASK21_REG 0x54
90#define AB8500_IT_MASK22_REG 0x55
91#define AB8500_IT_MASK23_REG 0x56
92#define AB8500_IT_MASK24_REG 0x57
Rabin Vincent62579262010-05-19 11:39:02 +020093
Mattias Wallin47c16972010-09-10 17:47:56 +020094#define AB8500_REV_REG 0x80
Linus Walleij0f6208372012-02-20 21:42:10 +010095#define AB8500_IC_NAME_REG 0x82
Mattias Walline5c238c2011-03-02 11:52:36 +010096#define AB8500_SWITCH_OFF_STATUS 0x00
Rabin Vincent62579262010-05-19 11:39:02 +020097
Andrew Lynnb4a31032011-10-11 10:49:47 +020098#define AB8500_TURN_ON_STATUS 0x00
99
Linus Walleijd6255522012-02-20 21:42:24 +0100100#define AB9540_MODEM_CTRL2_REG 0x23
101#define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT BIT(2)
102
Rabin Vincent62579262010-05-19 11:39:02 +0200103/*
104 * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt
Linus Walleij2ced4452012-02-20 21:42:17 +0100105 * numbers are indexed into this array with (num / 8). The interupts are
106 * defined in linux/mfd/ab8500.h
Rabin Vincent62579262010-05-19 11:39:02 +0200107 *
108 * This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at
109 * offset 0.
110 */
Linus Walleij2ced4452012-02-20 21:42:17 +0100111/* AB8500 support */
Rabin Vincent62579262010-05-19 11:39:02 +0200112static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = {
Mattias Wallin92d50a42010-12-07 11:20:47 +0100113 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21,
Rabin Vincent62579262010-05-19 11:39:02 +0200114};
115
Linus Walleijd6255522012-02-20 21:42:24 +0100116/* AB9540 support */
117static const int ab9540_irq_regoffset[AB9540_NUM_IRQ_REGS] = {
118 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24,
119};
120
Linus Walleij0f6208372012-02-20 21:42:10 +0100121static const char ab8500_version_str[][7] = {
122 [AB8500_VERSION_AB8500] = "AB8500",
123 [AB8500_VERSION_AB8505] = "AB8505",
124 [AB8500_VERSION_AB9540] = "AB9540",
125 [AB8500_VERSION_AB8540] = "AB8540",
126};
127
Mattias Wallin47c16972010-09-10 17:47:56 +0200128static int ab8500_get_chip_id(struct device *dev)
129{
Mattias Wallin6bce7bf2010-12-02 15:08:32 +0100130 struct ab8500 *ab8500;
131
132 if (!dev)
133 return -EINVAL;
134 ab8500 = dev_get_drvdata(dev->parent);
135 return ab8500 ? (int)ab8500->chip_id : -EINVAL;
Mattias Wallin47c16972010-09-10 17:47:56 +0200136}
137
138static int set_register_interruptible(struct ab8500 *ab8500, u8 bank,
139 u8 reg, u8 data)
Rabin Vincent62579262010-05-19 11:39:02 +0200140{
141 int ret;
Mattias Wallin47c16972010-09-10 17:47:56 +0200142 /*
143 * Put the u8 bank and u8 register together into a an u16.
144 * The bank on higher 8 bits and register in lower 8 bits.
145 * */
146 u16 addr = ((u16)bank) << 8 | reg;
Rabin Vincent62579262010-05-19 11:39:02 +0200147
148 dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data);
149
Mattias Wallin47c16972010-09-10 17:47:56 +0200150 ret = mutex_lock_interruptible(&ab8500->lock);
151 if (ret)
152 return ret;
153
154 ret = ab8500->write(ab8500, addr, data);
155 if (ret < 0)
156 dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
157 addr, ret);
158 mutex_unlock(&ab8500->lock);
159
160 return ret;
161}
162
163static int ab8500_set_register(struct device *dev, u8 bank,
164 u8 reg, u8 value)
165{
166 struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
167
168 return set_register_interruptible(ab8500, bank, reg, value);
169}
170
171static int get_register_interruptible(struct ab8500 *ab8500, u8 bank,
172 u8 reg, u8 *value)
173{
174 int ret;
175 /* put the u8 bank and u8 reg together into a an u16.
176 * bank on higher 8 bits and reg in lower */
177 u16 addr = ((u16)bank) << 8 | reg;
178
179 ret = mutex_lock_interruptible(&ab8500->lock);
180 if (ret)
181 return ret;
182
183 ret = ab8500->read(ab8500, addr);
184 if (ret < 0)
185 dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
186 addr, ret);
187 else
188 *value = ret;
189
190 mutex_unlock(&ab8500->lock);
191 dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret);
192
193 return ret;
194}
195
196static int ab8500_get_register(struct device *dev, u8 bank,
197 u8 reg, u8 *value)
198{
199 struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
200
201 return get_register_interruptible(ab8500, bank, reg, value);
202}
203
204static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank,
205 u8 reg, u8 bitmask, u8 bitvalues)
206{
207 int ret;
208 u8 data;
209 /* put the u8 bank and u8 reg together into a an u16.
210 * bank on higher 8 bits and reg in lower */
211 u16 addr = ((u16)bank) << 8 | reg;
212
213 ret = mutex_lock_interruptible(&ab8500->lock);
214 if (ret)
215 return ret;
216
217 ret = ab8500->read(ab8500, addr);
218 if (ret < 0) {
219 dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
220 addr, ret);
221 goto out;
222 }
223
224 data = (u8)ret;
225 data = (~bitmask & data) | (bitmask & bitvalues);
226
Rabin Vincent62579262010-05-19 11:39:02 +0200227 ret = ab8500->write(ab8500, addr, data);
228 if (ret < 0)
229 dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
230 addr, ret);
231
Mattias Wallin47c16972010-09-10 17:47:56 +0200232 dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr, data);
Rabin Vincent62579262010-05-19 11:39:02 +0200233out:
234 mutex_unlock(&ab8500->lock);
235 return ret;
236}
Mattias Wallin47c16972010-09-10 17:47:56 +0200237
238static int ab8500_mask_and_set_register(struct device *dev,
239 u8 bank, u8 reg, u8 bitmask, u8 bitvalues)
240{
241 struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
242
243 return mask_and_set_register_interruptible(ab8500, bank, reg,
244 bitmask, bitvalues);
245
246}
247
248static struct abx500_ops ab8500_ops = {
249 .get_chip_id = ab8500_get_chip_id,
250 .get_register = ab8500_get_register,
251 .set_register = ab8500_set_register,
252 .get_register_page = NULL,
253 .set_register_page = NULL,
254 .mask_and_set_register = ab8500_mask_and_set_register,
255 .event_registers_startup_state_get = NULL,
256 .startup_irq_enabled = NULL,
257};
Rabin Vincent62579262010-05-19 11:39:02 +0200258
Mark Brown9505a0a2010-12-11 13:16:08 +0000259static void ab8500_irq_lock(struct irq_data *data)
Rabin Vincent62579262010-05-19 11:39:02 +0200260{
Mark Brown9505a0a2010-12-11 13:16:08 +0000261 struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
Rabin Vincent62579262010-05-19 11:39:02 +0200262
263 mutex_lock(&ab8500->irq_lock);
264}
265
Mark Brown9505a0a2010-12-11 13:16:08 +0000266static void ab8500_irq_sync_unlock(struct irq_data *data)
Rabin Vincent62579262010-05-19 11:39:02 +0200267{
Mark Brown9505a0a2010-12-11 13:16:08 +0000268 struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
Rabin Vincent62579262010-05-19 11:39:02 +0200269 int i;
270
Linus Walleij2ced4452012-02-20 21:42:17 +0100271 for (i = 0; i < ab8500->mask_size; i++) {
Rabin Vincent62579262010-05-19 11:39:02 +0200272 u8 old = ab8500->oldmask[i];
273 u8 new = ab8500->mask[i];
274 int reg;
275
276 if (new == old)
277 continue;
278
Linus Walleij0f6208372012-02-20 21:42:10 +0100279 /*
280 * Interrupt register 12 doesn't exist prior to AB8500 version
281 * 2.0
282 */
283 if (ab8500->irq_reg_offset[i] == 11 &&
284 is_ab8500_1p1_or_earlier(ab8500))
Mattias Wallin92d50a42010-12-07 11:20:47 +0100285 continue;
286
Rabin Vincent62579262010-05-19 11:39:02 +0200287 ab8500->oldmask[i] = new;
288
Linus Walleij2ced4452012-02-20 21:42:17 +0100289 reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i];
Mattias Wallin47c16972010-09-10 17:47:56 +0200290 set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new);
Rabin Vincent62579262010-05-19 11:39:02 +0200291 }
292
293 mutex_unlock(&ab8500->irq_lock);
294}
295
Mark Brown9505a0a2010-12-11 13:16:08 +0000296static void ab8500_irq_mask(struct irq_data *data)
Rabin Vincent62579262010-05-19 11:39:02 +0200297{
Mark Brown9505a0a2010-12-11 13:16:08 +0000298 struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
299 int offset = data->irq - ab8500->irq_base;
Rabin Vincent62579262010-05-19 11:39:02 +0200300 int index = offset / 8;
301 int mask = 1 << (offset % 8);
302
303 ab8500->mask[index] |= mask;
304}
305
Mark Brown9505a0a2010-12-11 13:16:08 +0000306static void ab8500_irq_unmask(struct irq_data *data)
Rabin Vincent62579262010-05-19 11:39:02 +0200307{
Mark Brown9505a0a2010-12-11 13:16:08 +0000308 struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
309 int offset = data->irq - ab8500->irq_base;
Rabin Vincent62579262010-05-19 11:39:02 +0200310 int index = offset / 8;
311 int mask = 1 << (offset % 8);
312
313 ab8500->mask[index] &= ~mask;
314}
315
316static struct irq_chip ab8500_irq_chip = {
317 .name = "ab8500",
Mark Brown9505a0a2010-12-11 13:16:08 +0000318 .irq_bus_lock = ab8500_irq_lock,
319 .irq_bus_sync_unlock = ab8500_irq_sync_unlock,
320 .irq_mask = ab8500_irq_mask,
Virupax Sadashivpetimathe6f93062011-10-11 10:49:17 +0200321 .irq_disable = ab8500_irq_mask,
Mark Brown9505a0a2010-12-11 13:16:08 +0000322 .irq_unmask = ab8500_irq_unmask,
Rabin Vincent62579262010-05-19 11:39:02 +0200323};
324
325static irqreturn_t ab8500_irq(int irq, void *dev)
326{
327 struct ab8500 *ab8500 = dev;
328 int i;
329
330 dev_vdbg(ab8500->dev, "interrupt\n");
331
Linus Walleij2ced4452012-02-20 21:42:17 +0100332 for (i = 0; i < ab8500->mask_size; i++) {
333 int regoffset = ab8500->irq_reg_offset[i];
Rabin Vincent62579262010-05-19 11:39:02 +0200334 int status;
Mattias Wallin47c16972010-09-10 17:47:56 +0200335 u8 value;
Rabin Vincent62579262010-05-19 11:39:02 +0200336
Linus Walleij0f6208372012-02-20 21:42:10 +0100337 /*
338 * Interrupt register 12 doesn't exist prior to AB8500 version
339 * 2.0
340 */
341 if (regoffset == 11 && is_ab8500_1p1_or_earlier(ab8500))
Mattias Wallin92d50a42010-12-07 11:20:47 +0100342 continue;
343
Mattias Wallin47c16972010-09-10 17:47:56 +0200344 status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
345 AB8500_IT_LATCH1_REG + regoffset, &value);
346 if (status < 0 || value == 0)
Rabin Vincent62579262010-05-19 11:39:02 +0200347 continue;
348
349 do {
Mattias Wallin88aec4f2010-12-02 15:06:49 +0100350 int bit = __ffs(value);
Rabin Vincent62579262010-05-19 11:39:02 +0200351 int line = i * 8 + bit;
352
353 handle_nested_irq(ab8500->irq_base + line);
Mattias Wallin47c16972010-09-10 17:47:56 +0200354 value &= ~(1 << bit);
355 } while (value);
Rabin Vincent62579262010-05-19 11:39:02 +0200356 }
357
358 return IRQ_HANDLED;
359}
360
361static int ab8500_irq_init(struct ab8500 *ab8500)
362{
363 int base = ab8500->irq_base;
364 int irq;
Linus Walleij2ced4452012-02-20 21:42:17 +0100365 int num_irqs;
Rabin Vincent62579262010-05-19 11:39:02 +0200366
Linus Walleijd6255522012-02-20 21:42:24 +0100367 if (is_ab9540(ab8500))
368 num_irqs = AB9540_NR_IRQS;
369 else
370 num_irqs = AB8500_NR_IRQS;
Linus Walleij2ced4452012-02-20 21:42:17 +0100371
372 for (irq = base; irq < base + num_irqs; irq++) {
Thomas Gleixnerd5bb1222011-03-25 11:12:32 +0000373 irq_set_chip_data(irq, ab8500);
374 irq_set_chip_and_handler(irq, &ab8500_irq_chip,
Rabin Vincent62579262010-05-19 11:39:02 +0200375 handle_simple_irq);
Thomas Gleixnerd5bb1222011-03-25 11:12:32 +0000376 irq_set_nested_thread(irq, 1);
Rabin Vincent62579262010-05-19 11:39:02 +0200377#ifdef CONFIG_ARM
378 set_irq_flags(irq, IRQF_VALID);
379#else
Thomas Gleixnerd5bb1222011-03-25 11:12:32 +0000380 irq_set_noprobe(irq);
Rabin Vincent62579262010-05-19 11:39:02 +0200381#endif
382 }
383
384 return 0;
385}
386
387static void ab8500_irq_remove(struct ab8500 *ab8500)
388{
389 int base = ab8500->irq_base;
390 int irq;
Linus Walleij2ced4452012-02-20 21:42:17 +0100391 int num_irqs;
Rabin Vincent62579262010-05-19 11:39:02 +0200392
Linus Walleijd6255522012-02-20 21:42:24 +0100393 if (is_ab9540(ab8500))
394 num_irqs = AB9540_NR_IRQS;
395 else
396 num_irqs = AB8500_NR_IRQS;
Linus Walleij2ced4452012-02-20 21:42:17 +0100397
398 for (irq = base; irq < base + num_irqs; irq++) {
Rabin Vincent62579262010-05-19 11:39:02 +0200399#ifdef CONFIG_ARM
400 set_irq_flags(irq, 0);
401#endif
Thomas Gleixnerd5bb1222011-03-25 11:12:32 +0000402 irq_set_chip_and_handler(irq, NULL, NULL);
403 irq_set_chip_data(irq, NULL);
Rabin Vincent62579262010-05-19 11:39:02 +0200404 }
405}
406
Linus Walleijd6255522012-02-20 21:42:24 +0100407/* AB8500 GPIO Resources */
Robert Rosengren5cef8df2011-06-09 23:57:33 +0200408static struct resource __devinitdata ab8500_gpio_resources[] = {
Bibek Basu0cb3fcd2011-02-09 11:02:35 +0530409 {
410 .name = "GPIO_INT6",
411 .start = AB8500_INT_GPIO6R,
412 .end = AB8500_INT_GPIO41F,
413 .flags = IORESOURCE_IRQ,
414 }
415};
416
Linus Walleijd6255522012-02-20 21:42:24 +0100417/* AB9540 GPIO Resources */
418static struct resource __devinitdata ab9540_gpio_resources[] = {
419 {
420 .name = "GPIO_INT6",
421 .start = AB8500_INT_GPIO6R,
422 .end = AB8500_INT_GPIO41F,
423 .flags = IORESOURCE_IRQ,
424 },
425 {
426 .name = "GPIO_INT14",
427 .start = AB9540_INT_GPIO50R,
428 .end = AB9540_INT_GPIO54R,
429 .flags = IORESOURCE_IRQ,
430 },
431 {
432 .name = "GPIO_INT15",
433 .start = AB9540_INT_GPIO50F,
434 .end = AB9540_INT_GPIO54F,
435 .flags = IORESOURCE_IRQ,
436 }
437};
438
Robert Rosengren5cef8df2011-06-09 23:57:33 +0200439static struct resource __devinitdata ab8500_gpadc_resources[] = {
Rabin Vincent62579262010-05-19 11:39:02 +0200440 {
441 .name = "HW_CONV_END",
442 .start = AB8500_INT_GP_HW_ADC_CONV_END,
443 .end = AB8500_INT_GP_HW_ADC_CONV_END,
444 .flags = IORESOURCE_IRQ,
445 },
446 {
447 .name = "SW_CONV_END",
448 .start = AB8500_INT_GP_SW_ADC_CONV_END,
449 .end = AB8500_INT_GP_SW_ADC_CONV_END,
450 .flags = IORESOURCE_IRQ,
451 },
452};
453
Robert Rosengren5cef8df2011-06-09 23:57:33 +0200454static struct resource __devinitdata ab8500_rtc_resources[] = {
Rabin Vincent62579262010-05-19 11:39:02 +0200455 {
456 .name = "60S",
457 .start = AB8500_INT_RTC_60S,
458 .end = AB8500_INT_RTC_60S,
459 .flags = IORESOURCE_IRQ,
460 },
461 {
462 .name = "ALARM",
463 .start = AB8500_INT_RTC_ALARM,
464 .end = AB8500_INT_RTC_ALARM,
465 .flags = IORESOURCE_IRQ,
466 },
467};
468
Robert Rosengren5cef8df2011-06-09 23:57:33 +0200469static struct resource __devinitdata ab8500_poweronkey_db_resources[] = {
Sundar R Iyer77686512010-09-05 12:18:47 -0700470 {
471 .name = "ONKEY_DBF",
472 .start = AB8500_INT_PON_KEY1DB_F,
473 .end = AB8500_INT_PON_KEY1DB_F,
474 .flags = IORESOURCE_IRQ,
475 },
476 {
477 .name = "ONKEY_DBR",
478 .start = AB8500_INT_PON_KEY1DB_R,
479 .end = AB8500_INT_PON_KEY1DB_R,
480 .flags = IORESOURCE_IRQ,
481 },
482};
483
Linus Walleij6af75ec2011-06-09 23:57:45 +0200484static struct resource __devinitdata ab8500_av_acc_detect_resources[] = {
Mattias Walline098aded72010-12-02 15:40:31 +0100485 {
Linus Walleij6af75ec2011-06-09 23:57:45 +0200486 .name = "ACC_DETECT_1DB_F",
487 .start = AB8500_INT_ACC_DETECT_1DB_F,
488 .end = AB8500_INT_ACC_DETECT_1DB_F,
489 .flags = IORESOURCE_IRQ,
Mattias Walline098aded72010-12-02 15:40:31 +0100490 },
491 {
Linus Walleij6af75ec2011-06-09 23:57:45 +0200492 .name = "ACC_DETECT_1DB_R",
493 .start = AB8500_INT_ACC_DETECT_1DB_R,
494 .end = AB8500_INT_ACC_DETECT_1DB_R,
495 .flags = IORESOURCE_IRQ,
Mattias Walline098aded72010-12-02 15:40:31 +0100496 },
497 {
Linus Walleij6af75ec2011-06-09 23:57:45 +0200498 .name = "ACC_DETECT_21DB_F",
499 .start = AB8500_INT_ACC_DETECT_21DB_F,
500 .end = AB8500_INT_ACC_DETECT_21DB_F,
501 .flags = IORESOURCE_IRQ,
502 },
503 {
504 .name = "ACC_DETECT_21DB_R",
505 .start = AB8500_INT_ACC_DETECT_21DB_R,
506 .end = AB8500_INT_ACC_DETECT_21DB_R,
507 .flags = IORESOURCE_IRQ,
508 },
509 {
510 .name = "ACC_DETECT_22DB_F",
511 .start = AB8500_INT_ACC_DETECT_22DB_F,
512 .end = AB8500_INT_ACC_DETECT_22DB_F,
513 .flags = IORESOURCE_IRQ,
514 },
515 {
516 .name = "ACC_DETECT_22DB_R",
517 .start = AB8500_INT_ACC_DETECT_22DB_R,
518 .end = AB8500_INT_ACC_DETECT_22DB_R,
519 .flags = IORESOURCE_IRQ,
520 },
521};
522
523static struct resource __devinitdata ab8500_charger_resources[] = {
524 {
Mattias Walline098aded72010-12-02 15:40:31 +0100525 .name = "MAIN_CH_UNPLUG_DET",
526 .start = AB8500_INT_MAIN_CH_UNPLUG_DET,
527 .end = AB8500_INT_MAIN_CH_UNPLUG_DET,
528 .flags = IORESOURCE_IRQ,
529 },
530 {
531 .name = "MAIN_CHARGE_PLUG_DET",
532 .start = AB8500_INT_MAIN_CH_PLUG_DET,
533 .end = AB8500_INT_MAIN_CH_PLUG_DET,
534 .flags = IORESOURCE_IRQ,
535 },
536 {
Mattias Walline098aded72010-12-02 15:40:31 +0100537 .name = "VBUS_DET_R",
538 .start = AB8500_INT_VBUS_DET_R,
539 .end = AB8500_INT_VBUS_DET_R,
540 .flags = IORESOURCE_IRQ,
541 },
542 {
Linus Walleij6af75ec2011-06-09 23:57:45 +0200543 .name = "VBUS_DET_F",
544 .start = AB8500_INT_VBUS_DET_F,
545 .end = AB8500_INT_VBUS_DET_F,
Mattias Walline098aded72010-12-02 15:40:31 +0100546 .flags = IORESOURCE_IRQ,
547 },
548 {
Linus Walleij6af75ec2011-06-09 23:57:45 +0200549 .name = "USB_LINK_STATUS",
550 .start = AB8500_INT_USB_LINK_STATUS,
551 .end = AB8500_INT_USB_LINK_STATUS,
552 .flags = IORESOURCE_IRQ,
553 },
554 {
555 .name = "USB_CHARGE_DET_DONE",
556 .start = AB8500_INT_USB_CHG_DET_DONE,
557 .end = AB8500_INT_USB_CHG_DET_DONE,
Mattias Walline098aded72010-12-02 15:40:31 +0100558 .flags = IORESOURCE_IRQ,
559 },
560 {
561 .name = "VBUS_OVV",
562 .start = AB8500_INT_VBUS_OVV,
563 .end = AB8500_INT_VBUS_OVV,
564 .flags = IORESOURCE_IRQ,
565 },
566 {
Linus Walleij6af75ec2011-06-09 23:57:45 +0200567 .name = "USB_CH_TH_PROT_R",
568 .start = AB8500_INT_USB_CH_TH_PROT_R,
569 .end = AB8500_INT_USB_CH_TH_PROT_R,
Mattias Walline098aded72010-12-02 15:40:31 +0100570 .flags = IORESOURCE_IRQ,
571 },
572 {
Linus Walleij6af75ec2011-06-09 23:57:45 +0200573 .name = "USB_CH_TH_PROT_F",
574 .start = AB8500_INT_USB_CH_TH_PROT_F,
575 .end = AB8500_INT_USB_CH_TH_PROT_F,
Mattias Walline098aded72010-12-02 15:40:31 +0100576 .flags = IORESOURCE_IRQ,
577 },
578 {
Linus Walleij6af75ec2011-06-09 23:57:45 +0200579 .name = "MAIN_EXT_CH_NOT_OK",
580 .start = AB8500_INT_MAIN_EXT_CH_NOT_OK,
581 .end = AB8500_INT_MAIN_EXT_CH_NOT_OK,
582 .flags = IORESOURCE_IRQ,
583 },
584 {
585 .name = "MAIN_CH_TH_PROT_R",
586 .start = AB8500_INT_MAIN_CH_TH_PROT_R,
587 .end = AB8500_INT_MAIN_CH_TH_PROT_R,
588 .flags = IORESOURCE_IRQ,
589 },
590 {
591 .name = "MAIN_CH_TH_PROT_F",
592 .start = AB8500_INT_MAIN_CH_TH_PROT_F,
593 .end = AB8500_INT_MAIN_CH_TH_PROT_F,
594 .flags = IORESOURCE_IRQ,
595 },
596 {
597 .name = "USB_CHARGER_NOT_OKR",
598 .start = AB8500_INT_USB_CHARGER_NOT_OK,
599 .end = AB8500_INT_USB_CHARGER_NOT_OK,
600 .flags = IORESOURCE_IRQ,
601 },
602 {
603 .name = "USB_CHARGER_NOT_OKF",
604 .start = AB8500_INT_USB_CHARGER_NOT_OKF,
605 .end = AB8500_INT_USB_CHARGER_NOT_OKF,
606 .flags = IORESOURCE_IRQ,
607 },
608 {
609 .name = "CH_WD_EXP",
610 .start = AB8500_INT_CH_WD_EXP,
611 .end = AB8500_INT_CH_WD_EXP,
612 .flags = IORESOURCE_IRQ,
613 },
614};
615
616static struct resource __devinitdata ab8500_btemp_resources[] = {
617 {
618 .name = "BAT_CTRL_INDB",
619 .start = AB8500_INT_BAT_CTRL_INDB,
620 .end = AB8500_INT_BAT_CTRL_INDB,
Mattias Walline098aded72010-12-02 15:40:31 +0100621 .flags = IORESOURCE_IRQ,
622 },
623 {
624 .name = "BTEMP_LOW",
625 .start = AB8500_INT_BTEMP_LOW,
626 .end = AB8500_INT_BTEMP_LOW,
627 .flags = IORESOURCE_IRQ,
628 },
629 {
630 .name = "BTEMP_HIGH",
631 .start = AB8500_INT_BTEMP_HIGH,
632 .end = AB8500_INT_BTEMP_HIGH,
633 .flags = IORESOURCE_IRQ,
634 },
635 {
Linus Walleij6af75ec2011-06-09 23:57:45 +0200636 .name = "BTEMP_LOW_MEDIUM",
637 .start = AB8500_INT_BTEMP_LOW_MEDIUM,
638 .end = AB8500_INT_BTEMP_LOW_MEDIUM,
Mattias Walline098aded72010-12-02 15:40:31 +0100639 .flags = IORESOURCE_IRQ,
640 },
641 {
Linus Walleij6af75ec2011-06-09 23:57:45 +0200642 .name = "BTEMP_MEDIUM_HIGH",
643 .start = AB8500_INT_BTEMP_MEDIUM_HIGH,
644 .end = AB8500_INT_BTEMP_MEDIUM_HIGH,
Mattias Walline098aded72010-12-02 15:40:31 +0100645 .flags = IORESOURCE_IRQ,
646 },
647};
648
Linus Walleij6af75ec2011-06-09 23:57:45 +0200649static struct resource __devinitdata ab8500_fg_resources[] = {
650 {
651 .name = "NCONV_ACCU",
652 .start = AB8500_INT_CCN_CONV_ACC,
653 .end = AB8500_INT_CCN_CONV_ACC,
654 .flags = IORESOURCE_IRQ,
655 },
656 {
657 .name = "BATT_OVV",
658 .start = AB8500_INT_BATT_OVV,
659 .end = AB8500_INT_BATT_OVV,
660 .flags = IORESOURCE_IRQ,
661 },
662 {
663 .name = "LOW_BAT_F",
664 .start = AB8500_INT_LOW_BAT_F,
665 .end = AB8500_INT_LOW_BAT_F,
666 .flags = IORESOURCE_IRQ,
667 },
668 {
669 .name = "LOW_BAT_R",
670 .start = AB8500_INT_LOW_BAT_R,
671 .end = AB8500_INT_LOW_BAT_R,
672 .flags = IORESOURCE_IRQ,
673 },
674 {
675 .name = "CC_INT_CALIB",
676 .start = AB8500_INT_CC_INT_CALIB,
677 .end = AB8500_INT_CC_INT_CALIB,
678 .flags = IORESOURCE_IRQ,
679 },
680};
681
682static struct resource __devinitdata ab8500_chargalg_resources[] = {};
683
Axel Lindf720642011-11-10 09:56:18 +0800684#ifdef CONFIG_DEBUG_FS
Robert Rosengren5cef8df2011-06-09 23:57:33 +0200685static struct resource __devinitdata ab8500_debug_resources[] = {
Mattias Walline098aded72010-12-02 15:40:31 +0100686 {
687 .name = "IRQ_FIRST",
688 .start = AB8500_INT_MAIN_EXT_CH_NOT_OK,
689 .end = AB8500_INT_MAIN_EXT_CH_NOT_OK,
690 .flags = IORESOURCE_IRQ,
691 },
692 {
693 .name = "IRQ_LAST",
694 .start = AB8500_INT_USB_CHARGER_NOT_OKF,
695 .end = AB8500_INT_USB_CHARGER_NOT_OKF,
696 .flags = IORESOURCE_IRQ,
697 },
698};
Axel Lindf720642011-11-10 09:56:18 +0800699#endif
Mattias Walline098aded72010-12-02 15:40:31 +0100700
Robert Rosengren5cef8df2011-06-09 23:57:33 +0200701static struct resource __devinitdata ab8500_usb_resources[] = {
Mattias Walline098aded72010-12-02 15:40:31 +0100702 {
703 .name = "ID_WAKEUP_R",
704 .start = AB8500_INT_ID_WAKEUP_R,
705 .end = AB8500_INT_ID_WAKEUP_R,
706 .flags = IORESOURCE_IRQ,
707 },
708 {
709 .name = "ID_WAKEUP_F",
710 .start = AB8500_INT_ID_WAKEUP_F,
711 .end = AB8500_INT_ID_WAKEUP_F,
712 .flags = IORESOURCE_IRQ,
713 },
714 {
715 .name = "VBUS_DET_F",
716 .start = AB8500_INT_VBUS_DET_F,
717 .end = AB8500_INT_VBUS_DET_F,
718 .flags = IORESOURCE_IRQ,
719 },
720 {
721 .name = "VBUS_DET_R",
722 .start = AB8500_INT_VBUS_DET_R,
723 .end = AB8500_INT_VBUS_DET_R,
724 .flags = IORESOURCE_IRQ,
725 },
Mattias Wallin92d50a42010-12-07 11:20:47 +0100726 {
727 .name = "USB_LINK_STATUS",
728 .start = AB8500_INT_USB_LINK_STATUS,
729 .end = AB8500_INT_USB_LINK_STATUS,
730 .flags = IORESOURCE_IRQ,
731 },
Linus Walleij6af75ec2011-06-09 23:57:45 +0200732 {
733 .name = "USB_ADP_PROBE_PLUG",
734 .start = AB8500_INT_ADP_PROBE_PLUG,
735 .end = AB8500_INT_ADP_PROBE_PLUG,
736 .flags = IORESOURCE_IRQ,
737 },
738 {
739 .name = "USB_ADP_PROBE_UNPLUG",
740 .start = AB8500_INT_ADP_PROBE_UNPLUG,
741 .end = AB8500_INT_ADP_PROBE_UNPLUG,
742 .flags = IORESOURCE_IRQ,
743 },
Mattias Walline098aded72010-12-02 15:40:31 +0100744};
745
Robert Rosengren5cef8df2011-06-09 23:57:33 +0200746static struct resource __devinitdata ab8500_temp_resources[] = {
Mattias Walline098aded72010-12-02 15:40:31 +0100747 {
748 .name = "AB8500_TEMP_WARM",
749 .start = AB8500_INT_TEMP_WARM,
750 .end = AB8500_INT_TEMP_WARM,
751 .flags = IORESOURCE_IRQ,
752 },
753};
754
Linus Walleijd6255522012-02-20 21:42:24 +0100755static struct mfd_cell __devinitdata abx500_common_devs[] = {
Mattias Wallin5814fc32010-09-13 16:05:04 +0200756#ifdef CONFIG_DEBUG_FS
757 {
758 .name = "ab8500-debug",
Mattias Walline098aded72010-12-02 15:40:31 +0100759 .num_resources = ARRAY_SIZE(ab8500_debug_resources),
760 .resources = ab8500_debug_resources,
Mattias Wallin5814fc32010-09-13 16:05:04 +0200761 },
762#endif
Rabin Vincent62579262010-05-19 11:39:02 +0200763 {
Mattias Walline098aded72010-12-02 15:40:31 +0100764 .name = "ab8500-sysctrl",
765 },
766 {
767 .name = "ab8500-regulator",
768 },
769 {
Rabin Vincent62579262010-05-19 11:39:02 +0200770 .name = "ab8500-gpadc",
771 .num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
772 .resources = ab8500_gpadc_resources,
773 },
774 {
775 .name = "ab8500-rtc",
776 .num_resources = ARRAY_SIZE(ab8500_rtc_resources),
777 .resources = ab8500_rtc_resources,
778 },
Arun Murthyf0f05b12010-09-06 12:24:52 +0530779 {
Linus Walleij6af75ec2011-06-09 23:57:45 +0200780 .name = "ab8500-charger",
781 .num_resources = ARRAY_SIZE(ab8500_charger_resources),
782 .resources = ab8500_charger_resources,
Mattias Walline098aded72010-12-02 15:40:31 +0100783 },
Linus Walleij6af75ec2011-06-09 23:57:45 +0200784 {
785 .name = "ab8500-btemp",
786 .num_resources = ARRAY_SIZE(ab8500_btemp_resources),
787 .resources = ab8500_btemp_resources,
788 },
789 {
790 .name = "ab8500-fg",
791 .num_resources = ARRAY_SIZE(ab8500_fg_resources),
792 .resources = ab8500_fg_resources,
793 },
794 {
795 .name = "ab8500-chargalg",
796 .num_resources = ARRAY_SIZE(ab8500_chargalg_resources),
797 .resources = ab8500_chargalg_resources,
798 },
799 {
800 .name = "ab8500-acc-det",
801 .num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources),
802 .resources = ab8500_av_acc_detect_resources,
803 },
804 {
805 .name = "ab8500-codec",
806 },
Linus Walleijd6255522012-02-20 21:42:24 +0100807
Mattias Walline098aded72010-12-02 15:40:31 +0100808 {
809 .name = "ab8500-poweron-key",
810 .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
811 .resources = ab8500_poweronkey_db_resources,
812 },
813 {
Arun Murthyf0f05b12010-09-06 12:24:52 +0530814 .name = "ab8500-pwm",
815 .id = 1,
816 },
817 {
818 .name = "ab8500-pwm",
819 .id = 2,
820 },
821 {
822 .name = "ab8500-pwm",
823 .id = 3,
824 },
Mattias Walline098aded72010-12-02 15:40:31 +0100825 { .name = "ab8500-leds", },
Sundar R Iyer77686512010-09-05 12:18:47 -0700826 {
Mattias Walline098aded72010-12-02 15:40:31 +0100827 .name = "ab8500-denc",
828 },
829 {
830 .name = "ab8500-temp",
831 .num_resources = ARRAY_SIZE(ab8500_temp_resources),
832 .resources = ab8500_temp_resources,
Sundar R Iyer77686512010-09-05 12:18:47 -0700833 },
Rabin Vincent62579262010-05-19 11:39:02 +0200834};
835
Linus Walleijd6255522012-02-20 21:42:24 +0100836static struct mfd_cell __devinitdata ab8500_devs[] = {
837 {
838 .name = "ab8500-gpio",
839 .num_resources = ARRAY_SIZE(ab8500_gpio_resources),
840 .resources = ab8500_gpio_resources,
841 },
842 {
843 .name = "ab8500-usb",
844 .num_resources = ARRAY_SIZE(ab8500_usb_resources),
845 .resources = ab8500_usb_resources,
846 },
847};
848
849static struct mfd_cell __devinitdata ab9540_devs[] = {
850 {
851 .name = "ab8500-gpio",
852 .num_resources = ARRAY_SIZE(ab9540_gpio_resources),
853 .resources = ab9540_gpio_resources,
854 },
855 {
856 .name = "ab9540-usb",
857 .num_resources = ARRAY_SIZE(ab8500_usb_resources),
858 .resources = ab8500_usb_resources,
859 },
860};
861
Mattias Wallincca69b62010-12-02 15:09:36 +0100862static ssize_t show_chip_id(struct device *dev,
863 struct device_attribute *attr, char *buf)
864{
865 struct ab8500 *ab8500;
866
867 ab8500 = dev_get_drvdata(dev);
868 return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL);
869}
870
Mattias Walline5c238c2011-03-02 11:52:36 +0100871/*
872 * ab8500 has switched off due to (SWITCH_OFF_STATUS):
873 * 0x01 Swoff bit programming
874 * 0x02 Thermal protection activation
875 * 0x04 Vbat lower then BattOk falling threshold
876 * 0x08 Watchdog expired
877 * 0x10 Non presence of 32kHz clock
878 * 0x20 Battery level lower than power on reset threshold
879 * 0x40 Power on key 1 pressed longer than 10 seconds
880 * 0x80 DB8500 thermal shutdown
881 */
882static ssize_t show_switch_off_status(struct device *dev,
883 struct device_attribute *attr, char *buf)
884{
885 int ret;
886 u8 value;
887 struct ab8500 *ab8500;
888
889 ab8500 = dev_get_drvdata(dev);
890 ret = get_register_interruptible(ab8500, AB8500_RTC,
891 AB8500_SWITCH_OFF_STATUS, &value);
892 if (ret < 0)
893 return ret;
894 return sprintf(buf, "%#x\n", value);
895}
896
Andrew Lynnb4a31032011-10-11 10:49:47 +0200897/*
898 * ab8500 has turned on due to (TURN_ON_STATUS):
899 * 0x01 PORnVbat
900 * 0x02 PonKey1dbF
901 * 0x04 PonKey2dbF
902 * 0x08 RTCAlarm
903 * 0x10 MainChDet
904 * 0x20 VbusDet
905 * 0x40 UsbIDDetect
906 * 0x80 Reserved
907 */
908static ssize_t show_turn_on_status(struct device *dev,
909 struct device_attribute *attr, char *buf)
910{
911 int ret;
912 u8 value;
913 struct ab8500 *ab8500;
914
915 ab8500 = dev_get_drvdata(dev);
916 ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK,
917 AB8500_TURN_ON_STATUS, &value);
918 if (ret < 0)
919 return ret;
920 return sprintf(buf, "%#x\n", value);
921}
922
Linus Walleijd6255522012-02-20 21:42:24 +0100923static ssize_t show_ab9540_dbbrstn(struct device *dev,
924 struct device_attribute *attr, char *buf)
925{
926 struct ab8500 *ab8500;
927 int ret;
928 u8 value;
929
930 ab8500 = dev_get_drvdata(dev);
931
932 ret = get_register_interruptible(ab8500, AB8500_REGU_CTRL2,
933 AB9540_MODEM_CTRL2_REG, &value);
934 if (ret < 0)
935 return ret;
936
937 return sprintf(buf, "%d\n",
938 (value & AB9540_MODEM_CTRL2_SWDBBRSTN_BIT) ? 1 : 0);
939}
940
941static ssize_t store_ab9540_dbbrstn(struct device *dev,
942 struct device_attribute *attr, const char *buf, size_t count)
943{
944 struct ab8500 *ab8500;
945 int ret = count;
946 int err;
947 u8 bitvalues;
948
949 ab8500 = dev_get_drvdata(dev);
950
951 if (count > 0) {
952 switch (buf[0]) {
953 case '0':
954 bitvalues = 0;
955 break;
956 case '1':
957 bitvalues = AB9540_MODEM_CTRL2_SWDBBRSTN_BIT;
958 break;
959 default:
960 goto exit;
961 }
962
963 err = mask_and_set_register_interruptible(ab8500,
964 AB8500_REGU_CTRL2, AB9540_MODEM_CTRL2_REG,
965 AB9540_MODEM_CTRL2_SWDBBRSTN_BIT, bitvalues);
966 if (err)
967 dev_info(ab8500->dev,
968 "Failed to set DBBRSTN %c, err %#x\n",
969 buf[0], err);
970 }
971
972exit:
973 return ret;
974}
975
Mattias Wallincca69b62010-12-02 15:09:36 +0100976static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL);
Mattias Walline5c238c2011-03-02 11:52:36 +0100977static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL);
Andrew Lynnb4a31032011-10-11 10:49:47 +0200978static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL);
Linus Walleijd6255522012-02-20 21:42:24 +0100979static DEVICE_ATTR(dbbrstn, S_IRUGO | S_IWUSR,
980 show_ab9540_dbbrstn, store_ab9540_dbbrstn);
Mattias Wallincca69b62010-12-02 15:09:36 +0100981
982static struct attribute *ab8500_sysfs_entries[] = {
983 &dev_attr_chip_id.attr,
Mattias Walline5c238c2011-03-02 11:52:36 +0100984 &dev_attr_switch_off_status.attr,
Andrew Lynnb4a31032011-10-11 10:49:47 +0200985 &dev_attr_turn_on_status.attr,
Mattias Wallincca69b62010-12-02 15:09:36 +0100986 NULL,
987};
988
Linus Walleijd6255522012-02-20 21:42:24 +0100989static struct attribute *ab9540_sysfs_entries[] = {
990 &dev_attr_chip_id.attr,
991 &dev_attr_switch_off_status.attr,
992 &dev_attr_turn_on_status.attr,
993 &dev_attr_dbbrstn.attr,
994 NULL,
995};
996
Mattias Wallincca69b62010-12-02 15:09:36 +0100997static struct attribute_group ab8500_attr_group = {
998 .attrs = ab8500_sysfs_entries,
999};
1000
Linus Walleijd6255522012-02-20 21:42:24 +01001001static struct attribute_group ab9540_attr_group = {
1002 .attrs = ab9540_sysfs_entries,
1003};
1004
Linus Walleij0f6208372012-02-20 21:42:10 +01001005int __devinit ab8500_init(struct ab8500 *ab8500, enum ab8500_version version)
Rabin Vincent62579262010-05-19 11:39:02 +02001006{
1007 struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev);
1008 int ret;
1009 int i;
Mattias Wallin47c16972010-09-10 17:47:56 +02001010 u8 value;
Rabin Vincent62579262010-05-19 11:39:02 +02001011
1012 if (plat)
1013 ab8500->irq_base = plat->irq_base;
1014
1015 mutex_init(&ab8500->lock);
1016 mutex_init(&ab8500->irq_lock);
1017
Linus Walleij0f6208372012-02-20 21:42:10 +01001018 if (version != AB8500_VERSION_UNDEFINED)
1019 ab8500->version = version;
1020 else {
1021 ret = get_register_interruptible(ab8500, AB8500_MISC,
1022 AB8500_IC_NAME_REG, &value);
1023 if (ret < 0)
1024 return ret;
1025
1026 ab8500->version = value;
1027 }
1028
Mattias Wallin47c16972010-09-10 17:47:56 +02001029 ret = get_register_interruptible(ab8500, AB8500_MISC,
1030 AB8500_REV_REG, &value);
Rabin Vincent62579262010-05-19 11:39:02 +02001031 if (ret < 0)
1032 return ret;
1033
Mattias Wallin47c16972010-09-10 17:47:56 +02001034 ab8500->chip_id = value;
Rabin Vincent62579262010-05-19 11:39:02 +02001035
Linus Walleij0f6208372012-02-20 21:42:10 +01001036 dev_info(ab8500->dev, "detected chip, %s rev. %1x.%1x\n",
1037 ab8500_version_str[ab8500->version],
1038 ab8500->chip_id >> 4,
1039 ab8500->chip_id & 0x0F);
1040
Linus Walleijd6255522012-02-20 21:42:24 +01001041 /* Configure AB8500 or AB9540 IRQ */
1042 if (is_ab9540(ab8500)) {
1043 ab8500->mask_size = AB9540_NUM_IRQ_REGS;
1044 ab8500->irq_reg_offset = ab9540_irq_regoffset;
1045 } else {
1046 ab8500->mask_size = AB8500_NUM_IRQ_REGS;
1047 ab8500->irq_reg_offset = ab8500_irq_regoffset;
1048 }
Linus Walleij2ced4452012-02-20 21:42:17 +01001049 ab8500->mask = kzalloc(ab8500->mask_size, GFP_KERNEL);
1050 if (!ab8500->mask)
1051 return -ENOMEM;
1052 ab8500->oldmask = kzalloc(ab8500->mask_size, GFP_KERNEL);
1053 if (!ab8500->oldmask) {
1054 ret = -ENOMEM;
1055 goto out_freemask;
1056 }
Mattias Walline5c238c2011-03-02 11:52:36 +01001057 /*
1058 * ab8500 has switched off due to (SWITCH_OFF_STATUS):
1059 * 0x01 Swoff bit programming
1060 * 0x02 Thermal protection activation
1061 * 0x04 Vbat lower then BattOk falling threshold
1062 * 0x08 Watchdog expired
1063 * 0x10 Non presence of 32kHz clock
1064 * 0x20 Battery level lower than power on reset threshold
1065 * 0x40 Power on key 1 pressed longer than 10 seconds
1066 * 0x80 DB8500 thermal shutdown
1067 */
1068
1069 ret = get_register_interruptible(ab8500, AB8500_RTC,
1070 AB8500_SWITCH_OFF_STATUS, &value);
1071 if (ret < 0)
1072 return ret;
1073 dev_info(ab8500->dev, "switch off status: %#x", value);
1074
Rabin Vincent62579262010-05-19 11:39:02 +02001075 if (plat && plat->init)
1076 plat->init(ab8500);
1077
1078 /* Clear and mask all interrupts */
Linus Walleij2ced4452012-02-20 21:42:17 +01001079 for (i = 0; i < ab8500->mask_size; i++) {
Linus Walleij0f6208372012-02-20 21:42:10 +01001080 /*
1081 * Interrupt register 12 doesn't exist prior to AB8500 version
1082 * 2.0
1083 */
1084 if (ab8500->irq_reg_offset[i] == 11 &&
1085 is_ab8500_1p1_or_earlier(ab8500))
Mattias Wallin92d50a42010-12-07 11:20:47 +01001086 continue;
Rabin Vincent62579262010-05-19 11:39:02 +02001087
Mattias Wallin47c16972010-09-10 17:47:56 +02001088 get_register_interruptible(ab8500, AB8500_INTERRUPT,
Linus Walleij2ced4452012-02-20 21:42:17 +01001089 AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i],
Mattias Wallin92d50a42010-12-07 11:20:47 +01001090 &value);
Mattias Wallin47c16972010-09-10 17:47:56 +02001091 set_register_interruptible(ab8500, AB8500_INTERRUPT,
Linus Walleij2ced4452012-02-20 21:42:17 +01001092 AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i], 0xff);
Rabin Vincent62579262010-05-19 11:39:02 +02001093 }
1094
Mattias Wallin47c16972010-09-10 17:47:56 +02001095 ret = abx500_register_ops(ab8500->dev, &ab8500_ops);
1096 if (ret)
Linus Walleij2ced4452012-02-20 21:42:17 +01001097 goto out_freeoldmask;
Mattias Wallin47c16972010-09-10 17:47:56 +02001098
Linus Walleij2ced4452012-02-20 21:42:17 +01001099 for (i = 0; i < ab8500->mask_size; i++)
Rabin Vincent62579262010-05-19 11:39:02 +02001100 ab8500->mask[i] = ab8500->oldmask[i] = 0xff;
1101
1102 if (ab8500->irq_base) {
1103 ret = ab8500_irq_init(ab8500);
1104 if (ret)
Linus Walleij2ced4452012-02-20 21:42:17 +01001105 goto out_freeoldmask;
Rabin Vincent62579262010-05-19 11:39:02 +02001106
1107 ret = request_threaded_irq(ab8500->irq, NULL, ab8500_irq,
Mattias Wallin4f079982010-12-02 15:10:27 +01001108 IRQF_ONESHOT | IRQF_NO_SUSPEND,
1109 "ab8500", ab8500);
Rabin Vincent62579262010-05-19 11:39:02 +02001110 if (ret)
1111 goto out_removeirq;
1112 }
1113
Linus Walleijd6255522012-02-20 21:42:24 +01001114 ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs,
1115 ARRAY_SIZE(abx500_common_devs), NULL,
1116 ab8500->irq_base);
1117
1118 if (ret)
1119 goto out_freeirq;
1120
1121 if (is_ab9540(ab8500))
1122 ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs,
1123 ARRAY_SIZE(ab9540_devs), NULL,
1124 ab8500->irq_base);
1125 else
1126 ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
1127 ARRAY_SIZE(ab9540_devs), NULL,
Rabin Vincent62579262010-05-19 11:39:02 +02001128 ab8500->irq_base);
1129 if (ret)
1130 goto out_freeirq;
1131
Linus Walleijd6255522012-02-20 21:42:24 +01001132 if (is_ab9540(ab8500))
1133 ret = sysfs_create_group(&ab8500->dev->kobj,
1134 &ab9540_attr_group);
1135 else
1136 ret = sysfs_create_group(&ab8500->dev->kobj,
1137 &ab8500_attr_group);
Mattias Wallincca69b62010-12-02 15:09:36 +01001138 if (ret)
1139 dev_err(ab8500->dev, "error creating sysfs entries\n");
Linus Walleijd6255522012-02-20 21:42:24 +01001140 else
1141 return ret;
Rabin Vincent62579262010-05-19 11:39:02 +02001142
1143out_freeirq:
Linus Walleij6d95b7f2012-02-20 21:42:03 +01001144 if (ab8500->irq_base)
Rabin Vincent62579262010-05-19 11:39:02 +02001145 free_irq(ab8500->irq, ab8500);
1146out_removeirq:
Linus Walleij6d95b7f2012-02-20 21:42:03 +01001147 if (ab8500->irq_base)
Rabin Vincent62579262010-05-19 11:39:02 +02001148 ab8500_irq_remove(ab8500);
Linus Walleij2ced4452012-02-20 21:42:17 +01001149out_freeoldmask:
1150 kfree(ab8500->oldmask);
1151out_freemask:
1152 kfree(ab8500->mask);
Linus Walleij6d95b7f2012-02-20 21:42:03 +01001153
Rabin Vincent62579262010-05-19 11:39:02 +02001154 return ret;
1155}
1156
1157int __devexit ab8500_exit(struct ab8500 *ab8500)
1158{
Linus Walleijd6255522012-02-20 21:42:24 +01001159 if (is_ab9540(ab8500))
1160 sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group);
1161 else
1162 sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
Rabin Vincent62579262010-05-19 11:39:02 +02001163 mfd_remove_devices(ab8500->dev);
1164 if (ab8500->irq_base) {
1165 free_irq(ab8500->irq, ab8500);
1166 ab8500_irq_remove(ab8500);
1167 }
Linus Walleij2ced4452012-02-20 21:42:17 +01001168 kfree(ab8500->oldmask);
1169 kfree(ab8500->mask);
Rabin Vincent62579262010-05-19 11:39:02 +02001170
1171 return 0;
1172}
1173
Mattias Wallinadceed62011-03-02 11:51:11 +01001174MODULE_AUTHOR("Mattias Wallin, Srinidhi Kasagar, Rabin Vincent");
Rabin Vincent62579262010-05-19 11:39:02 +02001175MODULE_DESCRIPTION("AB8500 MFD core");
1176MODULE_LICENSE("GPL v2");