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