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