xref: /openbmc/linux/drivers/mfd/88pm860x-core.c (revision 3154c344)
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>
14 #include <linux/i2c.h>
15 #include <linux/irq.h>
16 #include <linux/interrupt.h>
17 #include <linux/platform_device.h>
18 #include <linux/mfd/core.h>
19 #include <linux/mfd/88pm860x.h>
20 
21 #define INT_STATUS_NUM			3
22 
23 static struct resource bk_resources[] __initdata = {
24 	{PM8606_BACKLIGHT1, PM8606_BACKLIGHT1, "backlight-0", IORESOURCE_IO,},
25 	{PM8606_BACKLIGHT2, PM8606_BACKLIGHT2, "backlight-1", IORESOURCE_IO,},
26 	{PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_IO,},
27 };
28 
29 static struct resource led_resources[] __initdata = {
30 	{PM8606_LED1_RED,   PM8606_LED1_RED,   "led0-red",   IORESOURCE_IO,},
31 	{PM8606_LED1_GREEN, PM8606_LED1_GREEN, "led0-green", IORESOURCE_IO,},
32 	{PM8606_LED1_BLUE,  PM8606_LED1_BLUE,  "led0-blue",  IORESOURCE_IO,},
33 	{PM8606_LED2_RED,   PM8606_LED2_RED,   "led1-red",   IORESOURCE_IO,},
34 	{PM8606_LED2_GREEN, PM8606_LED2_GREEN, "led1-green", IORESOURCE_IO,},
35 	{PM8606_LED2_BLUE,  PM8606_LED2_BLUE,  "led1-blue",  IORESOURCE_IO,},
36 };
37 
38 static struct mfd_cell bk_devs[] __initdata = {
39 	{"88pm860x-backlight", 0,},
40 	{"88pm860x-backlight", 1,},
41 	{"88pm860x-backlight", 2,},
42 };
43 
44 static struct mfd_cell led_devs[] __initdata = {
45 	{"88pm860x-led", 0,},
46 	{"88pm860x-led", 1,},
47 	{"88pm860x-led", 2,},
48 	{"88pm860x-led", 3,},
49 	{"88pm860x-led", 4,},
50 	{"88pm860x-led", 5,},
51 };
52 
53 static struct pm860x_backlight_pdata bk_pdata[ARRAY_SIZE(bk_devs)];
54 static struct pm860x_led_pdata led_pdata[ARRAY_SIZE(led_devs)];
55 
56 static struct resource touch_resources[] = {
57 	{
58 		.start	= PM8607_IRQ_PEN,
59 		.end	= PM8607_IRQ_PEN,
60 		.flags	= IORESOURCE_IRQ,
61 	},
62 };
63 
64 static struct mfd_cell touch_devs[] = {
65 	{
66 		.name		= "88pm860x-touch",
67 		.num_resources	= 1,
68 		.resources	= &touch_resources[0],
69 	},
70 };
71 
72 #define PM8607_REG_RESOURCE(_start, _end)		\
73 {							\
74 	.start	= PM8607_##_start,			\
75 	.end	= PM8607_##_end,			\
76 	.flags	= IORESOURCE_IO,			\
77 }
78 
79 static struct resource power_supply_resources[] = {
80 	{
81 		.name		= "88pm860x-power",
82 		.start		= PM8607_IRQ_CHG,
83 		.end		= PM8607_IRQ_CHG,
84 		.flags		= IORESOURCE_IRQ,
85 	},
86 };
87 
88 static struct mfd_cell power_devs[] = {
89 	{
90 		.name		= "88pm860x-power",
91 		.num_resources	= 1,
92 		.resources	= &power_supply_resources[0],
93 		.id		= -1,
94 	},
95 };
96 
97 static struct resource onkey_resources[] = {
98 	{
99 		.name		= "88pm860x-onkey",
100 		.start		= PM8607_IRQ_ONKEY,
101 		.end		= PM8607_IRQ_ONKEY,
102 		.flags		= IORESOURCE_IRQ,
103 	},
104 };
105 
106 static struct mfd_cell onkey_devs[] = {
107 	{
108 		.name		= "88pm860x-onkey",
109 		.num_resources	= 1,
110 		.resources	= &onkey_resources[0],
111 		.id		= -1,
112 	},
113 };
114 
115 static struct resource codec_resources[] = {
116 	{
117 		/* Headset microphone insertion or removal */
118 		.name		= "micin",
119 		.start		= PM8607_IRQ_MICIN,
120 		.end		= PM8607_IRQ_MICIN,
121 		.flags		= IORESOURCE_IRQ,
122 	}, {
123 		/* Hook-switch press or release */
124 		.name		= "hook",
125 		.start		= PM8607_IRQ_HOOK,
126 		.end		= PM8607_IRQ_HOOK,
127 		.flags		= IORESOURCE_IRQ,
128 	}, {
129 		/* Headset insertion or removal */
130 		.name		= "headset",
131 		.start		= PM8607_IRQ_HEADSET,
132 		.end		= PM8607_IRQ_HEADSET,
133 		.flags		= IORESOURCE_IRQ,
134 	}, {
135 		/* Audio short */
136 		.name		= "audio-short",
137 		.start		= PM8607_IRQ_AUDIO_SHORT,
138 		.end		= PM8607_IRQ_AUDIO_SHORT,
139 		.flags		= IORESOURCE_IRQ,
140 	},
141 };
142 
143 static struct mfd_cell codec_devs[] = {
144 	{
145 		.name		= "88pm860x-codec",
146 		.num_resources	= ARRAY_SIZE(codec_resources),
147 		.resources	= &codec_resources[0],
148 		.id		= -1,
149 	},
150 };
151 
152 static struct resource regulator_resources[] = {
153 	PM8607_REG_RESOURCE(BUCK1, BUCK1),
154 	PM8607_REG_RESOURCE(BUCK2, BUCK2),
155 	PM8607_REG_RESOURCE(BUCK3, BUCK3),
156 	PM8607_REG_RESOURCE(LDO1,  LDO1),
157 	PM8607_REG_RESOURCE(LDO2,  LDO2),
158 	PM8607_REG_RESOURCE(LDO3,  LDO3),
159 	PM8607_REG_RESOURCE(LDO4,  LDO4),
160 	PM8607_REG_RESOURCE(LDO5,  LDO5),
161 	PM8607_REG_RESOURCE(LDO6,  LDO6),
162 	PM8607_REG_RESOURCE(LDO7,  LDO7),
163 	PM8607_REG_RESOURCE(LDO8,  LDO8),
164 	PM8607_REG_RESOURCE(LDO9,  LDO9),
165 	PM8607_REG_RESOURCE(LDO10, LDO10),
166 	PM8607_REG_RESOURCE(LDO12, LDO12),
167 	PM8607_REG_RESOURCE(VIBRATOR_SET, VIBRATOR_SET),
168 	PM8607_REG_RESOURCE(LDO14, LDO14),
169 };
170 
171 #define PM8607_REG_DEVS(_id)						\
172 {									\
173 	.name		= "88pm860x-regulator",				\
174 	.num_resources	= 1,						\
175 	.resources	= &regulator_resources[PM8607_ID_##_id],	\
176 	.id		= PM8607_ID_##_id,				\
177 }
178 
179 static struct mfd_cell regulator_devs[] = {
180 	PM8607_REG_DEVS(BUCK1),
181 	PM8607_REG_DEVS(BUCK2),
182 	PM8607_REG_DEVS(BUCK3),
183 	PM8607_REG_DEVS(LDO1),
184 	PM8607_REG_DEVS(LDO2),
185 	PM8607_REG_DEVS(LDO3),
186 	PM8607_REG_DEVS(LDO4),
187 	PM8607_REG_DEVS(LDO5),
188 	PM8607_REG_DEVS(LDO6),
189 	PM8607_REG_DEVS(LDO7),
190 	PM8607_REG_DEVS(LDO8),
191 	PM8607_REG_DEVS(LDO9),
192 	PM8607_REG_DEVS(LDO10),
193 	PM8607_REG_DEVS(LDO12),
194 	PM8607_REG_DEVS(LDO13),
195 	PM8607_REG_DEVS(LDO14),
196 };
197 
198 struct pm860x_irq_data {
199 	int	reg;
200 	int	mask_reg;
201 	int	enable;		/* enable or not */
202 	int	offs;		/* bit offset in mask register */
203 };
204 
205 static struct pm860x_irq_data pm860x_irqs[] = {
206 	[PM8607_IRQ_ONKEY] = {
207 		.reg		= PM8607_INT_STATUS1,
208 		.mask_reg	= PM8607_INT_MASK_1,
209 		.offs		= 1 << 0,
210 	},
211 	[PM8607_IRQ_EXTON] = {
212 		.reg		= PM8607_INT_STATUS1,
213 		.mask_reg	= PM8607_INT_MASK_1,
214 		.offs		= 1 << 1,
215 	},
216 	[PM8607_IRQ_CHG] = {
217 		.reg		= PM8607_INT_STATUS1,
218 		.mask_reg	= PM8607_INT_MASK_1,
219 		.offs		= 1 << 2,
220 	},
221 	[PM8607_IRQ_BAT] = {
222 		.reg		= PM8607_INT_STATUS1,
223 		.mask_reg	= PM8607_INT_MASK_1,
224 		.offs		= 1 << 3,
225 	},
226 	[PM8607_IRQ_RTC] = {
227 		.reg		= PM8607_INT_STATUS1,
228 		.mask_reg	= PM8607_INT_MASK_1,
229 		.offs		= 1 << 4,
230 	},
231 	[PM8607_IRQ_CC] = {
232 		.reg		= PM8607_INT_STATUS1,
233 		.mask_reg	= PM8607_INT_MASK_1,
234 		.offs		= 1 << 5,
235 	},
236 	[PM8607_IRQ_VBAT] = {
237 		.reg		= PM8607_INT_STATUS2,
238 		.mask_reg	= PM8607_INT_MASK_2,
239 		.offs		= 1 << 0,
240 	},
241 	[PM8607_IRQ_VCHG] = {
242 		.reg		= PM8607_INT_STATUS2,
243 		.mask_reg	= PM8607_INT_MASK_2,
244 		.offs		= 1 << 1,
245 	},
246 	[PM8607_IRQ_VSYS] = {
247 		.reg		= PM8607_INT_STATUS2,
248 		.mask_reg	= PM8607_INT_MASK_2,
249 		.offs		= 1 << 2,
250 	},
251 	[PM8607_IRQ_TINT] = {
252 		.reg		= PM8607_INT_STATUS2,
253 		.mask_reg	= PM8607_INT_MASK_2,
254 		.offs		= 1 << 3,
255 	},
256 	[PM8607_IRQ_GPADC0] = {
257 		.reg		= PM8607_INT_STATUS2,
258 		.mask_reg	= PM8607_INT_MASK_2,
259 		.offs		= 1 << 4,
260 	},
261 	[PM8607_IRQ_GPADC1] = {
262 		.reg		= PM8607_INT_STATUS2,
263 		.mask_reg	= PM8607_INT_MASK_2,
264 		.offs		= 1 << 5,
265 	},
266 	[PM8607_IRQ_GPADC2] = {
267 		.reg		= PM8607_INT_STATUS2,
268 		.mask_reg	= PM8607_INT_MASK_2,
269 		.offs		= 1 << 6,
270 	},
271 	[PM8607_IRQ_GPADC3] = {
272 		.reg		= PM8607_INT_STATUS2,
273 		.mask_reg	= PM8607_INT_MASK_2,
274 		.offs		= 1 << 7,
275 	},
276 	[PM8607_IRQ_AUDIO_SHORT] = {
277 		.reg		= PM8607_INT_STATUS3,
278 		.mask_reg	= PM8607_INT_MASK_3,
279 		.offs		= 1 << 0,
280 	},
281 	[PM8607_IRQ_PEN] = {
282 		.reg		= PM8607_INT_STATUS3,
283 		.mask_reg	= PM8607_INT_MASK_3,
284 		.offs		= 1 << 1,
285 	},
286 	[PM8607_IRQ_HEADSET] = {
287 		.reg		= PM8607_INT_STATUS3,
288 		.mask_reg	= PM8607_INT_MASK_3,
289 		.offs		= 1 << 2,
290 	},
291 	[PM8607_IRQ_HOOK] = {
292 		.reg		= PM8607_INT_STATUS3,
293 		.mask_reg	= PM8607_INT_MASK_3,
294 		.offs		= 1 << 3,
295 	},
296 	[PM8607_IRQ_MICIN] = {
297 		.reg		= PM8607_INT_STATUS3,
298 		.mask_reg	= PM8607_INT_MASK_3,
299 		.offs		= 1 << 4,
300 	},
301 	[PM8607_IRQ_CHG_FAIL] = {
302 		.reg		= PM8607_INT_STATUS3,
303 		.mask_reg	= PM8607_INT_MASK_3,
304 		.offs		= 1 << 5,
305 	},
306 	[PM8607_IRQ_CHG_DONE] = {
307 		.reg		= PM8607_INT_STATUS3,
308 		.mask_reg	= PM8607_INT_MASK_3,
309 		.offs		= 1 << 6,
310 	},
311 	[PM8607_IRQ_CHG_FAULT] = {
312 		.reg		= PM8607_INT_STATUS3,
313 		.mask_reg	= PM8607_INT_MASK_3,
314 		.offs		= 1 << 7,
315 	},
316 };
317 
318 static irqreturn_t pm860x_irq(int irq, void *data)
319 {
320 	struct pm860x_chip *chip = data;
321 	struct pm860x_irq_data *irq_data;
322 	struct i2c_client *i2c;
323 	int read_reg = -1, value = 0;
324 	int i;
325 
326 	i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
327 	for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) {
328 		irq_data = &pm860x_irqs[i];
329 		if (read_reg != irq_data->reg) {
330 			read_reg = irq_data->reg;
331 			value = pm860x_reg_read(i2c, irq_data->reg);
332 		}
333 		if (value & irq_data->enable)
334 			handle_nested_irq(chip->irq_base + i);
335 	}
336 	return IRQ_HANDLED;
337 }
338 
339 static void pm860x_irq_lock(struct irq_data *data)
340 {
341 	struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
342 
343 	mutex_lock(&chip->irq_lock);
344 }
345 
346 static void pm860x_irq_sync_unlock(struct irq_data *data)
347 {
348 	struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
349 	struct pm860x_irq_data *irq_data;
350 	struct i2c_client *i2c;
351 	static unsigned char cached[3] = {0x0, 0x0, 0x0};
352 	unsigned char mask[3];
353 	int i;
354 
355 	i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
356 	/* Load cached value. In initial, all IRQs are masked */
357 	for (i = 0; i < 3; i++)
358 		mask[i] = cached[i];
359 	for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) {
360 		irq_data = &pm860x_irqs[i];
361 		switch (irq_data->mask_reg) {
362 		case PM8607_INT_MASK_1:
363 			mask[0] &= ~irq_data->offs;
364 			mask[0] |= irq_data->enable;
365 			break;
366 		case PM8607_INT_MASK_2:
367 			mask[1] &= ~irq_data->offs;
368 			mask[1] |= irq_data->enable;
369 			break;
370 		case PM8607_INT_MASK_3:
371 			mask[2] &= ~irq_data->offs;
372 			mask[2] |= irq_data->enable;
373 			break;
374 		default:
375 			dev_err(chip->dev, "wrong IRQ\n");
376 			break;
377 		}
378 	}
379 	/* update mask into registers */
380 	for (i = 0; i < 3; i++) {
381 		if (mask[i] != cached[i]) {
382 			cached[i] = mask[i];
383 			pm860x_reg_write(i2c, PM8607_INT_MASK_1 + i, mask[i]);
384 		}
385 	}
386 
387 	mutex_unlock(&chip->irq_lock);
388 }
389 
390 static void pm860x_irq_enable(struct irq_data *data)
391 {
392 	struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
393 	pm860x_irqs[data->irq - chip->irq_base].enable
394 		= pm860x_irqs[data->irq - chip->irq_base].offs;
395 }
396 
397 static void pm860x_irq_disable(struct irq_data *data)
398 {
399 	struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
400 	pm860x_irqs[data->irq - chip->irq_base].enable = 0;
401 }
402 
403 static struct irq_chip pm860x_irq_chip = {
404 	.name		= "88pm860x",
405 	.irq_bus_lock	= pm860x_irq_lock,
406 	.irq_bus_sync_unlock = pm860x_irq_sync_unlock,
407 	.irq_enable	= pm860x_irq_enable,
408 	.irq_disable	= pm860x_irq_disable,
409 };
410 
411 static int __devinit device_gpadc_init(struct pm860x_chip *chip,
412 				       struct pm860x_platform_data *pdata)
413 {
414 	struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \
415 				: chip->companion;
416 	int data;
417 	int ret;
418 
419 	/* initialize GPADC without activating it */
420 
421 	if (!pdata || !pdata->touch)
422 		return -EINVAL;
423 
424 	/* set GPADC MISC1 register */
425 	data = 0;
426 	data |= (pdata->touch->gpadc_prebias << 1) & PM8607_GPADC_PREBIAS_MASK;
427 	data |= (pdata->touch->slot_cycle << 3) & PM8607_GPADC_SLOT_CYCLE_MASK;
428 	data |= (pdata->touch->off_scale << 5) & PM8607_GPADC_OFF_SCALE_MASK;
429 	data |= (pdata->touch->sw_cal << 7) & PM8607_GPADC_SW_CAL_MASK;
430 	if (data) {
431 		ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data);
432 		if (ret < 0)
433 			goto out;
434 	}
435 	/* set tsi prebias time */
436 	if (pdata->touch->tsi_prebias) {
437 		data = pdata->touch->tsi_prebias;
438 		ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data);
439 		if (ret < 0)
440 			goto out;
441 	}
442 	/* set prebias & prechg time of pen detect */
443 	data = 0;
444 	data |= pdata->touch->pen_prebias & PM8607_PD_PREBIAS_MASK;
445 	data |= (pdata->touch->pen_prechg << 5) & PM8607_PD_PRECHG_MASK;
446 	if (data) {
447 		ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data);
448 		if (ret < 0)
449 			goto out;
450 	}
451 
452 	ret = pm860x_set_bits(i2c, PM8607_GPADC_MISC1,
453 			      PM8607_GPADC_EN, PM8607_GPADC_EN);
454 out:
455 	return ret;
456 }
457 
458 static int __devinit device_irq_init(struct pm860x_chip *chip,
459 				     struct pm860x_platform_data *pdata)
460 {
461 	struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \
462 				: chip->companion;
463 	unsigned char status_buf[INT_STATUS_NUM];
464 	unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
465 	struct irq_desc *desc;
466 	int i, data, mask, ret = -EINVAL;
467 	int __irq;
468 
469 	if (!pdata || !pdata->irq_base) {
470 		dev_warn(chip->dev, "No interrupt support on IRQ base\n");
471 		return -EINVAL;
472 	}
473 
474 	mask = PM8607_B0_MISC1_INV_INT | PM8607_B0_MISC1_INT_CLEAR
475 		| PM8607_B0_MISC1_INT_MASK;
476 	data = 0;
477 	chip->irq_mode = 0;
478 	if (pdata && pdata->irq_mode) {
479 		/*
480 		 * irq_mode defines the way of clearing interrupt. If it's 1,
481 		 * clear IRQ by write. Otherwise, clear it by read.
482 		 * This control bit is valid from 88PM8607 B0 steping.
483 		 */
484 		data |= PM8607_B0_MISC1_INT_CLEAR;
485 		chip->irq_mode = 1;
486 	}
487 	ret = pm860x_set_bits(i2c, PM8607_B0_MISC1, mask, data);
488 	if (ret < 0)
489 		goto out;
490 
491 	/* mask all IRQs */
492 	memset(status_buf, 0, INT_STATUS_NUM);
493 	ret = pm860x_bulk_write(i2c, PM8607_INT_MASK_1,
494 				INT_STATUS_NUM, status_buf);
495 	if (ret < 0)
496 		goto out;
497 
498 	if (chip->irq_mode) {
499 		/* clear interrupt status by write */
500 		memset(status_buf, 0xFF, INT_STATUS_NUM);
501 		ret = pm860x_bulk_write(i2c, PM8607_INT_STATUS1,
502 					INT_STATUS_NUM, status_buf);
503 	} else {
504 		/* clear interrupt status by read */
505 		ret = pm860x_bulk_read(i2c, PM8607_INT_STATUS1,
506 					INT_STATUS_NUM, status_buf);
507 	}
508 	if (ret < 0)
509 		goto out;
510 
511 	mutex_init(&chip->irq_lock);
512 	chip->irq_base = pdata->irq_base;
513 	chip->core_irq = i2c->irq;
514 	if (!chip->core_irq)
515 		goto out;
516 
517 	desc = irq_to_desc(chip->core_irq);
518 
519 	/* register IRQ by genirq */
520 	for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) {
521 		__irq = i + chip->irq_base;
522 		set_irq_chip_data(__irq, chip);
523 		set_irq_chip_and_handler(__irq, &pm860x_irq_chip,
524 					 handle_edge_irq);
525 		set_irq_nested_thread(__irq, 1);
526 #ifdef CONFIG_ARM
527 		set_irq_flags(__irq, IRQF_VALID);
528 #else
529 		set_irq_noprobe(__irq);
530 #endif
531 	}
532 
533 	ret = request_threaded_irq(chip->core_irq, NULL, pm860x_irq, flags,
534 				   "88pm860x", chip);
535 	if (ret) {
536 		dev_err(chip->dev, "Failed to request IRQ: %d\n", ret);
537 		chip->core_irq = 0;
538 	}
539 
540 	return 0;
541 out:
542 	chip->core_irq = 0;
543 	return ret;
544 }
545 
546 static void device_irq_exit(struct pm860x_chip *chip)
547 {
548 	if (chip->core_irq)
549 		free_irq(chip->core_irq, chip);
550 }
551 
552 static void __devinit device_bk_init(struct pm860x_chip *chip,
553 				     struct i2c_client *i2c,
554 				     struct pm860x_platform_data *pdata)
555 {
556 	int ret;
557 	int i, j, id;
558 
559 	if ((pdata == NULL) || (pdata->backlight == NULL))
560 		return;
561 
562 	if (pdata->num_backlights > ARRAY_SIZE(bk_devs))
563 		pdata->num_backlights = ARRAY_SIZE(bk_devs);
564 
565 	for (i = 0; i < pdata->num_backlights; i++) {
566 		memcpy(&bk_pdata[i], &pdata->backlight[i],
567 			sizeof(struct pm860x_backlight_pdata));
568 		bk_devs[i].mfd_data = &bk_pdata[i];
569 
570 		for (j = 0; j < ARRAY_SIZE(bk_devs); j++) {
571 			id = bk_resources[j].start;
572 			if (bk_pdata[i].flags != id)
573 				continue;
574 
575 			bk_devs[i].num_resources = 1;
576 			bk_devs[i].resources = &bk_resources[j];
577 			ret = mfd_add_devices(chip->dev, 0,
578 					      &bk_devs[i], 1,
579 					      &bk_resources[j], 0);
580 			if (ret < 0) {
581 				dev_err(chip->dev, "Failed to add "
582 					"backlight subdev\n");
583 				return;
584 			}
585 		}
586 	}
587 }
588 
589 static void __devinit device_led_init(struct pm860x_chip *chip,
590 				      struct i2c_client *i2c,
591 				      struct pm860x_platform_data *pdata)
592 {
593 	int ret;
594 	int i, j, id;
595 
596 	if ((pdata == NULL) || (pdata->led == NULL))
597 		return;
598 
599 	if (pdata->num_leds > ARRAY_SIZE(led_devs))
600 		pdata->num_leds = ARRAY_SIZE(led_devs);
601 
602 	for (i = 0; i < pdata->num_leds; i++) {
603 		memcpy(&led_pdata[i], &pdata->led[i],
604 			sizeof(struct pm860x_led_pdata));
605 		led_devs[i].mfd_data = &led_pdata[i];
606 
607 		for (j = 0; j < ARRAY_SIZE(led_devs); j++) {
608 			id = led_resources[j].start;
609 			if (led_pdata[i].flags != id)
610 				continue;
611 
612 			led_devs[i].num_resources = 1;
613 			led_devs[i].resources = &led_resources[j],
614 			ret = mfd_add_devices(chip->dev, 0,
615 					      &led_devs[i], 1,
616 					      &led_resources[j], 0);
617 			if (ret < 0) {
618 				dev_err(chip->dev, "Failed to add "
619 					"led subdev\n");
620 				return;
621 			}
622 		}
623 	}
624 }
625 
626 static void __devinit device_8607_init(struct pm860x_chip *chip,
627 				       struct i2c_client *i2c,
628 				       struct pm860x_platform_data *pdata)
629 {
630 	int data, ret;
631 
632 	ret = pm860x_reg_read(i2c, PM8607_CHIP_ID);
633 	if (ret < 0) {
634 		dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
635 		goto out;
636 	}
637 	switch (ret & PM8607_VERSION_MASK) {
638 	case 0x40:
639 	case 0x50:
640 		dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected\n",
641 			 ret);
642 		break;
643 	default:
644 		dev_err(chip->dev, "Failed to detect Marvell 88PM8607. "
645 			"Chip ID: %02x\n", ret);
646 		goto out;
647 	}
648 
649 	ret = pm860x_reg_read(i2c, PM8607_BUCK3);
650 	if (ret < 0) {
651 		dev_err(chip->dev, "Failed to read BUCK3 register: %d\n", ret);
652 		goto out;
653 	}
654 	if (ret & PM8607_BUCK3_DOUBLE)
655 		chip->buck3_double = 1;
656 
657 	ret = pm860x_reg_read(i2c, PM8607_B0_MISC1);
658 	if (ret < 0) {
659 		dev_err(chip->dev, "Failed to read MISC1 register: %d\n", ret);
660 		goto out;
661 	}
662 
663 	if (pdata && (pdata->i2c_port == PI2C_PORT))
664 		data = PM8607_B0_MISC1_PI2C;
665 	else
666 		data = 0;
667 	ret = pm860x_set_bits(i2c, PM8607_B0_MISC1, PM8607_B0_MISC1_PI2C, data);
668 	if (ret < 0) {
669 		dev_err(chip->dev, "Failed to access MISC1:%d\n", ret);
670 		goto out;
671 	}
672 
673 	ret = device_gpadc_init(chip, pdata);
674 	if (ret < 0)
675 		goto out;
676 
677 	ret = device_irq_init(chip, pdata);
678 	if (ret < 0)
679 		goto out;
680 
681 	ret = mfd_add_devices(chip->dev, 0, &regulator_devs[0],
682 			      ARRAY_SIZE(regulator_devs),
683 			      &regulator_resources[0], 0);
684 	if (ret < 0) {
685 		dev_err(chip->dev, "Failed to add regulator subdev\n");
686 		goto out_dev;
687 	}
688 
689 	if (pdata && pdata->touch) {
690 		ret = mfd_add_devices(chip->dev, 0, &touch_devs[0],
691 				      ARRAY_SIZE(touch_devs),
692 				      &touch_resources[0], 0);
693 		if (ret < 0) {
694 			dev_err(chip->dev, "Failed to add touch "
695 				"subdev\n");
696 			goto out_dev;
697 		}
698 	}
699 
700 	if (pdata && pdata->power) {
701 		ret = mfd_add_devices(chip->dev, 0, &power_devs[0],
702 				      ARRAY_SIZE(power_devs),
703 				      &power_supply_resources[0], 0);
704 		if (ret < 0) {
705 			dev_err(chip->dev, "Failed to add power supply "
706 				"subdev\n");
707 			goto out_dev;
708 		}
709 	}
710 
711 	ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0],
712 			      ARRAY_SIZE(onkey_devs),
713 			      &onkey_resources[0], 0);
714 	if (ret < 0) {
715 		dev_err(chip->dev, "Failed to add onkey subdev\n");
716 		goto out_dev;
717 	}
718 
719 	ret = mfd_add_devices(chip->dev, 0, &codec_devs[0],
720 			      ARRAY_SIZE(codec_devs),
721 			      &codec_resources[0], 0);
722 	if (ret < 0) {
723 		dev_err(chip->dev, "Failed to add codec subdev\n");
724 		goto out_dev;
725 	}
726 	return;
727 out_dev:
728 	mfd_remove_devices(chip->dev);
729 	device_irq_exit(chip);
730 out:
731 	return;
732 }
733 
734 int __devinit pm860x_device_init(struct pm860x_chip *chip,
735 		       struct pm860x_platform_data *pdata)
736 {
737 	chip->core_irq = 0;
738 
739 	switch (chip->id) {
740 	case CHIP_PM8606:
741 		device_bk_init(chip, chip->client, pdata);
742 		device_led_init(chip, chip->client, pdata);
743 		break;
744 	case CHIP_PM8607:
745 		device_8607_init(chip, chip->client, pdata);
746 		break;
747 	}
748 
749 	if (chip->companion) {
750 		switch (chip->id) {
751 		case CHIP_PM8607:
752 			device_bk_init(chip, chip->companion, pdata);
753 			device_led_init(chip, chip->companion, pdata);
754 			break;
755 		case CHIP_PM8606:
756 			device_8607_init(chip, chip->companion, pdata);
757 			break;
758 		}
759 	}
760 
761 	return 0;
762 }
763 
764 void __devexit pm860x_device_exit(struct pm860x_chip *chip)
765 {
766 	device_irq_exit(chip);
767 	mfd_remove_devices(chip->dev);
768 }
769 
770 MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM860x");
771 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
772 MODULE_LICENSE("GPL");
773