xref: /openbmc/linux/drivers/mfd/88pm860x-core.c (revision 18766f09)
1bbd51b1fSHaojian Zhuang /*
2bbd51b1fSHaojian Zhuang  * Base driver for Marvell 88PM8607
3bbd51b1fSHaojian Zhuang  *
4bbd51b1fSHaojian Zhuang  * Copyright (C) 2009 Marvell International Ltd.
5bbd51b1fSHaojian Zhuang  * 	Haojian Zhuang <haojian.zhuang@marvell.com>
6bbd51b1fSHaojian Zhuang  *
7bbd51b1fSHaojian Zhuang  * This program is free software; you can redistribute it and/or modify
8bbd51b1fSHaojian Zhuang  * it under the terms of the GNU General Public License version 2 as
9bbd51b1fSHaojian Zhuang  * published by the Free Software Foundation.
10bbd51b1fSHaojian Zhuang  */
11bbd51b1fSHaojian Zhuang 
12bbd51b1fSHaojian Zhuang #include <linux/kernel.h>
13bbd51b1fSHaojian Zhuang #include <linux/module.h>
145c42e8c4SHaojian Zhuang #include <linux/i2c.h>
152afa62eaSHaojian Zhuang #include <linux/irq.h>
16bbd51b1fSHaojian Zhuang #include <linux/interrupt.h>
17bbd51b1fSHaojian Zhuang #include <linux/platform_device.h>
18bbd51b1fSHaojian Zhuang #include <linux/mfd/core.h>
1953dbab7aSHaojian Zhuang #include <linux/mfd/88pm860x.h>
2022aad001SHaojian Zhuang #include <linux/regulator/machine.h>
21a830d28bSJett.Zhou #include <linux/power/charger-manager.h>
22bbd51b1fSHaojian Zhuang 
232afa62eaSHaojian Zhuang #define INT_STATUS_NUM			3
242afa62eaSHaojian Zhuang 
25a5156f1aSHaojian Zhuang static struct resource bk_resources[] __devinitdata = {
26adb70483SHaojian Zhuang 	{PM8606_BACKLIGHT1, PM8606_BACKLIGHT1, "backlight-0", IORESOURCE_IO,},
27adb70483SHaojian Zhuang 	{PM8606_BACKLIGHT2, PM8606_BACKLIGHT2, "backlight-1", IORESOURCE_IO,},
28adb70483SHaojian Zhuang 	{PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_IO,},
29a16122bcSHaojian Zhuang };
30adb70483SHaojian Zhuang 
31a5156f1aSHaojian Zhuang static struct resource led_resources[] __devinitdata = {
323154c344SHaojian Zhuang 	{PM8606_LED1_RED,   PM8606_LED1_RED,   "led0-red",   IORESOURCE_IO,},
333154c344SHaojian Zhuang 	{PM8606_LED1_GREEN, PM8606_LED1_GREEN, "led0-green", IORESOURCE_IO,},
343154c344SHaojian Zhuang 	{PM8606_LED1_BLUE,  PM8606_LED1_BLUE,  "led0-blue",  IORESOURCE_IO,},
353154c344SHaojian Zhuang 	{PM8606_LED2_RED,   PM8606_LED2_RED,   "led1-red",   IORESOURCE_IO,},
363154c344SHaojian Zhuang 	{PM8606_LED2_GREEN, PM8606_LED2_GREEN, "led1-green", IORESOURCE_IO,},
373154c344SHaojian Zhuang 	{PM8606_LED2_BLUE,  PM8606_LED2_BLUE,  "led1-blue",  IORESOURCE_IO,},
383154c344SHaojian Zhuang };
393154c344SHaojian Zhuang 
40a5156f1aSHaojian Zhuang static struct resource regulator_resources[] __devinitdata = {
4122aad001SHaojian Zhuang 	{PM8607_ID_BUCK1, PM8607_ID_BUCK1, "buck-1", IORESOURCE_IO,},
4222aad001SHaojian Zhuang 	{PM8607_ID_BUCK2, PM8607_ID_BUCK2, "buck-2", IORESOURCE_IO,},
4322aad001SHaojian Zhuang 	{PM8607_ID_BUCK3, PM8607_ID_BUCK3, "buck-3", IORESOURCE_IO,},
4422aad001SHaojian Zhuang 	{PM8607_ID_LDO1,  PM8607_ID_LDO1,  "ldo-01", IORESOURCE_IO,},
4522aad001SHaojian Zhuang 	{PM8607_ID_LDO2,  PM8607_ID_LDO2,  "ldo-02", IORESOURCE_IO,},
4622aad001SHaojian Zhuang 	{PM8607_ID_LDO3,  PM8607_ID_LDO3,  "ldo-03", IORESOURCE_IO,},
4722aad001SHaojian Zhuang 	{PM8607_ID_LDO4,  PM8607_ID_LDO4,  "ldo-04", IORESOURCE_IO,},
4822aad001SHaojian Zhuang 	{PM8607_ID_LDO5,  PM8607_ID_LDO5,  "ldo-05", IORESOURCE_IO,},
4922aad001SHaojian Zhuang 	{PM8607_ID_LDO6,  PM8607_ID_LDO6,  "ldo-06", IORESOURCE_IO,},
5022aad001SHaojian Zhuang 	{PM8607_ID_LDO7,  PM8607_ID_LDO7,  "ldo-07", IORESOURCE_IO,},
5122aad001SHaojian Zhuang 	{PM8607_ID_LDO8,  PM8607_ID_LDO8,  "ldo-08", IORESOURCE_IO,},
5222aad001SHaojian Zhuang 	{PM8607_ID_LDO9,  PM8607_ID_LDO9,  "ldo-09", IORESOURCE_IO,},
5322aad001SHaojian Zhuang 	{PM8607_ID_LDO10, PM8607_ID_LDO10, "ldo-10", IORESOURCE_IO,},
5422aad001SHaojian Zhuang 	{PM8607_ID_LDO11, PM8607_ID_LDO11, "ldo-11", IORESOURCE_IO,},
5522aad001SHaojian Zhuang 	{PM8607_ID_LDO12, PM8607_ID_LDO12, "ldo-12", IORESOURCE_IO,},
5622aad001SHaojian Zhuang 	{PM8607_ID_LDO13, PM8607_ID_LDO13, "ldo-13", IORESOURCE_IO,},
5722aad001SHaojian Zhuang 	{PM8607_ID_LDO14, PM8607_ID_LDO14, "ldo-14", IORESOURCE_IO,},
5822aad001SHaojian Zhuang 	{PM8607_ID_LDO15, PM8607_ID_LDO15, "ldo-15", IORESOURCE_IO,},
5922aad001SHaojian Zhuang };
6022aad001SHaojian Zhuang 
61a5156f1aSHaojian Zhuang static struct resource touch_resources[] __devinitdata = {
62c9f560b3SHaojian Zhuang 	{PM8607_IRQ_PEN, PM8607_IRQ_PEN, "touch", IORESOURCE_IRQ,},
63c9f560b3SHaojian Zhuang };
64c9f560b3SHaojian Zhuang 
65a5156f1aSHaojian Zhuang static struct resource onkey_resources[] __devinitdata = {
66c9f560b3SHaojian Zhuang 	{PM8607_IRQ_ONKEY, PM8607_IRQ_ONKEY, "onkey", IORESOURCE_IRQ,},
67c9f560b3SHaojian Zhuang };
68c9f560b3SHaojian Zhuang 
69a5156f1aSHaojian Zhuang static struct resource codec_resources[] __devinitdata = {
70c9f560b3SHaojian Zhuang 	/* Headset microphone insertion or removal */
71c9f560b3SHaojian Zhuang 	{PM8607_IRQ_MICIN,   PM8607_IRQ_MICIN,   "micin",   IORESOURCE_IRQ,},
72c9f560b3SHaojian Zhuang 	/* Hook-switch press or release */
73c9f560b3SHaojian Zhuang 	{PM8607_IRQ_HOOK,    PM8607_IRQ_HOOK,    "hook",    IORESOURCE_IRQ,},
74c9f560b3SHaojian Zhuang 	/* Headset insertion or removal */
75c9f560b3SHaojian Zhuang 	{PM8607_IRQ_HEADSET, PM8607_IRQ_HEADSET, "headset", IORESOURCE_IRQ,},
76c9f560b3SHaojian Zhuang 	/* Audio short */
77c9f560b3SHaojian Zhuang 	{PM8607_IRQ_AUDIO_SHORT, PM8607_IRQ_AUDIO_SHORT, "audio-short", IORESOURCE_IRQ,},
78c9f560b3SHaojian Zhuang };
79c9f560b3SHaojian Zhuang 
80a5156f1aSHaojian Zhuang static struct resource battery_resources[] __devinitdata = {
81c9f560b3SHaojian Zhuang 	{PM8607_IRQ_CC,  PM8607_IRQ_CC,  "columb counter", IORESOURCE_IRQ,},
82c9f560b3SHaojian Zhuang 	{PM8607_IRQ_BAT, PM8607_IRQ_BAT, "battery",        IORESOURCE_IRQ,},
83c9f560b3SHaojian Zhuang };
84c9f560b3SHaojian Zhuang 
85a5156f1aSHaojian Zhuang static struct resource charger_resources[] __devinitdata = {
86c9f560b3SHaojian Zhuang 	{PM8607_IRQ_CHG,  PM8607_IRQ_CHG,  "charger detect",  IORESOURCE_IRQ,},
87c9f560b3SHaojian Zhuang 	{PM8607_IRQ_CHG_DONE,  PM8607_IRQ_CHG_DONE,  "charging done",       IORESOURCE_IRQ,},
88a830d28bSJett.Zhou 	{PM8607_IRQ_CHG_FAIL,  PM8607_IRQ_CHG_FAIL,  "charging timeout",    IORESOURCE_IRQ,},
89a830d28bSJett.Zhou 	{PM8607_IRQ_CHG_FAULT, PM8607_IRQ_CHG_FAULT, "charging fault",	    IORESOURCE_IRQ,},
90c9f560b3SHaojian Zhuang 	{PM8607_IRQ_GPADC1,    PM8607_IRQ_GPADC1,    "battery temperature", IORESOURCE_IRQ,},
91c9f560b3SHaojian Zhuang 	{PM8607_IRQ_VBAT, PM8607_IRQ_VBAT, "battery voltage", IORESOURCE_IRQ,},
92c9f560b3SHaojian Zhuang 	{PM8607_IRQ_VCHG, PM8607_IRQ_VCHG, "vchg voltage",    IORESOURCE_IRQ,},
93c9f560b3SHaojian Zhuang };
94c9f560b3SHaojian Zhuang 
952573f6d3SJett.Zhou static struct resource preg_resources[] __devinitdata = {
962573f6d3SJett.Zhou 	{PM8606_ID_PREG,  PM8606_ID_PREG,  "preg",   IORESOURCE_IO,},
972573f6d3SJett.Zhou };
982573f6d3SJett.Zhou 
99008b3040SHaojian Zhuang static struct resource rtc_resources[] __devinitdata = {
100008b3040SHaojian Zhuang 	{PM8607_IRQ_RTC, PM8607_IRQ_RTC, "rtc", IORESOURCE_IRQ,},
101008b3040SHaojian Zhuang };
102008b3040SHaojian Zhuang 
103a5156f1aSHaojian Zhuang static struct mfd_cell bk_devs[] = {
104adb70483SHaojian Zhuang 	{"88pm860x-backlight", 0,},
105adb70483SHaojian Zhuang 	{"88pm860x-backlight", 1,},
106adb70483SHaojian Zhuang 	{"88pm860x-backlight", 2,},
107adb70483SHaojian Zhuang };
108adb70483SHaojian Zhuang 
109a5156f1aSHaojian Zhuang static struct mfd_cell led_devs[] = {
1103154c344SHaojian Zhuang 	{"88pm860x-led", 0,},
1113154c344SHaojian Zhuang 	{"88pm860x-led", 1,},
1123154c344SHaojian Zhuang 	{"88pm860x-led", 2,},
1133154c344SHaojian Zhuang 	{"88pm860x-led", 3,},
1143154c344SHaojian Zhuang 	{"88pm860x-led", 4,},
1153154c344SHaojian Zhuang 	{"88pm860x-led", 5,},
1163154c344SHaojian Zhuang };
1173154c344SHaojian Zhuang 
118a5156f1aSHaojian Zhuang static struct mfd_cell regulator_devs[] = {
11922aad001SHaojian Zhuang 	{"88pm860x-regulator", 0,},
12022aad001SHaojian Zhuang 	{"88pm860x-regulator", 1,},
12122aad001SHaojian Zhuang 	{"88pm860x-regulator", 2,},
12222aad001SHaojian Zhuang 	{"88pm860x-regulator", 3,},
12322aad001SHaojian Zhuang 	{"88pm860x-regulator", 4,},
12422aad001SHaojian Zhuang 	{"88pm860x-regulator", 5,},
12522aad001SHaojian Zhuang 	{"88pm860x-regulator", 6,},
12622aad001SHaojian Zhuang 	{"88pm860x-regulator", 7,},
12722aad001SHaojian Zhuang 	{"88pm860x-regulator", 8,},
12822aad001SHaojian Zhuang 	{"88pm860x-regulator", 9,},
12922aad001SHaojian Zhuang 	{"88pm860x-regulator", 10,},
13022aad001SHaojian Zhuang 	{"88pm860x-regulator", 11,},
13122aad001SHaojian Zhuang 	{"88pm860x-regulator", 12,},
13222aad001SHaojian Zhuang 	{"88pm860x-regulator", 13,},
13322aad001SHaojian Zhuang 	{"88pm860x-regulator", 14,},
13422aad001SHaojian Zhuang 	{"88pm860x-regulator", 15,},
13522aad001SHaojian Zhuang 	{"88pm860x-regulator", 16,},
13622aad001SHaojian Zhuang 	{"88pm860x-regulator", 17,},
13722aad001SHaojian Zhuang };
13822aad001SHaojian Zhuang 
139a5156f1aSHaojian Zhuang static struct mfd_cell touch_devs[] = {
140c9f560b3SHaojian Zhuang 	{"88pm860x-touch", -1,},
141a16122bcSHaojian Zhuang };
142a16122bcSHaojian Zhuang 
143a5156f1aSHaojian Zhuang static struct mfd_cell onkey_devs[] = {
144c9f560b3SHaojian Zhuang 	{"88pm860x-onkey", -1,},
145a16122bcSHaojian Zhuang };
146bbd51b1fSHaojian Zhuang 
147a5156f1aSHaojian Zhuang static struct mfd_cell codec_devs[] = {
148c9f560b3SHaojian Zhuang 	{"88pm860x-codec", -1,},
1492afa62eaSHaojian Zhuang };
1502afa62eaSHaojian Zhuang 
1512573f6d3SJett.Zhou static struct regulator_consumer_supply preg_supply[] = {
1522573f6d3SJett.Zhou 	REGULATOR_SUPPLY("preg", "charger-manager"),
1532573f6d3SJett.Zhou };
1542573f6d3SJett.Zhou 
1552573f6d3SJett.Zhou static struct regulator_init_data preg_init_data = {
1562573f6d3SJett.Zhou 	.num_consumer_supplies	= ARRAY_SIZE(preg_supply),
1572573f6d3SJett.Zhou 	.consumer_supplies	= &preg_supply[0],
1582573f6d3SJett.Zhou };
1592573f6d3SJett.Zhou 
160f1ade352SAnton Vorontsov static struct charger_regulator chg_desc_regulator_data[] = {
161f1ade352SAnton Vorontsov 	{ .regulator_name = "preg", },
162a830d28bSJett.Zhou };
163a830d28bSJett.Zhou 
1642afa62eaSHaojian Zhuang static struct mfd_cell power_devs[] = {
165c9f560b3SHaojian Zhuang 	{"88pm860x-battery", -1,},
166c9f560b3SHaojian Zhuang 	{"88pm860x-charger", -1,},
1672573f6d3SJett.Zhou 	{"88pm860x-preg",    -1,},
168a830d28bSJett.Zhou 	{"charger-manager", -1,},
1692afa62eaSHaojian Zhuang };
1702afa62eaSHaojian Zhuang 
171008b3040SHaojian Zhuang static struct mfd_cell rtc_devs[] = {
172008b3040SHaojian Zhuang 	{"88pm860x-rtc", -1,},
173008b3040SHaojian Zhuang };
174008b3040SHaojian Zhuang 
1752c36af7bSHaojian Zhuang 
1762afa62eaSHaojian Zhuang struct pm860x_irq_data {
1772afa62eaSHaojian Zhuang 	int	reg;
1782afa62eaSHaojian Zhuang 	int	mask_reg;
1792afa62eaSHaojian Zhuang 	int	enable;		/* enable or not */
1802afa62eaSHaojian Zhuang 	int	offs;		/* bit offset in mask register */
1812afa62eaSHaojian Zhuang };
1825c42e8c4SHaojian Zhuang 
1832afa62eaSHaojian Zhuang static struct pm860x_irq_data pm860x_irqs[] = {
1842afa62eaSHaojian Zhuang 	[PM8607_IRQ_ONKEY] = {
1852afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS1,
1862afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_1,
1872afa62eaSHaojian Zhuang 		.offs		= 1 << 0,
1882afa62eaSHaojian Zhuang 	},
1892afa62eaSHaojian Zhuang 	[PM8607_IRQ_EXTON] = {
1902afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS1,
1912afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_1,
1922afa62eaSHaojian Zhuang 		.offs		= 1 << 1,
1932afa62eaSHaojian Zhuang 	},
1942afa62eaSHaojian Zhuang 	[PM8607_IRQ_CHG] = {
1952afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS1,
1962afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_1,
1972afa62eaSHaojian Zhuang 		.offs		= 1 << 2,
1982afa62eaSHaojian Zhuang 	},
1992afa62eaSHaojian Zhuang 	[PM8607_IRQ_BAT] = {
2002afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS1,
2012afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_1,
2022afa62eaSHaojian Zhuang 		.offs		= 1 << 3,
2032afa62eaSHaojian Zhuang 	},
2042afa62eaSHaojian Zhuang 	[PM8607_IRQ_RTC] = {
2052afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS1,
2062afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_1,
2072afa62eaSHaojian Zhuang 		.offs		= 1 << 4,
2082afa62eaSHaojian Zhuang 	},
2092afa62eaSHaojian Zhuang 	[PM8607_IRQ_CC] = {
2102afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS1,
2112afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_1,
2122afa62eaSHaojian Zhuang 		.offs		= 1 << 5,
2132afa62eaSHaojian Zhuang 	},
2142afa62eaSHaojian Zhuang 	[PM8607_IRQ_VBAT] = {
2152afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS2,
2162afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_2,
2172afa62eaSHaojian Zhuang 		.offs		= 1 << 0,
2182afa62eaSHaojian Zhuang 	},
2192afa62eaSHaojian Zhuang 	[PM8607_IRQ_VCHG] = {
2202afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS2,
2212afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_2,
2222afa62eaSHaojian Zhuang 		.offs		= 1 << 1,
2232afa62eaSHaojian Zhuang 	},
2242afa62eaSHaojian Zhuang 	[PM8607_IRQ_VSYS] = {
2252afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS2,
2262afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_2,
2272afa62eaSHaojian Zhuang 		.offs		= 1 << 2,
2282afa62eaSHaojian Zhuang 	},
2292afa62eaSHaojian Zhuang 	[PM8607_IRQ_TINT] = {
2302afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS2,
2312afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_2,
2322afa62eaSHaojian Zhuang 		.offs		= 1 << 3,
2332afa62eaSHaojian Zhuang 	},
2342afa62eaSHaojian Zhuang 	[PM8607_IRQ_GPADC0] = {
2352afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS2,
2362afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_2,
2372afa62eaSHaojian Zhuang 		.offs		= 1 << 4,
2382afa62eaSHaojian Zhuang 	},
2392afa62eaSHaojian Zhuang 	[PM8607_IRQ_GPADC1] = {
2402afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS2,
2412afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_2,
2422afa62eaSHaojian Zhuang 		.offs		= 1 << 5,
2432afa62eaSHaojian Zhuang 	},
2442afa62eaSHaojian Zhuang 	[PM8607_IRQ_GPADC2] = {
2452afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS2,
2462afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_2,
2472afa62eaSHaojian Zhuang 		.offs		= 1 << 6,
2482afa62eaSHaojian Zhuang 	},
2492afa62eaSHaojian Zhuang 	[PM8607_IRQ_GPADC3] = {
2502afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS2,
2512afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_2,
2522afa62eaSHaojian Zhuang 		.offs		= 1 << 7,
2532afa62eaSHaojian Zhuang 	},
2542afa62eaSHaojian Zhuang 	[PM8607_IRQ_AUDIO_SHORT] = {
2552afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS3,
2562afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_3,
2572afa62eaSHaojian Zhuang 		.offs		= 1 << 0,
2582afa62eaSHaojian Zhuang 	},
2592afa62eaSHaojian Zhuang 	[PM8607_IRQ_PEN] = {
2602afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS3,
2612afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_3,
2622afa62eaSHaojian Zhuang 		.offs		= 1 << 1,
2632afa62eaSHaojian Zhuang 	},
2642afa62eaSHaojian Zhuang 	[PM8607_IRQ_HEADSET] = {
2652afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS3,
2662afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_3,
2672afa62eaSHaojian Zhuang 		.offs		= 1 << 2,
2682afa62eaSHaojian Zhuang 	},
2692afa62eaSHaojian Zhuang 	[PM8607_IRQ_HOOK] = {
2702afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS3,
2712afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_3,
2722afa62eaSHaojian Zhuang 		.offs		= 1 << 3,
2732afa62eaSHaojian Zhuang 	},
2742afa62eaSHaojian Zhuang 	[PM8607_IRQ_MICIN] = {
2752afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS3,
2762afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_3,
2772afa62eaSHaojian Zhuang 		.offs		= 1 << 4,
2782afa62eaSHaojian Zhuang 	},
2792afa62eaSHaojian Zhuang 	[PM8607_IRQ_CHG_FAIL] = {
2802afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS3,
2812afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_3,
2822afa62eaSHaojian Zhuang 		.offs		= 1 << 5,
2832afa62eaSHaojian Zhuang 	},
2842afa62eaSHaojian Zhuang 	[PM8607_IRQ_CHG_DONE] = {
2852afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS3,
2862afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_3,
2872afa62eaSHaojian Zhuang 		.offs		= 1 << 6,
2882afa62eaSHaojian Zhuang 	},
2892afa62eaSHaojian Zhuang 	[PM8607_IRQ_CHG_FAULT] = {
2902afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS3,
2912afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_3,
2922afa62eaSHaojian Zhuang 		.offs		= 1 << 7,
2932afa62eaSHaojian Zhuang 	},
2942afa62eaSHaojian Zhuang };
2952afa62eaSHaojian Zhuang 
2962afa62eaSHaojian Zhuang static irqreturn_t pm860x_irq(int irq, void *data)
2975c42e8c4SHaojian Zhuang {
2985c42e8c4SHaojian Zhuang 	struct pm860x_chip *chip = data;
2992afa62eaSHaojian Zhuang 	struct pm860x_irq_data *irq_data;
3002afa62eaSHaojian Zhuang 	struct i2c_client *i2c;
3012afa62eaSHaojian Zhuang 	int read_reg = -1, value = 0;
3022afa62eaSHaojian Zhuang 	int i;
3035c42e8c4SHaojian Zhuang 
3042afa62eaSHaojian Zhuang 	i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
3052afa62eaSHaojian Zhuang 	for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) {
3062afa62eaSHaojian Zhuang 		irq_data = &pm860x_irqs[i];
3072afa62eaSHaojian Zhuang 		if (read_reg != irq_data->reg) {
3082afa62eaSHaojian Zhuang 			read_reg = irq_data->reg;
3092afa62eaSHaojian Zhuang 			value = pm860x_reg_read(i2c, irq_data->reg);
3105c42e8c4SHaojian Zhuang 		}
3112afa62eaSHaojian Zhuang 		if (value & irq_data->enable)
3122afa62eaSHaojian Zhuang 			handle_nested_irq(chip->irq_base + i);
3135c42e8c4SHaojian Zhuang 	}
3145c42e8c4SHaojian Zhuang 	return IRQ_HANDLED;
3155c42e8c4SHaojian Zhuang }
3165c42e8c4SHaojian Zhuang 
31749f89d9aSMark Brown static void pm860x_irq_lock(struct irq_data *data)
3185c42e8c4SHaojian Zhuang {
31949f89d9aSMark Brown 	struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
3205c42e8c4SHaojian Zhuang 
3215c42e8c4SHaojian Zhuang 	mutex_lock(&chip->irq_lock);
3225c42e8c4SHaojian Zhuang }
3235c42e8c4SHaojian Zhuang 
32449f89d9aSMark Brown static void pm860x_irq_sync_unlock(struct irq_data *data)
3255c42e8c4SHaojian Zhuang {
32649f89d9aSMark Brown 	struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
3272afa62eaSHaojian Zhuang 	struct pm860x_irq_data *irq_data;
3282afa62eaSHaojian Zhuang 	struct i2c_client *i2c;
3292afa62eaSHaojian Zhuang 	static unsigned char cached[3] = {0x0, 0x0, 0x0};
3302afa62eaSHaojian Zhuang 	unsigned char mask[3];
3312afa62eaSHaojian Zhuang 	int i;
3325c42e8c4SHaojian Zhuang 
3332afa62eaSHaojian Zhuang 	i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
3342afa62eaSHaojian Zhuang 	/* Load cached value. In initial, all IRQs are masked */
3352afa62eaSHaojian Zhuang 	for (i = 0; i < 3; i++)
3362afa62eaSHaojian Zhuang 		mask[i] = cached[i];
3372afa62eaSHaojian Zhuang 	for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) {
3382afa62eaSHaojian Zhuang 		irq_data = &pm860x_irqs[i];
3392afa62eaSHaojian Zhuang 		switch (irq_data->mask_reg) {
3402afa62eaSHaojian Zhuang 		case PM8607_INT_MASK_1:
3412afa62eaSHaojian Zhuang 			mask[0] &= ~irq_data->offs;
3422afa62eaSHaojian Zhuang 			mask[0] |= irq_data->enable;
3432afa62eaSHaojian Zhuang 			break;
3442afa62eaSHaojian Zhuang 		case PM8607_INT_MASK_2:
3452afa62eaSHaojian Zhuang 			mask[1] &= ~irq_data->offs;
3462afa62eaSHaojian Zhuang 			mask[1] |= irq_data->enable;
3472afa62eaSHaojian Zhuang 			break;
3482afa62eaSHaojian Zhuang 		case PM8607_INT_MASK_3:
3492afa62eaSHaojian Zhuang 			mask[2] &= ~irq_data->offs;
3502afa62eaSHaojian Zhuang 			mask[2] |= irq_data->enable;
3512afa62eaSHaojian Zhuang 			break;
3522afa62eaSHaojian Zhuang 		default:
3532afa62eaSHaojian Zhuang 			dev_err(chip->dev, "wrong IRQ\n");
3542afa62eaSHaojian Zhuang 			break;
3555c42e8c4SHaojian Zhuang 		}
3562afa62eaSHaojian Zhuang 	}
3572afa62eaSHaojian Zhuang 	/* update mask into registers */
3582afa62eaSHaojian Zhuang 	for (i = 0; i < 3; i++) {
3592afa62eaSHaojian Zhuang 		if (mask[i] != cached[i]) {
3602afa62eaSHaojian Zhuang 			cached[i] = mask[i];
3612afa62eaSHaojian Zhuang 			pm860x_reg_write(i2c, PM8607_INT_MASK_1 + i, mask[i]);
3622afa62eaSHaojian Zhuang 		}
3632afa62eaSHaojian Zhuang 	}
3642afa62eaSHaojian Zhuang 
3652afa62eaSHaojian Zhuang 	mutex_unlock(&chip->irq_lock);
3662afa62eaSHaojian Zhuang }
3672afa62eaSHaojian Zhuang 
36849f89d9aSMark Brown static void pm860x_irq_enable(struct irq_data *data)
3692afa62eaSHaojian Zhuang {
37049f89d9aSMark Brown 	struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
37149f89d9aSMark Brown 	pm860x_irqs[data->irq - chip->irq_base].enable
37249f89d9aSMark Brown 		= pm860x_irqs[data->irq - chip->irq_base].offs;
3732afa62eaSHaojian Zhuang }
3742afa62eaSHaojian Zhuang 
37549f89d9aSMark Brown static void pm860x_irq_disable(struct irq_data *data)
3762afa62eaSHaojian Zhuang {
37749f89d9aSMark Brown 	struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
37849f89d9aSMark Brown 	pm860x_irqs[data->irq - chip->irq_base].enable = 0;
3792afa62eaSHaojian Zhuang }
3802afa62eaSHaojian Zhuang 
3812afa62eaSHaojian Zhuang static struct irq_chip pm860x_irq_chip = {
3822afa62eaSHaojian Zhuang 	.name		= "88pm860x",
38349f89d9aSMark Brown 	.irq_bus_lock	= pm860x_irq_lock,
38449f89d9aSMark Brown 	.irq_bus_sync_unlock = pm860x_irq_sync_unlock,
38549f89d9aSMark Brown 	.irq_enable	= pm860x_irq_enable,
38649f89d9aSMark Brown 	.irq_disable	= pm860x_irq_disable,
3872afa62eaSHaojian Zhuang };
3885c42e8c4SHaojian Zhuang 
389a16122bcSHaojian Zhuang static int __devinit device_gpadc_init(struct pm860x_chip *chip,
390a16122bcSHaojian Zhuang 				       struct pm860x_platform_data *pdata)
391a16122bcSHaojian Zhuang {
392a16122bcSHaojian Zhuang 	struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \
393a16122bcSHaojian Zhuang 				: chip->companion;
394eb6e8ddfSDan Carpenter 	int data;
395eb6e8ddfSDan Carpenter 	int ret;
396a16122bcSHaojian Zhuang 
397a16122bcSHaojian Zhuang 	/* initialize GPADC without activating it */
398a16122bcSHaojian Zhuang 
399eb6e8ddfSDan Carpenter 	if (!pdata || !pdata->touch)
400eb6e8ddfSDan Carpenter 		return -EINVAL;
401eb6e8ddfSDan Carpenter 
402a16122bcSHaojian Zhuang 	/* set GPADC MISC1 register */
403a16122bcSHaojian Zhuang 	data = 0;
404eb6e8ddfSDan Carpenter 	data |= (pdata->touch->gpadc_prebias << 1) & PM8607_GPADC_PREBIAS_MASK;
405eb6e8ddfSDan Carpenter 	data |= (pdata->touch->slot_cycle << 3) & PM8607_GPADC_SLOT_CYCLE_MASK;
406eb6e8ddfSDan Carpenter 	data |= (pdata->touch->off_scale << 5) & PM8607_GPADC_OFF_SCALE_MASK;
407eb6e8ddfSDan Carpenter 	data |= (pdata->touch->sw_cal << 7) & PM8607_GPADC_SW_CAL_MASK;
408a16122bcSHaojian Zhuang 	if (data) {
409a16122bcSHaojian Zhuang 		ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data);
410a16122bcSHaojian Zhuang 		if (ret < 0)
411a16122bcSHaojian Zhuang 			goto out;
412a16122bcSHaojian Zhuang 	}
413a16122bcSHaojian Zhuang 	/* set tsi prebias time */
414a16122bcSHaojian Zhuang 	if (pdata->touch->tsi_prebias) {
415a16122bcSHaojian Zhuang 		data = pdata->touch->tsi_prebias;
416a16122bcSHaojian Zhuang 		ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data);
417a16122bcSHaojian Zhuang 		if (ret < 0)
418a16122bcSHaojian Zhuang 			goto out;
419a16122bcSHaojian Zhuang 	}
420a16122bcSHaojian Zhuang 	/* set prebias & prechg time of pen detect */
421a16122bcSHaojian Zhuang 	data = 0;
422a16122bcSHaojian Zhuang 	data |= pdata->touch->pen_prebias & PM8607_PD_PREBIAS_MASK;
423eb6e8ddfSDan Carpenter 	data |= (pdata->touch->pen_prechg << 5) & PM8607_PD_PRECHG_MASK;
424a16122bcSHaojian Zhuang 	if (data) {
425a16122bcSHaojian Zhuang 		ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data);
426a16122bcSHaojian Zhuang 		if (ret < 0)
427a16122bcSHaojian Zhuang 			goto out;
428a16122bcSHaojian Zhuang 	}
429a16122bcSHaojian Zhuang 
430a16122bcSHaojian Zhuang 	ret = pm860x_set_bits(i2c, PM8607_GPADC_MISC1,
431a16122bcSHaojian Zhuang 			      PM8607_GPADC_EN, PM8607_GPADC_EN);
432a16122bcSHaojian Zhuang out:
433a16122bcSHaojian Zhuang 	return ret;
434a16122bcSHaojian Zhuang }
435a16122bcSHaojian Zhuang 
4365c42e8c4SHaojian Zhuang static int __devinit device_irq_init(struct pm860x_chip *chip,
4375c42e8c4SHaojian Zhuang 				     struct pm860x_platform_data *pdata)
4385c42e8c4SHaojian Zhuang {
4395c42e8c4SHaojian Zhuang 	struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \
4405c42e8c4SHaojian Zhuang 				: chip->companion;
4415c42e8c4SHaojian Zhuang 	unsigned char status_buf[INT_STATUS_NUM];
4422afa62eaSHaojian Zhuang 	unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
4432afa62eaSHaojian Zhuang 	int i, data, mask, ret = -EINVAL;
4442afa62eaSHaojian Zhuang 	int __irq;
4455c42e8c4SHaojian Zhuang 
4462afa62eaSHaojian Zhuang 	if (!pdata || !pdata->irq_base) {
4472afa62eaSHaojian Zhuang 		dev_warn(chip->dev, "No interrupt support on IRQ base\n");
4482afa62eaSHaojian Zhuang 		return -EINVAL;
4492afa62eaSHaojian Zhuang 	}
4505c42e8c4SHaojian Zhuang 
4515c42e8c4SHaojian Zhuang 	mask = PM8607_B0_MISC1_INV_INT | PM8607_B0_MISC1_INT_CLEAR
4525c42e8c4SHaojian Zhuang 		| PM8607_B0_MISC1_INT_MASK;
4535c42e8c4SHaojian Zhuang 	data = 0;
4545c42e8c4SHaojian Zhuang 	chip->irq_mode = 0;
4555c42e8c4SHaojian Zhuang 	if (pdata && pdata->irq_mode) {
4565c42e8c4SHaojian Zhuang 		/*
4575c42e8c4SHaojian Zhuang 		 * irq_mode defines the way of clearing interrupt. If it's 1,
4585c42e8c4SHaojian Zhuang 		 * clear IRQ by write. Otherwise, clear it by read.
4595c42e8c4SHaojian Zhuang 		 * This control bit is valid from 88PM8607 B0 steping.
4605c42e8c4SHaojian Zhuang 		 */
4615c42e8c4SHaojian Zhuang 		data |= PM8607_B0_MISC1_INT_CLEAR;
4625c42e8c4SHaojian Zhuang 		chip->irq_mode = 1;
4635c42e8c4SHaojian Zhuang 	}
4645c42e8c4SHaojian Zhuang 	ret = pm860x_set_bits(i2c, PM8607_B0_MISC1, mask, data);
4655c42e8c4SHaojian Zhuang 	if (ret < 0)
4665c42e8c4SHaojian Zhuang 		goto out;
4675c42e8c4SHaojian Zhuang 
4685c42e8c4SHaojian Zhuang 	/* mask all IRQs */
4695c42e8c4SHaojian Zhuang 	memset(status_buf, 0, INT_STATUS_NUM);
4705c42e8c4SHaojian Zhuang 	ret = pm860x_bulk_write(i2c, PM8607_INT_MASK_1,
4715c42e8c4SHaojian Zhuang 				INT_STATUS_NUM, status_buf);
4725c42e8c4SHaojian Zhuang 	if (ret < 0)
4735c42e8c4SHaojian Zhuang 		goto out;
4745c42e8c4SHaojian Zhuang 
4755c42e8c4SHaojian Zhuang 	if (chip->irq_mode) {
4765c42e8c4SHaojian Zhuang 		/* clear interrupt status by write */
4775c42e8c4SHaojian Zhuang 		memset(status_buf, 0xFF, INT_STATUS_NUM);
4785c42e8c4SHaojian Zhuang 		ret = pm860x_bulk_write(i2c, PM8607_INT_STATUS1,
4795c42e8c4SHaojian Zhuang 					INT_STATUS_NUM, status_buf);
4805c42e8c4SHaojian Zhuang 	} else {
4815c42e8c4SHaojian Zhuang 		/* clear interrupt status by read */
4825c42e8c4SHaojian Zhuang 		ret = pm860x_bulk_read(i2c, PM8607_INT_STATUS1,
4835c42e8c4SHaojian Zhuang 					INT_STATUS_NUM, status_buf);
4845c42e8c4SHaojian Zhuang 	}
4855c42e8c4SHaojian Zhuang 	if (ret < 0)
4865c42e8c4SHaojian Zhuang 		goto out;
4875c42e8c4SHaojian Zhuang 
4882afa62eaSHaojian Zhuang 	mutex_init(&chip->irq_lock);
4892afa62eaSHaojian Zhuang 	chip->irq_base = pdata->irq_base;
4902afa62eaSHaojian Zhuang 	chip->core_irq = i2c->irq;
4912afa62eaSHaojian Zhuang 	if (!chip->core_irq)
4925c42e8c4SHaojian Zhuang 		goto out;
4932afa62eaSHaojian Zhuang 
4942afa62eaSHaojian Zhuang 	/* register IRQ by genirq */
4952afa62eaSHaojian Zhuang 	for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) {
4962afa62eaSHaojian Zhuang 		__irq = i + chip->irq_base;
497d5bb1221SThomas Gleixner 		irq_set_chip_data(__irq, chip);
498d5bb1221SThomas Gleixner 		irq_set_chip_and_handler(__irq, &pm860x_irq_chip,
4992afa62eaSHaojian Zhuang 					 handle_edge_irq);
500d5bb1221SThomas Gleixner 		irq_set_nested_thread(__irq, 1);
5012afa62eaSHaojian Zhuang #ifdef CONFIG_ARM
5022afa62eaSHaojian Zhuang 		set_irq_flags(__irq, IRQF_VALID);
5032afa62eaSHaojian Zhuang #else
504d5bb1221SThomas Gleixner 		irq_set_noprobe(__irq);
5052afa62eaSHaojian Zhuang #endif
5065c42e8c4SHaojian Zhuang 	}
5072afa62eaSHaojian Zhuang 
5082afa62eaSHaojian Zhuang 	ret = request_threaded_irq(chip->core_irq, NULL, pm860x_irq, flags,
5092afa62eaSHaojian Zhuang 				   "88pm860x", chip);
5102afa62eaSHaojian Zhuang 	if (ret) {
5112afa62eaSHaojian Zhuang 		dev_err(chip->dev, "Failed to request IRQ: %d\n", ret);
5122afa62eaSHaojian Zhuang 		chip->core_irq = 0;
5132afa62eaSHaojian Zhuang 	}
5142afa62eaSHaojian Zhuang 
5155c42e8c4SHaojian Zhuang 	return 0;
5165c42e8c4SHaojian Zhuang out:
5172afa62eaSHaojian Zhuang 	chip->core_irq = 0;
5185c42e8c4SHaojian Zhuang 	return ret;
5195c42e8c4SHaojian Zhuang }
5205c42e8c4SHaojian Zhuang 
521872c1b14SHenrik Kretzschmar static void device_irq_exit(struct pm860x_chip *chip)
5225c42e8c4SHaojian Zhuang {
5232afa62eaSHaojian Zhuang 	if (chip->core_irq)
5242afa62eaSHaojian Zhuang 		free_irq(chip->core_irq, chip);
5255c42e8c4SHaojian Zhuang }
5265c42e8c4SHaojian Zhuang 
52723de435aSJett.Zhou int pm8606_osc_enable(struct pm860x_chip *chip, unsigned short client)
52823de435aSJett.Zhou {
52923de435aSJett.Zhou 	int ret = -EIO;
53023de435aSJett.Zhou 	struct i2c_client *i2c = (chip->id == CHIP_PM8606) ?
53123de435aSJett.Zhou 		chip->client : chip->companion;
53223de435aSJett.Zhou 
53323de435aSJett.Zhou 	dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client);
53423de435aSJett.Zhou 	dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n",
53523de435aSJett.Zhou 			__func__, chip->osc_vote,
53623de435aSJett.Zhou 			chip->osc_status);
53723de435aSJett.Zhou 
53823de435aSJett.Zhou 	mutex_lock(&chip->osc_lock);
53923de435aSJett.Zhou 	/* Update voting status */
54023de435aSJett.Zhou 	chip->osc_vote |= client;
54123de435aSJett.Zhou 	/* If reference group is off - turn on*/
54223de435aSJett.Zhou 	if (chip->osc_status != PM8606_REF_GP_OSC_ON) {
54323de435aSJett.Zhou 		chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN;
54423de435aSJett.Zhou 		/* Enable Reference group Vsys */
54523de435aSJett.Zhou 		if (pm860x_set_bits(i2c, PM8606_VSYS,
54623de435aSJett.Zhou 				PM8606_VSYS_EN, PM8606_VSYS_EN))
54723de435aSJett.Zhou 			goto out;
54823de435aSJett.Zhou 
54923de435aSJett.Zhou 		/*Enable Internal Oscillator */
55023de435aSJett.Zhou 		if (pm860x_set_bits(i2c, PM8606_MISC,
55123de435aSJett.Zhou 				PM8606_MISC_OSC_EN, PM8606_MISC_OSC_EN))
55223de435aSJett.Zhou 			goto out;
55323de435aSJett.Zhou 		/* Update status (only if writes succeed) */
55423de435aSJett.Zhou 		chip->osc_status = PM8606_REF_GP_OSC_ON;
55523de435aSJett.Zhou 	}
55623de435aSJett.Zhou 	mutex_unlock(&chip->osc_lock);
55723de435aSJett.Zhou 
55823de435aSJett.Zhou 	dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n",
55923de435aSJett.Zhou 			__func__, chip->osc_vote,
56023de435aSJett.Zhou 			chip->osc_status, ret);
56123de435aSJett.Zhou 	return 0;
56223de435aSJett.Zhou out:
56323de435aSJett.Zhou 	mutex_unlock(&chip->osc_lock);
56423de435aSJett.Zhou 	return ret;
56523de435aSJett.Zhou }
5662f5f89beSSamuel Ortiz EXPORT_SYMBOL(pm8606_osc_enable);
56723de435aSJett.Zhou 
56823de435aSJett.Zhou int pm8606_osc_disable(struct pm860x_chip *chip, unsigned short client)
56923de435aSJett.Zhou {
57023de435aSJett.Zhou 	int ret = -EIO;
57123de435aSJett.Zhou 	struct i2c_client *i2c = (chip->id == CHIP_PM8606) ?
57223de435aSJett.Zhou 		chip->client : chip->companion;
57323de435aSJett.Zhou 
57423de435aSJett.Zhou 	dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client);
57523de435aSJett.Zhou 	dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n",
57623de435aSJett.Zhou 			__func__, chip->osc_vote,
57723de435aSJett.Zhou 			chip->osc_status);
57823de435aSJett.Zhou 
57923de435aSJett.Zhou 	mutex_lock(&chip->osc_lock);
58023de435aSJett.Zhou 	/*Update voting status */
58123de435aSJett.Zhou 	chip->osc_vote &= ~(client);
58223de435aSJett.Zhou 	/* If reference group is off and this is the last client to release
58323de435aSJett.Zhou 	 * - turn off */
58423de435aSJett.Zhou 	if ((chip->osc_status != PM8606_REF_GP_OSC_OFF) &&
58523de435aSJett.Zhou 			(chip->osc_vote == REF_GP_NO_CLIENTS)) {
58623de435aSJett.Zhou 		chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN;
58723de435aSJett.Zhou 		/* Disable Reference group Vsys */
58823de435aSJett.Zhou 		if (pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0))
58923de435aSJett.Zhou 			goto out;
59023de435aSJett.Zhou 		/* Disable Internal Oscillator */
59123de435aSJett.Zhou 		if (pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0))
59223de435aSJett.Zhou 			goto out;
59323de435aSJett.Zhou 		chip->osc_status = PM8606_REF_GP_OSC_OFF;
59423de435aSJett.Zhou 	}
59523de435aSJett.Zhou 	mutex_unlock(&chip->osc_lock);
59623de435aSJett.Zhou 
59723de435aSJett.Zhou 	dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n",
59823de435aSJett.Zhou 			__func__, chip->osc_vote,
59923de435aSJett.Zhou 			chip->osc_status, ret);
60023de435aSJett.Zhou 	return 0;
60123de435aSJett.Zhou out:
60223de435aSJett.Zhou 	mutex_unlock(&chip->osc_lock);
60323de435aSJett.Zhou 	return ret;
60423de435aSJett.Zhou }
6052f5f89beSSamuel Ortiz EXPORT_SYMBOL(pm8606_osc_disable);
60623de435aSJett.Zhou 
60723de435aSJett.Zhou static void __devinit device_osc_init(struct i2c_client *i2c)
60823de435aSJett.Zhou {
60923de435aSJett.Zhou 	struct pm860x_chip *chip = i2c_get_clientdata(i2c);
61023de435aSJett.Zhou 
61123de435aSJett.Zhou 	mutex_init(&chip->osc_lock);
61223de435aSJett.Zhou 	/* init portofino reference group voting and status */
61323de435aSJett.Zhou 	/* Disable Reference group Vsys */
61423de435aSJett.Zhou 	pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0);
61523de435aSJett.Zhou 	/* Disable Internal Oscillator */
61623de435aSJett.Zhou 	pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0);
61723de435aSJett.Zhou 
61823de435aSJett.Zhou 	chip->osc_vote = REF_GP_NO_CLIENTS;
61923de435aSJett.Zhou 	chip->osc_status = PM8606_REF_GP_OSC_OFF;
62023de435aSJett.Zhou }
62123de435aSJett.Zhou 
622adb70483SHaojian Zhuang static void __devinit device_bk_init(struct pm860x_chip *chip,
623adb70483SHaojian Zhuang 				     struct pm860x_platform_data *pdata)
624adb70483SHaojian Zhuang {
625adb70483SHaojian Zhuang 	int ret;
626adb70483SHaojian Zhuang 	int i, j, id;
627adb70483SHaojian Zhuang 
628adb70483SHaojian Zhuang 	if ((pdata == NULL) || (pdata->backlight == NULL))
629adb70483SHaojian Zhuang 		return;
630adb70483SHaojian Zhuang 
631adb70483SHaojian Zhuang 	if (pdata->num_backlights > ARRAY_SIZE(bk_devs))
632adb70483SHaojian Zhuang 		pdata->num_backlights = ARRAY_SIZE(bk_devs);
633adb70483SHaojian Zhuang 
634adb70483SHaojian Zhuang 	for (i = 0; i < pdata->num_backlights; i++) {
635f5fb758dSHaojian Zhuang 		bk_devs[i].platform_data = &pdata->backlight[i];
636f5fb758dSHaojian Zhuang 		bk_devs[i].pdata_size = sizeof(struct pm860x_backlight_pdata);
637adb70483SHaojian Zhuang 
638adb70483SHaojian Zhuang 		for (j = 0; j < ARRAY_SIZE(bk_devs); j++) {
639adb70483SHaojian Zhuang 			id = bk_resources[j].start;
640f5fb758dSHaojian Zhuang 			if (pdata->backlight[i].flags != id)
641adb70483SHaojian Zhuang 				continue;
642adb70483SHaojian Zhuang 
643adb70483SHaojian Zhuang 			bk_devs[i].num_resources = 1;
644adb70483SHaojian Zhuang 			bk_devs[i].resources = &bk_resources[j];
645adb70483SHaojian Zhuang 			ret = mfd_add_devices(chip->dev, 0,
646adb70483SHaojian Zhuang 					      &bk_devs[i], 1,
6470848c94fSMark Brown 					      &bk_resources[j], 0, NULL);
648adb70483SHaojian Zhuang 			if (ret < 0) {
649adb70483SHaojian Zhuang 				dev_err(chip->dev, "Failed to add "
650adb70483SHaojian Zhuang 					"backlight subdev\n");
651adb70483SHaojian Zhuang 				return;
652adb70483SHaojian Zhuang 			}
653adb70483SHaojian Zhuang 		}
654adb70483SHaojian Zhuang 	}
655adb70483SHaojian Zhuang }
656adb70483SHaojian Zhuang 
6573154c344SHaojian Zhuang static void __devinit device_led_init(struct pm860x_chip *chip,
65853dbab7aSHaojian Zhuang 				      struct pm860x_platform_data *pdata)
65953dbab7aSHaojian Zhuang {
660a16122bcSHaojian Zhuang 	int ret;
6613154c344SHaojian Zhuang 	int i, j, id;
662a16122bcSHaojian Zhuang 
6633154c344SHaojian Zhuang 	if ((pdata == NULL) || (pdata->led == NULL))
664a16122bcSHaojian Zhuang 		return;
6653154c344SHaojian Zhuang 
6663154c344SHaojian Zhuang 	if (pdata->num_leds > ARRAY_SIZE(led_devs))
6673154c344SHaojian Zhuang 		pdata->num_leds = ARRAY_SIZE(led_devs);
6683154c344SHaojian Zhuang 
6693154c344SHaojian Zhuang 	for (i = 0; i < pdata->num_leds; i++) {
670f5fb758dSHaojian Zhuang 		led_devs[i].platform_data = &pdata->led[i];
671f5fb758dSHaojian Zhuang 		led_devs[i].pdata_size = sizeof(struct pm860x_led_pdata);
6723154c344SHaojian Zhuang 
6733154c344SHaojian Zhuang 		for (j = 0; j < ARRAY_SIZE(led_devs); j++) {
6743154c344SHaojian Zhuang 			id = led_resources[j].start;
675f5fb758dSHaojian Zhuang 			if (pdata->led[i].flags != id)
6763154c344SHaojian Zhuang 				continue;
6773154c344SHaojian Zhuang 
6783154c344SHaojian Zhuang 			led_devs[i].num_resources = 1;
6793154c344SHaojian Zhuang 			led_devs[i].resources = &led_resources[j],
6803154c344SHaojian Zhuang 			ret = mfd_add_devices(chip->dev, 0,
6813154c344SHaojian Zhuang 					      &led_devs[i], 1,
6820848c94fSMark Brown 					      &led_resources[j], 0, NULL);
6833154c344SHaojian Zhuang 			if (ret < 0) {
6843154c344SHaojian Zhuang 				dev_err(chip->dev, "Failed to add "
6853154c344SHaojian Zhuang 					"led subdev\n");
6863154c344SHaojian Zhuang 				return;
6873154c344SHaojian Zhuang 			}
6883154c344SHaojian Zhuang 		}
6893154c344SHaojian Zhuang 	}
69053dbab7aSHaojian Zhuang }
69153dbab7aSHaojian Zhuang 
69222aad001SHaojian Zhuang static void __devinit device_regulator_init(struct pm860x_chip *chip,
69322aad001SHaojian Zhuang 					    struct pm860x_platform_data *pdata)
69422aad001SHaojian Zhuang {
69522aad001SHaojian Zhuang 	struct regulator_init_data *initdata;
69622aad001SHaojian Zhuang 	int ret;
697586e1a17SHaojian Zhuang 	int i, seq;
69822aad001SHaojian Zhuang 
69922aad001SHaojian Zhuang 	if ((pdata == NULL) || (pdata->regulator == NULL))
70022aad001SHaojian Zhuang 		return;
70122aad001SHaojian Zhuang 
70222aad001SHaojian Zhuang 	if (pdata->num_regulators > ARRAY_SIZE(regulator_devs))
70322aad001SHaojian Zhuang 		pdata->num_regulators = ARRAY_SIZE(regulator_devs);
70422aad001SHaojian Zhuang 
705586e1a17SHaojian Zhuang 	for (i = 0, seq = -1; i < pdata->num_regulators; i++) {
70622aad001SHaojian Zhuang 		initdata = &pdata->regulator[i];
707586e1a17SHaojian Zhuang 		seq = *(unsigned int *)initdata->driver_data;
708586e1a17SHaojian Zhuang 		if ((seq < 0) || (seq > PM8607_ID_RG_MAX)) {
709586e1a17SHaojian Zhuang 			dev_err(chip->dev, "Wrong ID(%d) on regulator(%s)\n",
710586e1a17SHaojian Zhuang 				seq, initdata->constraints.name);
71122aad001SHaojian Zhuang 			goto out;
71222aad001SHaojian Zhuang 		}
713f5fb758dSHaojian Zhuang 		regulator_devs[i].platform_data = &pdata->regulator[i];
714f5fb758dSHaojian Zhuang 		regulator_devs[i].pdata_size = sizeof(struct regulator_init_data);
71522aad001SHaojian Zhuang 		regulator_devs[i].num_resources = 1;
716586e1a17SHaojian Zhuang 		regulator_devs[i].resources = &regulator_resources[seq];
71722aad001SHaojian Zhuang 
71822aad001SHaojian Zhuang 		ret = mfd_add_devices(chip->dev, 0, &regulator_devs[i], 1,
7190848c94fSMark Brown 				      &regulator_resources[seq], 0, NULL);
72022aad001SHaojian Zhuang 		if (ret < 0) {
72122aad001SHaojian Zhuang 			dev_err(chip->dev, "Failed to add regulator subdev\n");
72222aad001SHaojian Zhuang 			goto out;
72322aad001SHaojian Zhuang 		}
72422aad001SHaojian Zhuang 	}
72522aad001SHaojian Zhuang out:
72622aad001SHaojian Zhuang 	return;
72722aad001SHaojian Zhuang }
72822aad001SHaojian Zhuang 
729008b3040SHaojian Zhuang static void __devinit device_rtc_init(struct pm860x_chip *chip,
730008b3040SHaojian Zhuang 				      struct pm860x_platform_data *pdata)
731008b3040SHaojian Zhuang {
732008b3040SHaojian Zhuang 	int ret;
733008b3040SHaojian Zhuang 
734008b3040SHaojian Zhuang 	if ((pdata == NULL))
735008b3040SHaojian Zhuang 		return;
736008b3040SHaojian Zhuang 
737008b3040SHaojian Zhuang 	rtc_devs[0].platform_data = pdata->rtc;
738008b3040SHaojian Zhuang 	rtc_devs[0].pdata_size = sizeof(struct pm860x_rtc_pdata);
739008b3040SHaojian Zhuang 	rtc_devs[0].num_resources = ARRAY_SIZE(rtc_resources);
740008b3040SHaojian Zhuang 	rtc_devs[0].resources = &rtc_resources[0];
741008b3040SHaojian Zhuang 	ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
742008b3040SHaojian Zhuang 			      ARRAY_SIZE(rtc_devs), &rtc_resources[0],
7430848c94fSMark Brown 			      chip->irq_base, NULL);
744008b3040SHaojian Zhuang 	if (ret < 0)
745008b3040SHaojian Zhuang 		dev_err(chip->dev, "Failed to add rtc subdev\n");
746008b3040SHaojian Zhuang }
747008b3040SHaojian Zhuang 
748c9f560b3SHaojian Zhuang static void __devinit device_touch_init(struct pm860x_chip *chip,
749c9f560b3SHaojian Zhuang 					struct pm860x_platform_data *pdata)
750c9f560b3SHaojian Zhuang {
751c9f560b3SHaojian Zhuang 	int ret;
752c9f560b3SHaojian Zhuang 
753f5fb758dSHaojian Zhuang 	if (pdata == NULL)
754c9f560b3SHaojian Zhuang 		return;
755c9f560b3SHaojian Zhuang 
756f5fb758dSHaojian Zhuang 	touch_devs[0].platform_data = pdata->touch;
757f5fb758dSHaojian Zhuang 	touch_devs[0].pdata_size = sizeof(struct pm860x_touch_pdata);
758c9f560b3SHaojian Zhuang 	touch_devs[0].num_resources = ARRAY_SIZE(touch_resources);
759c9f560b3SHaojian Zhuang 	touch_devs[0].resources = &touch_resources[0];
760c9f560b3SHaojian Zhuang 	ret = mfd_add_devices(chip->dev, 0, &touch_devs[0],
761c9f560b3SHaojian Zhuang 			      ARRAY_SIZE(touch_devs), &touch_resources[0],
7620848c94fSMark Brown 			      chip->irq_base, NULL);
763c9f560b3SHaojian Zhuang 	if (ret < 0)
764c9f560b3SHaojian Zhuang 		dev_err(chip->dev, "Failed to add touch subdev\n");
765c9f560b3SHaojian Zhuang }
766c9f560b3SHaojian Zhuang 
767c9f560b3SHaojian Zhuang static void __devinit device_power_init(struct pm860x_chip *chip,
768c9f560b3SHaojian Zhuang 					struct pm860x_platform_data *pdata)
769c9f560b3SHaojian Zhuang {
770c9f560b3SHaojian Zhuang 	int ret;
771c9f560b3SHaojian Zhuang 
772f5fb758dSHaojian Zhuang 	if (pdata == NULL)
773c9f560b3SHaojian Zhuang 		return;
774c9f560b3SHaojian Zhuang 
775f5fb758dSHaojian Zhuang 	power_devs[0].platform_data = pdata->power;
776f5fb758dSHaojian Zhuang 	power_devs[0].pdata_size = sizeof(struct pm860x_power_pdata);
777c9f560b3SHaojian Zhuang 	power_devs[0].num_resources = ARRAY_SIZE(battery_resources);
778c9f560b3SHaojian Zhuang 	power_devs[0].resources = &battery_resources[0],
779c9f560b3SHaojian Zhuang 	ret = mfd_add_devices(chip->dev, 0, &power_devs[0], 1,
7800848c94fSMark Brown 			      &battery_resources[0], chip->irq_base, NULL);
781c9f560b3SHaojian Zhuang 	if (ret < 0)
782c9f560b3SHaojian Zhuang 		dev_err(chip->dev, "Failed to add battery subdev\n");
783c9f560b3SHaojian Zhuang 
784f5fb758dSHaojian Zhuang 	power_devs[1].platform_data = pdata->power;
785f5fb758dSHaojian Zhuang 	power_devs[1].pdata_size = sizeof(struct pm860x_power_pdata);
786c9f560b3SHaojian Zhuang 	power_devs[1].num_resources = ARRAY_SIZE(charger_resources);
787c9f560b3SHaojian Zhuang 	power_devs[1].resources = &charger_resources[0],
788c9f560b3SHaojian Zhuang 	ret = mfd_add_devices(chip->dev, 0, &power_devs[1], 1,
7890848c94fSMark Brown 			      &charger_resources[0], chip->irq_base, NULL);
790c9f560b3SHaojian Zhuang 	if (ret < 0)
791c9f560b3SHaojian Zhuang 		dev_err(chip->dev, "Failed to add charger subdev\n");
7922573f6d3SJett.Zhou 
7932573f6d3SJett.Zhou 	power_devs[2].platform_data = &preg_init_data;
7942573f6d3SJett.Zhou 	power_devs[2].pdata_size = sizeof(struct regulator_init_data);
7952573f6d3SJett.Zhou 	power_devs[2].num_resources = ARRAY_SIZE(preg_resources);
7962573f6d3SJett.Zhou 	power_devs[2].resources = &preg_resources[0],
7972573f6d3SJett.Zhou 	ret = mfd_add_devices(chip->dev, 0, &power_devs[2], 1,
7980848c94fSMark Brown 			      &preg_resources[0], chip->irq_base, NULL);
7992573f6d3SJett.Zhou 	if (ret < 0)
8002573f6d3SJett.Zhou 		dev_err(chip->dev, "Failed to add preg subdev\n");
801a830d28bSJett.Zhou 
802a830d28bSJett.Zhou 	if (pdata->chg_desc) {
803a830d28bSJett.Zhou 		pdata->chg_desc->charger_regulators =
804a830d28bSJett.Zhou 			&chg_desc_regulator_data[0];
805a830d28bSJett.Zhou 		pdata->chg_desc->num_charger_regulators	=
806a830d28bSJett.Zhou 			ARRAY_SIZE(chg_desc_regulator_data),
807a830d28bSJett.Zhou 		power_devs[3].platform_data = pdata->chg_desc;
808a830d28bSJett.Zhou 		power_devs[3].pdata_size = sizeof(*pdata->chg_desc);
809a830d28bSJett.Zhou 		ret = mfd_add_devices(chip->dev, 0, &power_devs[3], 1,
81018766f09SAnton Vorontsov 				      NULL, chip->irq_base, NULL);
811a830d28bSJett.Zhou 		if (ret < 0)
812a830d28bSJett.Zhou 			dev_err(chip->dev, "Failed to add chg-manager subdev\n");
813a830d28bSJett.Zhou 	}
814c9f560b3SHaojian Zhuang }
815c9f560b3SHaojian Zhuang 
816c9f560b3SHaojian Zhuang static void __devinit device_onkey_init(struct pm860x_chip *chip,
817c9f560b3SHaojian Zhuang 					struct pm860x_platform_data *pdata)
818c9f560b3SHaojian Zhuang {
819c9f560b3SHaojian Zhuang 	int ret;
820c9f560b3SHaojian Zhuang 
821c9f560b3SHaojian Zhuang 	onkey_devs[0].num_resources = ARRAY_SIZE(onkey_resources);
822c9f560b3SHaojian Zhuang 	onkey_devs[0].resources = &onkey_resources[0],
823c9f560b3SHaojian Zhuang 	ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0],
824c9f560b3SHaojian Zhuang 			      ARRAY_SIZE(onkey_devs), &onkey_resources[0],
8250848c94fSMark Brown 			      chip->irq_base, NULL);
826c9f560b3SHaojian Zhuang 	if (ret < 0)
827c9f560b3SHaojian Zhuang 		dev_err(chip->dev, "Failed to add onkey subdev\n");
828c9f560b3SHaojian Zhuang }
829c9f560b3SHaojian Zhuang 
830c9f560b3SHaojian Zhuang static void __devinit device_codec_init(struct pm860x_chip *chip,
831c9f560b3SHaojian Zhuang 					struct pm860x_platform_data *pdata)
832c9f560b3SHaojian Zhuang {
833c9f560b3SHaojian Zhuang 	int ret;
834c9f560b3SHaojian Zhuang 
835c9f560b3SHaojian Zhuang 	codec_devs[0].num_resources = ARRAY_SIZE(codec_resources);
836c9f560b3SHaojian Zhuang 	codec_devs[0].resources = &codec_resources[0],
837c9f560b3SHaojian Zhuang 	ret = mfd_add_devices(chip->dev, 0, &codec_devs[0],
8380848c94fSMark Brown 			      ARRAY_SIZE(codec_devs), &codec_resources[0], 0,
8390848c94fSMark Brown 			      NULL);
840c9f560b3SHaojian Zhuang 	if (ret < 0)
841c9f560b3SHaojian Zhuang 		dev_err(chip->dev, "Failed to add codec subdev\n");
842c9f560b3SHaojian Zhuang }
843c9f560b3SHaojian Zhuang 
8445c42e8c4SHaojian Zhuang static void __devinit device_8607_init(struct pm860x_chip *chip,
8455c42e8c4SHaojian Zhuang 				       struct i2c_client *i2c,
84653dbab7aSHaojian Zhuang 				       struct pm860x_platform_data *pdata)
847bbd51b1fSHaojian Zhuang {
848a16122bcSHaojian Zhuang 	int data, ret;
849bbd51b1fSHaojian Zhuang 
85053dbab7aSHaojian Zhuang 	ret = pm860x_reg_read(i2c, PM8607_CHIP_ID);
851bbd51b1fSHaojian Zhuang 	if (ret < 0) {
852bbd51b1fSHaojian Zhuang 		dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
853bbd51b1fSHaojian Zhuang 		goto out;
854bbd51b1fSHaojian Zhuang 	}
85538b34052SHaojian Zhuang 	switch (ret & PM8607_VERSION_MASK) {
85638b34052SHaojian Zhuang 	case 0x40:
85738b34052SHaojian Zhuang 	case 0x50:
858bbd51b1fSHaojian Zhuang 		dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected\n",
859bbd51b1fSHaojian Zhuang 			 ret);
86038b34052SHaojian Zhuang 		break;
86138b34052SHaojian Zhuang 	default:
862bbd51b1fSHaojian Zhuang 		dev_err(chip->dev, "Failed to detect Marvell 88PM8607. "
863bbd51b1fSHaojian Zhuang 			"Chip ID: %02x\n", ret);
864bbd51b1fSHaojian Zhuang 		goto out;
865bbd51b1fSHaojian Zhuang 	}
866bbd51b1fSHaojian Zhuang 
86753dbab7aSHaojian Zhuang 	ret = pm860x_reg_read(i2c, PM8607_BUCK3);
868bbd51b1fSHaojian Zhuang 	if (ret < 0) {
869bbd51b1fSHaojian Zhuang 		dev_err(chip->dev, "Failed to read BUCK3 register: %d\n", ret);
870bbd51b1fSHaojian Zhuang 		goto out;
871bbd51b1fSHaojian Zhuang 	}
872bbd51b1fSHaojian Zhuang 	if (ret & PM8607_BUCK3_DOUBLE)
873bbd51b1fSHaojian Zhuang 		chip->buck3_double = 1;
874bbd51b1fSHaojian Zhuang 
8755c42e8c4SHaojian Zhuang 	ret = pm860x_reg_read(i2c, PM8607_B0_MISC1);
876bbd51b1fSHaojian Zhuang 	if (ret < 0) {
877bbd51b1fSHaojian Zhuang 		dev_err(chip->dev, "Failed to read MISC1 register: %d\n", ret);
878bbd51b1fSHaojian Zhuang 		goto out;
879bbd51b1fSHaojian Zhuang 	}
880bbd51b1fSHaojian Zhuang 
8815c42e8c4SHaojian Zhuang 	if (pdata && (pdata->i2c_port == PI2C_PORT))
8825c42e8c4SHaojian Zhuang 		data = PM8607_B0_MISC1_PI2C;
8835c42e8c4SHaojian Zhuang 	else
8845c42e8c4SHaojian Zhuang 		data = 0;
8855c42e8c4SHaojian Zhuang 	ret = pm860x_set_bits(i2c, PM8607_B0_MISC1, PM8607_B0_MISC1_PI2C, data);
8865c42e8c4SHaojian Zhuang 	if (ret < 0) {
8875c42e8c4SHaojian Zhuang 		dev_err(chip->dev, "Failed to access MISC1:%d\n", ret);
8885c42e8c4SHaojian Zhuang 		goto out;
8895c42e8c4SHaojian Zhuang 	}
8905c42e8c4SHaojian Zhuang 
891a16122bcSHaojian Zhuang 	ret = device_gpadc_init(chip, pdata);
892a16122bcSHaojian Zhuang 	if (ret < 0)
893a16122bcSHaojian Zhuang 		goto out;
894a16122bcSHaojian Zhuang 
8955c42e8c4SHaojian Zhuang 	ret = device_irq_init(chip, pdata);
8965c42e8c4SHaojian Zhuang 	if (ret < 0)
8975c42e8c4SHaojian Zhuang 		goto out;
8985c42e8c4SHaojian Zhuang 
899cea438ddSHaojian Zhuang 	device_regulator_init(chip, pdata);
900cea438ddSHaojian Zhuang 	device_rtc_init(chip, pdata);
901cea438ddSHaojian Zhuang 	device_onkey_init(chip, pdata);
902cea438ddSHaojian Zhuang 	device_touch_init(chip, pdata);
903cea438ddSHaojian Zhuang 	device_power_init(chip, pdata);
904cea438ddSHaojian Zhuang 	device_codec_init(chip, pdata);
905bbd51b1fSHaojian Zhuang out:
90653dbab7aSHaojian Zhuang 	return;
907bbd51b1fSHaojian Zhuang }
908bbd51b1fSHaojian Zhuang 
90978258064SJett.Zhou static void __devinit device_8606_init(struct pm860x_chip *chip,
91078258064SJett.Zhou 				       struct i2c_client *i2c,
91178258064SJett.Zhou 				       struct pm860x_platform_data *pdata)
91278258064SJett.Zhou {
91378258064SJett.Zhou 	device_osc_init(i2c);
91478258064SJett.Zhou 	device_bk_init(chip, pdata);
91578258064SJett.Zhou 	device_led_init(chip, pdata);
91678258064SJett.Zhou }
91778258064SJett.Zhou 
918872c1b14SHenrik Kretzschmar int __devinit pm860x_device_init(struct pm860x_chip *chip,
91953dbab7aSHaojian Zhuang 		       struct pm860x_platform_data *pdata)
92053dbab7aSHaojian Zhuang {
9212afa62eaSHaojian Zhuang 	chip->core_irq = 0;
9225c42e8c4SHaojian Zhuang 
92353dbab7aSHaojian Zhuang 	switch (chip->id) {
92453dbab7aSHaojian Zhuang 	case CHIP_PM8606:
92578258064SJett.Zhou 		device_8606_init(chip, chip->client, pdata);
92653dbab7aSHaojian Zhuang 		break;
92753dbab7aSHaojian Zhuang 	case CHIP_PM8607:
92853dbab7aSHaojian Zhuang 		device_8607_init(chip, chip->client, pdata);
92953dbab7aSHaojian Zhuang 		break;
93053dbab7aSHaojian Zhuang 	}
93153dbab7aSHaojian Zhuang 
93253dbab7aSHaojian Zhuang 	if (chip->companion) {
93353dbab7aSHaojian Zhuang 		switch (chip->id) {
93453dbab7aSHaojian Zhuang 		case CHIP_PM8607:
93578258064SJett.Zhou 			device_8606_init(chip, chip->companion, pdata);
93653dbab7aSHaojian Zhuang 			break;
93753dbab7aSHaojian Zhuang 		case CHIP_PM8606:
93853dbab7aSHaojian Zhuang 			device_8607_init(chip, chip->companion, pdata);
93953dbab7aSHaojian Zhuang 			break;
94053dbab7aSHaojian Zhuang 		}
94153dbab7aSHaojian Zhuang 	}
9425c42e8c4SHaojian Zhuang 
94353dbab7aSHaojian Zhuang 	return 0;
94453dbab7aSHaojian Zhuang }
94553dbab7aSHaojian Zhuang 
946872c1b14SHenrik Kretzschmar void __devexit pm860x_device_exit(struct pm860x_chip *chip)
947bbd51b1fSHaojian Zhuang {
9485c42e8c4SHaojian Zhuang 	device_irq_exit(chip);
949bbd51b1fSHaojian Zhuang 	mfd_remove_devices(chip->dev);
950bbd51b1fSHaojian Zhuang }
951bbd51b1fSHaojian Zhuang 
95253dbab7aSHaojian Zhuang MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM860x");
953bbd51b1fSHaojian Zhuang MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
954bbd51b1fSHaojian Zhuang MODULE_LICENSE("GPL");
955