mfd: wm831x: Convert to IORESOURCE_REG
[deliverable/linux.git] / drivers / mfd / 88pm860x-core.c
CommitLineData
bbd51b1f
HZ
1/*
2 * Base driver for Marvell 88PM8607
3 *
4 * Copyright (C) 2009 Marvell International Ltd.
5 * Haojian Zhuang <haojian.zhuang@marvell.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/kernel.h>
13#include <linux/module.h>
5c42e8c4 14#include <linux/i2c.h>
2afa62ea 15#include <linux/irq.h>
bbd51b1f
HZ
16#include <linux/interrupt.h>
17#include <linux/platform_device.h>
18#include <linux/mfd/core.h>
53dbab7a 19#include <linux/mfd/88pm860x.h>
22aad001 20#include <linux/regulator/machine.h>
bbd51b1f 21
2afa62ea
HZ
22#define INT_STATUS_NUM 3
23
c10c2aab
MB
24static struct resource io_parent = {
25 .start = 0,
26 .end = 0xffffffff,
27 .flags = IORESOURCE_IO,
28};
29
a5156f1a 30static struct resource bk_resources[] __devinitdata = {
c10c2aab
MB
31 {PM8606_BACKLIGHT1, PM8606_BACKLIGHT1, "backlight-0", IORESOURCE_IO,
32 &io_parent,},
33 {PM8606_BACKLIGHT2, PM8606_BACKLIGHT2, "backlight-1", IORESOURCE_IO,
34 &io_parent,},
35 {PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_IO,
36 &io_parent,},
a16122bc 37};
adb70483 38
a5156f1a 39static struct resource led_resources[] __devinitdata = {
c10c2aab
MB
40 {PM8606_LED1_RED, PM8606_LED1_RED, "led0-red", IORESOURCE_IO,
41 &io_parent,},
42 {PM8606_LED1_GREEN, PM8606_LED1_GREEN, "led0-green", IORESOURCE_IO,
43 &io_parent,},
44 {PM8606_LED1_BLUE, PM8606_LED1_BLUE, "led0-blue", IORESOURCE_IO,
45 &io_parent,},
46 {PM8606_LED2_RED, PM8606_LED2_RED, "led1-red", IORESOURCE_IO,
47 &io_parent,},
48 {PM8606_LED2_GREEN, PM8606_LED2_GREEN, "led1-green", IORESOURCE_IO,
49 &io_parent,},
50 {PM8606_LED2_BLUE, PM8606_LED2_BLUE, "led1-blue", IORESOURCE_IO,
51 &io_parent,},
3154c344
HZ
52};
53
a5156f1a 54static struct resource regulator_resources[] __devinitdata = {
c10c2aab
MB
55 {PM8607_ID_BUCK1, PM8607_ID_BUCK1, "buck-1", IORESOURCE_IO,
56 &io_parent,},
57 {PM8607_ID_BUCK2, PM8607_ID_BUCK2, "buck-2", IORESOURCE_IO,
58 &io_parent,},
59 {PM8607_ID_BUCK3, PM8607_ID_BUCK3, "buck-3", IORESOURCE_IO,
60 &io_parent,},
61 {PM8607_ID_LDO1, PM8607_ID_LDO1, "ldo-01", IORESOURCE_IO,
62 &io_parent,},
63 {PM8607_ID_LDO2, PM8607_ID_LDO2, "ldo-02", IORESOURCE_IO,
64 &io_parent,},
65 {PM8607_ID_LDO3, PM8607_ID_LDO3, "ldo-03", IORESOURCE_IO,
66 &io_parent,},
67 {PM8607_ID_LDO4, PM8607_ID_LDO4, "ldo-04", IORESOURCE_IO,
68 &io_parent,},
69 {PM8607_ID_LDO5, PM8607_ID_LDO5, "ldo-05", IORESOURCE_IO,
70 &io_parent,},
71 {PM8607_ID_LDO6, PM8607_ID_LDO6, "ldo-06", IORESOURCE_IO,
72 &io_parent,},
73 {PM8607_ID_LDO7, PM8607_ID_LDO7, "ldo-07", IORESOURCE_IO,
74 &io_parent,},
75 {PM8607_ID_LDO8, PM8607_ID_LDO8, "ldo-08", IORESOURCE_IO,
76 &io_parent,},
77 {PM8607_ID_LDO9, PM8607_ID_LDO9, "ldo-09", IORESOURCE_IO,
78 &io_parent,},
79 {PM8607_ID_LDO10, PM8607_ID_LDO10, "ldo-10", IORESOURCE_IO,
80 &io_parent,},
81 {PM8607_ID_LDO11, PM8607_ID_LDO11, "ldo-11", IORESOURCE_IO,
82 &io_parent,},
83 {PM8607_ID_LDO12, PM8607_ID_LDO12, "ldo-12", IORESOURCE_IO,
84 &io_parent,},
85 {PM8607_ID_LDO13, PM8607_ID_LDO13, "ldo-13", IORESOURCE_IO,
86 &io_parent,},
87 {PM8607_ID_LDO14, PM8607_ID_LDO14, "ldo-14", IORESOURCE_IO,
88 &io_parent,},
89 {PM8607_ID_LDO15, PM8607_ID_LDO15, "ldo-15", IORESOURCE_IO,
90 &io_parent,},
22aad001
HZ
91};
92
a5156f1a 93static struct resource touch_resources[] __devinitdata = {
c9f560b3
HZ
94 {PM8607_IRQ_PEN, PM8607_IRQ_PEN, "touch", IORESOURCE_IRQ,},
95};
96
a5156f1a 97static struct resource onkey_resources[] __devinitdata = {
c9f560b3
HZ
98 {PM8607_IRQ_ONKEY, PM8607_IRQ_ONKEY, "onkey", IORESOURCE_IRQ,},
99};
100
a5156f1a 101static struct resource codec_resources[] __devinitdata = {
c9f560b3
HZ
102 /* Headset microphone insertion or removal */
103 {PM8607_IRQ_MICIN, PM8607_IRQ_MICIN, "micin", IORESOURCE_IRQ,},
104 /* Hook-switch press or release */
105 {PM8607_IRQ_HOOK, PM8607_IRQ_HOOK, "hook", IORESOURCE_IRQ,},
106 /* Headset insertion or removal */
107 {PM8607_IRQ_HEADSET, PM8607_IRQ_HEADSET, "headset", IORESOURCE_IRQ,},
108 /* Audio short */
109 {PM8607_IRQ_AUDIO_SHORT, PM8607_IRQ_AUDIO_SHORT, "audio-short", IORESOURCE_IRQ,},
110};
111
a5156f1a 112static struct resource battery_resources[] __devinitdata = {
c9f560b3
HZ
113 {PM8607_IRQ_CC, PM8607_IRQ_CC, "columb counter", IORESOURCE_IRQ,},
114 {PM8607_IRQ_BAT, PM8607_IRQ_BAT, "battery", IORESOURCE_IRQ,},
115};
116
a5156f1a 117static struct resource charger_resources[] __devinitdata = {
c9f560b3
HZ
118 {PM8607_IRQ_CHG, PM8607_IRQ_CHG, "charger detect", IORESOURCE_IRQ,},
119 {PM8607_IRQ_CHG_DONE, PM8607_IRQ_CHG_DONE, "charging done", IORESOURCE_IRQ,},
120 {PM8607_IRQ_CHG_FAULT, PM8607_IRQ_CHG_FAULT, "charging timeout", IORESOURCE_IRQ,},
121 {PM8607_IRQ_GPADC1, PM8607_IRQ_GPADC1, "battery temperature", IORESOURCE_IRQ,},
122 {PM8607_IRQ_VBAT, PM8607_IRQ_VBAT, "battery voltage", IORESOURCE_IRQ,},
123 {PM8607_IRQ_VCHG, PM8607_IRQ_VCHG, "vchg voltage", IORESOURCE_IRQ,},
124};
125
2573f6d3 126static struct resource preg_resources[] __devinitdata = {
c10c2aab
MB
127 {PM8606_ID_PREG, PM8606_ID_PREG, "preg", IORESOURCE_IO,
128 &io_parent,},
2573f6d3
JZ
129};
130
008b3040 131static struct resource rtc_resources[] __devinitdata = {
c10c2aab 132 {PM8607_IRQ_RTC, PM8607_IRQ_RTC, "rtc", IORESOURCE_IRQ, &io_parent,},
008b3040
HZ
133};
134
a5156f1a 135static struct mfd_cell bk_devs[] = {
adb70483
HZ
136 {"88pm860x-backlight", 0,},
137 {"88pm860x-backlight", 1,},
138 {"88pm860x-backlight", 2,},
139};
140
a5156f1a 141static struct mfd_cell led_devs[] = {
3154c344
HZ
142 {"88pm860x-led", 0,},
143 {"88pm860x-led", 1,},
144 {"88pm860x-led", 2,},
145 {"88pm860x-led", 3,},
146 {"88pm860x-led", 4,},
147 {"88pm860x-led", 5,},
a16122bc
HZ
148};
149
a5156f1a 150static struct mfd_cell regulator_devs[] = {
22aad001
HZ
151 {"88pm860x-regulator", 0,},
152 {"88pm860x-regulator", 1,},
153 {"88pm860x-regulator", 2,},
154 {"88pm860x-regulator", 3,},
155 {"88pm860x-regulator", 4,},
156 {"88pm860x-regulator", 5,},
157 {"88pm860x-regulator", 6,},
158 {"88pm860x-regulator", 7,},
159 {"88pm860x-regulator", 8,},
160 {"88pm860x-regulator", 9,},
161 {"88pm860x-regulator", 10,},
162 {"88pm860x-regulator", 11,},
163 {"88pm860x-regulator", 12,},
164 {"88pm860x-regulator", 13,},
165 {"88pm860x-regulator", 14,},
166 {"88pm860x-regulator", 15,},
167 {"88pm860x-regulator", 16,},
168 {"88pm860x-regulator", 17,},
169};
170
a5156f1a 171static struct mfd_cell touch_devs[] = {
c9f560b3 172 {"88pm860x-touch", -1,},
a16122bc
HZ
173};
174
a5156f1a 175static struct mfd_cell onkey_devs[] = {
c9f560b3 176 {"88pm860x-onkey", -1,},
a16122bc 177};
bbd51b1f 178
a5156f1a 179static struct mfd_cell codec_devs[] = {
c9f560b3 180 {"88pm860x-codec", -1,},
2afa62ea
HZ
181};
182
2573f6d3
JZ
183static struct regulator_consumer_supply preg_supply[] = {
184 REGULATOR_SUPPLY("preg", "charger-manager"),
185};
186
187static struct regulator_init_data preg_init_data = {
188 .num_consumer_supplies = ARRAY_SIZE(preg_supply),
189 .consumer_supplies = &preg_supply[0],
190};
191
2afa62ea 192static struct mfd_cell power_devs[] = {
c9f560b3
HZ
193 {"88pm860x-battery", -1,},
194 {"88pm860x-charger", -1,},
2573f6d3 195 {"88pm860x-preg", -1,},
2c36af7b
HZ
196};
197
008b3040
HZ
198static struct mfd_cell rtc_devs[] = {
199 {"88pm860x-rtc", -1,},
200};
201
2c36af7b 202
2afa62ea
HZ
203struct pm860x_irq_data {
204 int reg;
205 int mask_reg;
206 int enable; /* enable or not */
207 int offs; /* bit offset in mask register */
208};
5c42e8c4 209
2afa62ea
HZ
210static struct pm860x_irq_data pm860x_irqs[] = {
211 [PM8607_IRQ_ONKEY] = {
212 .reg = PM8607_INT_STATUS1,
213 .mask_reg = PM8607_INT_MASK_1,
214 .offs = 1 << 0,
215 },
216 [PM8607_IRQ_EXTON] = {
217 .reg = PM8607_INT_STATUS1,
218 .mask_reg = PM8607_INT_MASK_1,
219 .offs = 1 << 1,
220 },
221 [PM8607_IRQ_CHG] = {
222 .reg = PM8607_INT_STATUS1,
223 .mask_reg = PM8607_INT_MASK_1,
224 .offs = 1 << 2,
225 },
226 [PM8607_IRQ_BAT] = {
227 .reg = PM8607_INT_STATUS1,
228 .mask_reg = PM8607_INT_MASK_1,
229 .offs = 1 << 3,
230 },
231 [PM8607_IRQ_RTC] = {
232 .reg = PM8607_INT_STATUS1,
233 .mask_reg = PM8607_INT_MASK_1,
234 .offs = 1 << 4,
235 },
236 [PM8607_IRQ_CC] = {
237 .reg = PM8607_INT_STATUS1,
238 .mask_reg = PM8607_INT_MASK_1,
239 .offs = 1 << 5,
240 },
241 [PM8607_IRQ_VBAT] = {
242 .reg = PM8607_INT_STATUS2,
243 .mask_reg = PM8607_INT_MASK_2,
244 .offs = 1 << 0,
245 },
246 [PM8607_IRQ_VCHG] = {
247 .reg = PM8607_INT_STATUS2,
248 .mask_reg = PM8607_INT_MASK_2,
249 .offs = 1 << 1,
250 },
251 [PM8607_IRQ_VSYS] = {
252 .reg = PM8607_INT_STATUS2,
253 .mask_reg = PM8607_INT_MASK_2,
254 .offs = 1 << 2,
255 },
256 [PM8607_IRQ_TINT] = {
257 .reg = PM8607_INT_STATUS2,
258 .mask_reg = PM8607_INT_MASK_2,
259 .offs = 1 << 3,
260 },
261 [PM8607_IRQ_GPADC0] = {
262 .reg = PM8607_INT_STATUS2,
263 .mask_reg = PM8607_INT_MASK_2,
264 .offs = 1 << 4,
265 },
266 [PM8607_IRQ_GPADC1] = {
267 .reg = PM8607_INT_STATUS2,
268 .mask_reg = PM8607_INT_MASK_2,
269 .offs = 1 << 5,
270 },
271 [PM8607_IRQ_GPADC2] = {
272 .reg = PM8607_INT_STATUS2,
273 .mask_reg = PM8607_INT_MASK_2,
274 .offs = 1 << 6,
275 },
276 [PM8607_IRQ_GPADC3] = {
277 .reg = PM8607_INT_STATUS2,
278 .mask_reg = PM8607_INT_MASK_2,
279 .offs = 1 << 7,
280 },
281 [PM8607_IRQ_AUDIO_SHORT] = {
282 .reg = PM8607_INT_STATUS3,
283 .mask_reg = PM8607_INT_MASK_3,
284 .offs = 1 << 0,
285 },
286 [PM8607_IRQ_PEN] = {
287 .reg = PM8607_INT_STATUS3,
288 .mask_reg = PM8607_INT_MASK_3,
289 .offs = 1 << 1,
290 },
291 [PM8607_IRQ_HEADSET] = {
292 .reg = PM8607_INT_STATUS3,
293 .mask_reg = PM8607_INT_MASK_3,
294 .offs = 1 << 2,
295 },
296 [PM8607_IRQ_HOOK] = {
297 .reg = PM8607_INT_STATUS3,
298 .mask_reg = PM8607_INT_MASK_3,
299 .offs = 1 << 3,
300 },
301 [PM8607_IRQ_MICIN] = {
302 .reg = PM8607_INT_STATUS3,
303 .mask_reg = PM8607_INT_MASK_3,
304 .offs = 1 << 4,
305 },
306 [PM8607_IRQ_CHG_FAIL] = {
307 .reg = PM8607_INT_STATUS3,
308 .mask_reg = PM8607_INT_MASK_3,
309 .offs = 1 << 5,
310 },
311 [PM8607_IRQ_CHG_DONE] = {
312 .reg = PM8607_INT_STATUS3,
313 .mask_reg = PM8607_INT_MASK_3,
314 .offs = 1 << 6,
315 },
316 [PM8607_IRQ_CHG_FAULT] = {
317 .reg = PM8607_INT_STATUS3,
318 .mask_reg = PM8607_INT_MASK_3,
319 .offs = 1 << 7,
320 },
321};
5c42e8c4 322
2afa62ea 323static irqreturn_t pm860x_irq(int irq, void *data)
5c42e8c4 324{
5c42e8c4 325 struct pm860x_chip *chip = data;
2afa62ea
HZ
326 struct pm860x_irq_data *irq_data;
327 struct i2c_client *i2c;
328 int read_reg = -1, value = 0;
329 int i;
330
331 i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
332 for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) {
333 irq_data = &pm860x_irqs[i];
334 if (read_reg != irq_data->reg) {
335 read_reg = irq_data->reg;
336 value = pm860x_reg_read(i2c, irq_data->reg);
5c42e8c4 337 }
2afa62ea
HZ
338 if (value & irq_data->enable)
339 handle_nested_irq(chip->irq_base + i);
5c42e8c4 340 }
5c42e8c4
HZ
341 return IRQ_HANDLED;
342}
343
49f89d9a 344static void pm860x_irq_lock(struct irq_data *data)
53dbab7a 345{
49f89d9a 346 struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
5c42e8c4
HZ
347
348 mutex_lock(&chip->irq_lock);
53dbab7a
HZ
349}
350
49f89d9a 351static void pm860x_irq_sync_unlock(struct irq_data *data)
bbd51b1f 352{
49f89d9a 353 struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
2afa62ea
HZ
354 struct pm860x_irq_data *irq_data;
355 struct i2c_client *i2c;
356 static unsigned char cached[3] = {0x0, 0x0, 0x0};
357 unsigned char mask[3];
358 int i;
359
360 i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
361 /* Load cached value. In initial, all IRQs are masked */
362 for (i = 0; i < 3; i++)
363 mask[i] = cached[i];
364 for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) {
365 irq_data = &pm860x_irqs[i];
366 switch (irq_data->mask_reg) {
367 case PM8607_INT_MASK_1:
368 mask[0] &= ~irq_data->offs;
369 mask[0] |= irq_data->enable;
370 break;
371 case PM8607_INT_MASK_2:
372 mask[1] &= ~irq_data->offs;
373 mask[1] |= irq_data->enable;
374 break;
375 case PM8607_INT_MASK_3:
376 mask[2] &= ~irq_data->offs;
377 mask[2] |= irq_data->enable;
378 break;
379 default:
380 dev_err(chip->dev, "wrong IRQ\n");
381 break;
382 }
383 }
384 /* update mask into registers */
385 for (i = 0; i < 3; i++) {
386 if (mask[i] != cached[i]) {
387 cached[i] = mask[i];
388 pm860x_reg_write(i2c, PM8607_INT_MASK_1 + i, mask[i]);
389 }
390 }
5c42e8c4 391
5c42e8c4 392 mutex_unlock(&chip->irq_lock);
2afa62ea 393}
5c42e8c4 394
49f89d9a 395static void pm860x_irq_enable(struct irq_data *data)
2afa62ea 396{
49f89d9a
MB
397 struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
398 pm860x_irqs[data->irq - chip->irq_base].enable
399 = pm860x_irqs[data->irq - chip->irq_base].offs;
5c42e8c4 400}
2afa62ea 401
49f89d9a 402static void pm860x_irq_disable(struct irq_data *data)
2afa62ea 403{
49f89d9a
MB
404 struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
405 pm860x_irqs[data->irq - chip->irq_base].enable = 0;
2afa62ea
HZ
406}
407
408static struct irq_chip pm860x_irq_chip = {
409 .name = "88pm860x",
49f89d9a
MB
410 .irq_bus_lock = pm860x_irq_lock,
411 .irq_bus_sync_unlock = pm860x_irq_sync_unlock,
412 .irq_enable = pm860x_irq_enable,
413 .irq_disable = pm860x_irq_disable,
2afa62ea 414};
5c42e8c4 415
a16122bc
HZ
416static int __devinit device_gpadc_init(struct pm860x_chip *chip,
417 struct pm860x_platform_data *pdata)
418{
419 struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \
420 : chip->companion;
eb6e8ddf
DC
421 int data;
422 int ret;
a16122bc
HZ
423
424 /* initialize GPADC without activating it */
425
eb6e8ddf
DC
426 if (!pdata || !pdata->touch)
427 return -EINVAL;
428
429 /* set GPADC MISC1 register */
430 data = 0;
431 data |= (pdata->touch->gpadc_prebias << 1) & PM8607_GPADC_PREBIAS_MASK;
432 data |= (pdata->touch->slot_cycle << 3) & PM8607_GPADC_SLOT_CYCLE_MASK;
433 data |= (pdata->touch->off_scale << 5) & PM8607_GPADC_OFF_SCALE_MASK;
434 data |= (pdata->touch->sw_cal << 7) & PM8607_GPADC_SW_CAL_MASK;
435 if (data) {
436 ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data);
437 if (ret < 0)
438 goto out;
a16122bc 439 }
eb6e8ddf
DC
440 /* set tsi prebias time */
441 if (pdata->touch->tsi_prebias) {
442 data = pdata->touch->tsi_prebias;
443 ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data);
444 if (ret < 0)
445 goto out;
446 }
447 /* set prebias & prechg time of pen detect */
448 data = 0;
449 data |= pdata->touch->pen_prebias & PM8607_PD_PREBIAS_MASK;
450 data |= (pdata->touch->pen_prechg << 5) & PM8607_PD_PRECHG_MASK;
451 if (data) {
452 ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data);
453 if (ret < 0)
454 goto out;
a16122bc 455 }
eb6e8ddf
DC
456
457 ret = pm860x_set_bits(i2c, PM8607_GPADC_MISC1,
458 PM8607_GPADC_EN, PM8607_GPADC_EN);
a16122bc
HZ
459out:
460 return ret;
461}
462
5c42e8c4
HZ
463static int __devinit device_irq_init(struct pm860x_chip *chip,
464 struct pm860x_platform_data *pdata)
465{
466 struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \
467 : chip->companion;
468 unsigned char status_buf[INT_STATUS_NUM];
2afa62ea 469 unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
2afa62ea
HZ
470 int i, data, mask, ret = -EINVAL;
471 int __irq;
5c42e8c4 472
2afa62ea
HZ
473 if (!pdata || !pdata->irq_base) {
474 dev_warn(chip->dev, "No interrupt support on IRQ base\n");
475 return -EINVAL;
476 }
5c42e8c4
HZ
477
478 mask = PM8607_B0_MISC1_INV_INT | PM8607_B0_MISC1_INT_CLEAR
479 | PM8607_B0_MISC1_INT_MASK;
480 data = 0;
481 chip->irq_mode = 0;
482 if (pdata && pdata->irq_mode) {
483 /*
484 * irq_mode defines the way of clearing interrupt. If it's 1,
485 * clear IRQ by write. Otherwise, clear it by read.
486 * This control bit is valid from 88PM8607 B0 steping.
487 */
488 data |= PM8607_B0_MISC1_INT_CLEAR;
489 chip->irq_mode = 1;
490 }
491 ret = pm860x_set_bits(i2c, PM8607_B0_MISC1, mask, data);
492 if (ret < 0)
493 goto out;
494
495 /* mask all IRQs */
496 memset(status_buf, 0, INT_STATUS_NUM);
497 ret = pm860x_bulk_write(i2c, PM8607_INT_MASK_1,
498 INT_STATUS_NUM, status_buf);
499 if (ret < 0)
500 goto out;
501
502 if (chip->irq_mode) {
503 /* clear interrupt status by write */
504 memset(status_buf, 0xFF, INT_STATUS_NUM);
505 ret = pm860x_bulk_write(i2c, PM8607_INT_STATUS1,
506 INT_STATUS_NUM, status_buf);
507 } else {
508 /* clear interrupt status by read */
509 ret = pm860x_bulk_read(i2c, PM8607_INT_STATUS1,
510 INT_STATUS_NUM, status_buf);
511 }
512 if (ret < 0)
513 goto out;
514
2afa62ea
HZ
515 mutex_init(&chip->irq_lock);
516 chip->irq_base = pdata->irq_base;
517 chip->core_irq = i2c->irq;
518 if (!chip->core_irq)
5c42e8c4 519 goto out;
2afa62ea 520
2afa62ea
HZ
521 /* register IRQ by genirq */
522 for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) {
523 __irq = i + chip->irq_base;
d5bb1221
TG
524 irq_set_chip_data(__irq, chip);
525 irq_set_chip_and_handler(__irq, &pm860x_irq_chip,
2afa62ea 526 handle_edge_irq);
d5bb1221 527 irq_set_nested_thread(__irq, 1);
2afa62ea
HZ
528#ifdef CONFIG_ARM
529 set_irq_flags(__irq, IRQF_VALID);
530#else
d5bb1221 531 irq_set_noprobe(__irq);
2afa62ea 532#endif
5c42e8c4 533 }
2afa62ea
HZ
534
535 ret = request_threaded_irq(chip->core_irq, NULL, pm860x_irq, flags,
536 "88pm860x", chip);
537 if (ret) {
538 dev_err(chip->dev, "Failed to request IRQ: %d\n", ret);
539 chip->core_irq = 0;
540 }
541
5c42e8c4
HZ
542 return 0;
543out:
2afa62ea 544 chip->core_irq = 0;
5c42e8c4
HZ
545 return ret;
546}
547
872c1b14 548static void device_irq_exit(struct pm860x_chip *chip)
5c42e8c4 549{
2afa62ea
HZ
550 if (chip->core_irq)
551 free_irq(chip->core_irq, chip);
5c42e8c4
HZ
552}
553
23de435a
JZ
554int pm8606_osc_enable(struct pm860x_chip *chip, unsigned short client)
555{
556 int ret = -EIO;
557 struct i2c_client *i2c = (chip->id == CHIP_PM8606) ?
558 chip->client : chip->companion;
559
560 dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client);
561 dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n",
562 __func__, chip->osc_vote,
563 chip->osc_status);
564
565 mutex_lock(&chip->osc_lock);
566 /* Update voting status */
567 chip->osc_vote |= client;
568 /* If reference group is off - turn on*/
569 if (chip->osc_status != PM8606_REF_GP_OSC_ON) {
570 chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN;
571 /* Enable Reference group Vsys */
572 if (pm860x_set_bits(i2c, PM8606_VSYS,
573 PM8606_VSYS_EN, PM8606_VSYS_EN))
574 goto out;
575
576 /*Enable Internal Oscillator */
577 if (pm860x_set_bits(i2c, PM8606_MISC,
578 PM8606_MISC_OSC_EN, PM8606_MISC_OSC_EN))
579 goto out;
580 /* Update status (only if writes succeed) */
581 chip->osc_status = PM8606_REF_GP_OSC_ON;
582 }
583 mutex_unlock(&chip->osc_lock);
584
585 dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n",
586 __func__, chip->osc_vote,
587 chip->osc_status, ret);
588 return 0;
589out:
590 mutex_unlock(&chip->osc_lock);
591 return ret;
592}
2f5f89be 593EXPORT_SYMBOL(pm8606_osc_enable);
23de435a
JZ
594
595int pm8606_osc_disable(struct pm860x_chip *chip, unsigned short client)
596{
597 int ret = -EIO;
598 struct i2c_client *i2c = (chip->id == CHIP_PM8606) ?
599 chip->client : chip->companion;
600
601 dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client);
602 dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n",
603 __func__, chip->osc_vote,
604 chip->osc_status);
605
606 mutex_lock(&chip->osc_lock);
607 /*Update voting status */
608 chip->osc_vote &= ~(client);
609 /* If reference group is off and this is the last client to release
610 * - turn off */
611 if ((chip->osc_status != PM8606_REF_GP_OSC_OFF) &&
612 (chip->osc_vote == REF_GP_NO_CLIENTS)) {
613 chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN;
614 /* Disable Reference group Vsys */
615 if (pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0))
616 goto out;
617 /* Disable Internal Oscillator */
618 if (pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0))
619 goto out;
620 chip->osc_status = PM8606_REF_GP_OSC_OFF;
621 }
622 mutex_unlock(&chip->osc_lock);
623
624 dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n",
625 __func__, chip->osc_vote,
626 chip->osc_status, ret);
627 return 0;
628out:
629 mutex_unlock(&chip->osc_lock);
630 return ret;
631}
2f5f89be 632EXPORT_SYMBOL(pm8606_osc_disable);
23de435a
JZ
633
634static void __devinit device_osc_init(struct i2c_client *i2c)
635{
636 struct pm860x_chip *chip = i2c_get_clientdata(i2c);
637
638 mutex_init(&chip->osc_lock);
639 /* init portofino reference group voting and status */
640 /* Disable Reference group Vsys */
641 pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0);
642 /* Disable Internal Oscillator */
643 pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0);
644
645 chip->osc_vote = REF_GP_NO_CLIENTS;
646 chip->osc_status = PM8606_REF_GP_OSC_OFF;
647}
648
adb70483 649static void __devinit device_bk_init(struct pm860x_chip *chip,
adb70483
HZ
650 struct pm860x_platform_data *pdata)
651{
652 int ret;
653 int i, j, id;
654
655 if ((pdata == NULL) || (pdata->backlight == NULL))
656 return;
657
658 if (pdata->num_backlights > ARRAY_SIZE(bk_devs))
659 pdata->num_backlights = ARRAY_SIZE(bk_devs);
660
661 for (i = 0; i < pdata->num_backlights; i++) {
f5fb758d
HZ
662 bk_devs[i].platform_data = &pdata->backlight[i];
663 bk_devs[i].pdata_size = sizeof(struct pm860x_backlight_pdata);
adb70483
HZ
664
665 for (j = 0; j < ARRAY_SIZE(bk_devs); j++) {
666 id = bk_resources[j].start;
f5fb758d 667 if (pdata->backlight[i].flags != id)
adb70483
HZ
668 continue;
669
670 bk_devs[i].num_resources = 1;
671 bk_devs[i].resources = &bk_resources[j];
672 ret = mfd_add_devices(chip->dev, 0,
673 &bk_devs[i], 1,
674 &bk_resources[j], 0);
675 if (ret < 0) {
676 dev_err(chip->dev, "Failed to add "
677 "backlight subdev\n");
678 return;
679 }
680 }
681 }
682}
683
3154c344 684static void __devinit device_led_init(struct pm860x_chip *chip,
3154c344 685 struct pm860x_platform_data *pdata)
5c42e8c4 686{
a16122bc 687 int ret;
3154c344 688 int i, j, id;
a16122bc 689
3154c344
HZ
690 if ((pdata == NULL) || (pdata->led == NULL))
691 return;
692
693 if (pdata->num_leds > ARRAY_SIZE(led_devs))
694 pdata->num_leds = ARRAY_SIZE(led_devs);
695
696 for (i = 0; i < pdata->num_leds; i++) {
f5fb758d
HZ
697 led_devs[i].platform_data = &pdata->led[i];
698 led_devs[i].pdata_size = sizeof(struct pm860x_led_pdata);
3154c344
HZ
699
700 for (j = 0; j < ARRAY_SIZE(led_devs); j++) {
701 id = led_resources[j].start;
f5fb758d 702 if (pdata->led[i].flags != id)
3154c344
HZ
703 continue;
704
705 led_devs[i].num_resources = 1;
706 led_devs[i].resources = &led_resources[j],
707 ret = mfd_add_devices(chip->dev, 0,
708 &led_devs[i], 1,
709 &led_resources[j], 0);
710 if (ret < 0) {
711 dev_err(chip->dev, "Failed to add "
712 "led subdev\n");
713 return;
714 }
a16122bc
HZ
715 }
716 }
5c42e8c4
HZ
717}
718
22aad001 719static void __devinit device_regulator_init(struct pm860x_chip *chip,
22aad001
HZ
720 struct pm860x_platform_data *pdata)
721{
722 struct regulator_init_data *initdata;
723 int ret;
586e1a17 724 int i, seq;
22aad001
HZ
725
726 if ((pdata == NULL) || (pdata->regulator == NULL))
727 return;
728
729 if (pdata->num_regulators > ARRAY_SIZE(regulator_devs))
730 pdata->num_regulators = ARRAY_SIZE(regulator_devs);
731
586e1a17 732 for (i = 0, seq = -1; i < pdata->num_regulators; i++) {
22aad001 733 initdata = &pdata->regulator[i];
586e1a17
HZ
734 seq = *(unsigned int *)initdata->driver_data;
735 if ((seq < 0) || (seq > PM8607_ID_RG_MAX)) {
736 dev_err(chip->dev, "Wrong ID(%d) on regulator(%s)\n",
737 seq, initdata->constraints.name);
22aad001
HZ
738 goto out;
739 }
f5fb758d
HZ
740 regulator_devs[i].platform_data = &pdata->regulator[i];
741 regulator_devs[i].pdata_size = sizeof(struct regulator_init_data);
22aad001 742 regulator_devs[i].num_resources = 1;
586e1a17 743 regulator_devs[i].resources = &regulator_resources[seq];
22aad001
HZ
744
745 ret = mfd_add_devices(chip->dev, 0, &regulator_devs[i], 1,
586e1a17 746 &regulator_resources[seq], 0);
22aad001
HZ
747 if (ret < 0) {
748 dev_err(chip->dev, "Failed to add regulator subdev\n");
749 goto out;
750 }
751 }
752out:
753 return;
754}
755
008b3040 756static void __devinit device_rtc_init(struct pm860x_chip *chip,
008b3040
HZ
757 struct pm860x_platform_data *pdata)
758{
759 int ret;
760
761 if ((pdata == NULL))
762 return;
763
764 rtc_devs[0].platform_data = pdata->rtc;
765 rtc_devs[0].pdata_size = sizeof(struct pm860x_rtc_pdata);
766 rtc_devs[0].num_resources = ARRAY_SIZE(rtc_resources);
767 rtc_devs[0].resources = &rtc_resources[0];
768 ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
769 ARRAY_SIZE(rtc_devs), &rtc_resources[0],
770 chip->irq_base);
771 if (ret < 0)
772 dev_err(chip->dev, "Failed to add rtc subdev\n");
773}
774
c9f560b3 775static void __devinit device_touch_init(struct pm860x_chip *chip,
c9f560b3
HZ
776 struct pm860x_platform_data *pdata)
777{
778 int ret;
779
f5fb758d 780 if (pdata == NULL)
c9f560b3
HZ
781 return;
782
f5fb758d
HZ
783 touch_devs[0].platform_data = pdata->touch;
784 touch_devs[0].pdata_size = sizeof(struct pm860x_touch_pdata);
c9f560b3
HZ
785 touch_devs[0].num_resources = ARRAY_SIZE(touch_resources);
786 touch_devs[0].resources = &touch_resources[0];
787 ret = mfd_add_devices(chip->dev, 0, &touch_devs[0],
788 ARRAY_SIZE(touch_devs), &touch_resources[0],
789 chip->irq_base);
790 if (ret < 0)
791 dev_err(chip->dev, "Failed to add touch subdev\n");
792}
793
794static void __devinit device_power_init(struct pm860x_chip *chip,
c9f560b3
HZ
795 struct pm860x_platform_data *pdata)
796{
797 int ret;
798
f5fb758d 799 if (pdata == NULL)
c9f560b3
HZ
800 return;
801
f5fb758d
HZ
802 power_devs[0].platform_data = pdata->power;
803 power_devs[0].pdata_size = sizeof(struct pm860x_power_pdata);
c9f560b3
HZ
804 power_devs[0].num_resources = ARRAY_SIZE(battery_resources);
805 power_devs[0].resources = &battery_resources[0],
806 ret = mfd_add_devices(chip->dev, 0, &power_devs[0], 1,
807 &battery_resources[0], chip->irq_base);
808 if (ret < 0)
809 dev_err(chip->dev, "Failed to add battery subdev\n");
810
f5fb758d
HZ
811 power_devs[1].platform_data = pdata->power;
812 power_devs[1].pdata_size = sizeof(struct pm860x_power_pdata);
c9f560b3
HZ
813 power_devs[1].num_resources = ARRAY_SIZE(charger_resources);
814 power_devs[1].resources = &charger_resources[0],
815 ret = mfd_add_devices(chip->dev, 0, &power_devs[1], 1,
816 &charger_resources[0], chip->irq_base);
817 if (ret < 0)
818 dev_err(chip->dev, "Failed to add charger subdev\n");
2573f6d3
JZ
819
820 power_devs[2].platform_data = &preg_init_data;
821 power_devs[2].pdata_size = sizeof(struct regulator_init_data);
822 power_devs[2].num_resources = ARRAY_SIZE(preg_resources);
823 power_devs[2].resources = &preg_resources[0],
824 ret = mfd_add_devices(chip->dev, 0, &power_devs[2], 1,
825 &preg_resources[0], chip->irq_base);
826 if (ret < 0)
827 dev_err(chip->dev, "Failed to add preg subdev\n");
c9f560b3
HZ
828}
829
830static void __devinit device_onkey_init(struct pm860x_chip *chip,
c9f560b3
HZ
831 struct pm860x_platform_data *pdata)
832{
833 int ret;
834
835 onkey_devs[0].num_resources = ARRAY_SIZE(onkey_resources);
836 onkey_devs[0].resources = &onkey_resources[0],
837 ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0],
838 ARRAY_SIZE(onkey_devs), &onkey_resources[0],
839 chip->irq_base);
840 if (ret < 0)
841 dev_err(chip->dev, "Failed to add onkey subdev\n");
842}
843
844static void __devinit device_codec_init(struct pm860x_chip *chip,
c9f560b3
HZ
845 struct pm860x_platform_data *pdata)
846{
847 int ret;
848
849 codec_devs[0].num_resources = ARRAY_SIZE(codec_resources);
850 codec_devs[0].resources = &codec_resources[0],
851 ret = mfd_add_devices(chip->dev, 0, &codec_devs[0],
852 ARRAY_SIZE(codec_devs), &codec_resources[0], 0);
853 if (ret < 0)
854 dev_err(chip->dev, "Failed to add codec subdev\n");
855}
856
5c42e8c4
HZ
857static void __devinit device_8607_init(struct pm860x_chip *chip,
858 struct i2c_client *i2c,
859 struct pm860x_platform_data *pdata)
860{
a16122bc 861 int data, ret;
bbd51b1f 862
53dbab7a 863 ret = pm860x_reg_read(i2c, PM8607_CHIP_ID);
bbd51b1f
HZ
864 if (ret < 0) {
865 dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
866 goto out;
867 }
38b34052
HZ
868 switch (ret & PM8607_VERSION_MASK) {
869 case 0x40:
870 case 0x50:
bbd51b1f
HZ
871 dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected\n",
872 ret);
38b34052
HZ
873 break;
874 default:
bbd51b1f
HZ
875 dev_err(chip->dev, "Failed to detect Marvell 88PM8607. "
876 "Chip ID: %02x\n", ret);
877 goto out;
878 }
bbd51b1f 879
53dbab7a 880 ret = pm860x_reg_read(i2c, PM8607_BUCK3);
bbd51b1f
HZ
881 if (ret < 0) {
882 dev_err(chip->dev, "Failed to read BUCK3 register: %d\n", ret);
883 goto out;
884 }
885 if (ret & PM8607_BUCK3_DOUBLE)
886 chip->buck3_double = 1;
887
5c42e8c4 888 ret = pm860x_reg_read(i2c, PM8607_B0_MISC1);
bbd51b1f
HZ
889 if (ret < 0) {
890 dev_err(chip->dev, "Failed to read MISC1 register: %d\n", ret);
891 goto out;
892 }
bbd51b1f 893
5c42e8c4
HZ
894 if (pdata && (pdata->i2c_port == PI2C_PORT))
895 data = PM8607_B0_MISC1_PI2C;
896 else
897 data = 0;
898 ret = pm860x_set_bits(i2c, PM8607_B0_MISC1, PM8607_B0_MISC1_PI2C, data);
899 if (ret < 0) {
900 dev_err(chip->dev, "Failed to access MISC1:%d\n", ret);
901 goto out;
902 }
903
a16122bc
HZ
904 ret = device_gpadc_init(chip, pdata);
905 if (ret < 0)
906 goto out;
907
5c42e8c4
HZ
908 ret = device_irq_init(chip, pdata);
909 if (ret < 0)
910 goto out;
911
cea438dd
HZ
912 device_regulator_init(chip, pdata);
913 device_rtc_init(chip, pdata);
914 device_onkey_init(chip, pdata);
915 device_touch_init(chip, pdata);
916 device_power_init(chip, pdata);
917 device_codec_init(chip, pdata);
bbd51b1f 918out:
53dbab7a
HZ
919 return;
920}
921
78258064
JZ
922static void __devinit device_8606_init(struct pm860x_chip *chip,
923 struct i2c_client *i2c,
924 struct pm860x_platform_data *pdata)
925{
926 device_osc_init(i2c);
927 device_bk_init(chip, pdata);
928 device_led_init(chip, pdata);
929}
930
872c1b14 931int __devinit pm860x_device_init(struct pm860x_chip *chip,
53dbab7a
HZ
932 struct pm860x_platform_data *pdata)
933{
2afa62ea 934 chip->core_irq = 0;
5c42e8c4 935
53dbab7a
HZ
936 switch (chip->id) {
937 case CHIP_PM8606:
78258064 938 device_8606_init(chip, chip->client, pdata);
53dbab7a
HZ
939 break;
940 case CHIP_PM8607:
941 device_8607_init(chip, chip->client, pdata);
942 break;
943 }
944
945 if (chip->companion) {
946 switch (chip->id) {
947 case CHIP_PM8607:
78258064 948 device_8606_init(chip, chip->companion, pdata);
53dbab7a
HZ
949 break;
950 case CHIP_PM8606:
951 device_8607_init(chip, chip->companion, pdata);
952 break;
953 }
954 }
5c42e8c4 955
53dbab7a 956 return 0;
bbd51b1f
HZ
957}
958
872c1b14 959void __devexit pm860x_device_exit(struct pm860x_chip *chip)
bbd51b1f 960{
5c42e8c4 961 device_irq_exit(chip);
bbd51b1f
HZ
962 mfd_remove_devices(chip->dev);
963}
964
53dbab7a 965MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM860x");
bbd51b1f
HZ
966MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
967MODULE_LICENSE("GPL");
This page took 0.222789 seconds and 5 git commands to generate.