xref: /openbmc/linux/drivers/mfd/88pm860x-core.c (revision 894fc8f2)
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>
21bbd51b1fSHaojian Zhuang 
222afa62eaSHaojian Zhuang #define INT_STATUS_NUM			3
232afa62eaSHaojian Zhuang 
24a6ccdcd9SHaojian Zhuang static struct resource bk0_resources[] __devinitdata = {
25a6ccdcd9SHaojian Zhuang 	{2, 2, "duty cycle", IORESOURCE_REG, },
26a6ccdcd9SHaojian Zhuang 	{3, 3, "always on",  IORESOURCE_REG, },
27a6ccdcd9SHaojian Zhuang 	{3, 3, "current",    IORESOURCE_REG, },
28a6ccdcd9SHaojian Zhuang };
29a6ccdcd9SHaojian Zhuang static struct resource bk1_resources[] __devinitdata = {
30a6ccdcd9SHaojian Zhuang 	{4, 4, "duty cycle", IORESOURCE_REG, },
31a6ccdcd9SHaojian Zhuang 	{5, 5, "always on",  IORESOURCE_REG, },
32a6ccdcd9SHaojian Zhuang 	{5, 5, "current",    IORESOURCE_REG, },
33a6ccdcd9SHaojian Zhuang };
34a6ccdcd9SHaojian Zhuang static struct resource bk2_resources[] __devinitdata = {
35a6ccdcd9SHaojian Zhuang 	{6, 6, "duty cycle", IORESOURCE_REG, },
36a6ccdcd9SHaojian Zhuang 	{7, 7, "always on",  IORESOURCE_REG, },
37a6ccdcd9SHaojian Zhuang 	{5, 5, "current",    IORESOURCE_REG, },
38a16122bcSHaojian Zhuang };
39adb70483SHaojian Zhuang 
40894fc8f2SHaojian Zhuang static struct resource led0_resources[] __devinitdata = {
41894fc8f2SHaojian Zhuang 	/* RGB1 Red LED */
42894fc8f2SHaojian Zhuang 	{0xd, 0xd, "control", IORESOURCE_REG, },
43894fc8f2SHaojian Zhuang 	{0xc, 0xc, "blink",   IORESOURCE_REG, },
44894fc8f2SHaojian Zhuang };
45894fc8f2SHaojian Zhuang static struct resource led1_resources[] __devinitdata = {
46894fc8f2SHaojian Zhuang 	/* RGB1 Green LED */
47894fc8f2SHaojian Zhuang 	{0xe, 0xe, "control", IORESOURCE_REG, },
48894fc8f2SHaojian Zhuang 	{0xc, 0xc, "blink",   IORESOURCE_REG, },
49894fc8f2SHaojian Zhuang };
50894fc8f2SHaojian Zhuang static struct resource led2_resources[] __devinitdata = {
51894fc8f2SHaojian Zhuang 	/* RGB1 Blue LED */
52894fc8f2SHaojian Zhuang 	{0xf, 0xf, "control", IORESOURCE_REG, },
53894fc8f2SHaojian Zhuang 	{0xc, 0xc, "blink",   IORESOURCE_REG, },
54894fc8f2SHaojian Zhuang };
55894fc8f2SHaojian Zhuang static struct resource led3_resources[] __devinitdata = {
56894fc8f2SHaojian Zhuang 	/* RGB2 Red LED */
57894fc8f2SHaojian Zhuang 	{0x9, 0x9, "control", IORESOURCE_REG, },
58894fc8f2SHaojian Zhuang 	{0x8, 0x8, "blink",   IORESOURCE_REG, },
59894fc8f2SHaojian Zhuang };
60894fc8f2SHaojian Zhuang static struct resource led4_resources[] __devinitdata = {
61894fc8f2SHaojian Zhuang 	/* RGB2 Green LED */
62894fc8f2SHaojian Zhuang 	{0xa, 0xa, "control", IORESOURCE_REG, },
63894fc8f2SHaojian Zhuang 	{0x8, 0x8, "blink",   IORESOURCE_REG, },
64894fc8f2SHaojian Zhuang };
65894fc8f2SHaojian Zhuang static struct resource led5_resources[] __devinitdata = {
66894fc8f2SHaojian Zhuang 	/* RGB2 Blue LED */
67894fc8f2SHaojian Zhuang 	{0xb, 0xb, "control", IORESOURCE_REG, },
68894fc8f2SHaojian Zhuang 	{0x8, 0x8, "blink",   IORESOURCE_REG, },
693154c344SHaojian Zhuang };
703154c344SHaojian Zhuang 
71a5156f1aSHaojian Zhuang static struct resource regulator_resources[] __devinitdata = {
7202367029SMark Brown 	{PM8607_ID_BUCK1, PM8607_ID_BUCK1, "buck-1", IORESOURCE_REG,},
7302367029SMark Brown 	{PM8607_ID_BUCK2, PM8607_ID_BUCK2, "buck-2", IORESOURCE_REG,},
7402367029SMark Brown 	{PM8607_ID_BUCK3, PM8607_ID_BUCK3, "buck-3", IORESOURCE_REG,},
7502367029SMark Brown 	{PM8607_ID_LDO1,  PM8607_ID_LDO1,  "ldo-01", IORESOURCE_REG,},
7602367029SMark Brown 	{PM8607_ID_LDO2,  PM8607_ID_LDO2,  "ldo-02", IORESOURCE_REG,},
7702367029SMark Brown 	{PM8607_ID_LDO3,  PM8607_ID_LDO3,  "ldo-03", IORESOURCE_REG,},
7802367029SMark Brown 	{PM8607_ID_LDO4,  PM8607_ID_LDO4,  "ldo-04", IORESOURCE_REG,},
7902367029SMark Brown 	{PM8607_ID_LDO5,  PM8607_ID_LDO5,  "ldo-05", IORESOURCE_REG,},
8002367029SMark Brown 	{PM8607_ID_LDO6,  PM8607_ID_LDO6,  "ldo-06", IORESOURCE_REG,},
8102367029SMark Brown 	{PM8607_ID_LDO7,  PM8607_ID_LDO7,  "ldo-07", IORESOURCE_REG,},
8202367029SMark Brown 	{PM8607_ID_LDO8,  PM8607_ID_LDO8,  "ldo-08", IORESOURCE_REG,},
8302367029SMark Brown 	{PM8607_ID_LDO9,  PM8607_ID_LDO9,  "ldo-09", IORESOURCE_REG,},
8402367029SMark Brown 	{PM8607_ID_LDO10, PM8607_ID_LDO10, "ldo-10", IORESOURCE_REG,},
8502367029SMark Brown 	{PM8607_ID_LDO11, PM8607_ID_LDO11, "ldo-11", IORESOURCE_REG,},
8602367029SMark Brown 	{PM8607_ID_LDO12, PM8607_ID_LDO12, "ldo-12", IORESOURCE_REG,},
8702367029SMark Brown 	{PM8607_ID_LDO13, PM8607_ID_LDO13, "ldo-13", IORESOURCE_REG,},
8802367029SMark Brown 	{PM8607_ID_LDO14, PM8607_ID_LDO14, "ldo-14", IORESOURCE_REG,},
8902367029SMark Brown 	{PM8607_ID_LDO15, PM8607_ID_LDO15, "ldo-15", IORESOURCE_REG,},
9022aad001SHaojian Zhuang };
9122aad001SHaojian Zhuang 
92a5156f1aSHaojian Zhuang static struct resource touch_resources[] __devinitdata = {
93c9f560b3SHaojian Zhuang 	{PM8607_IRQ_PEN, PM8607_IRQ_PEN, "touch", IORESOURCE_IRQ,},
94c9f560b3SHaojian Zhuang };
95c9f560b3SHaojian Zhuang 
96a5156f1aSHaojian Zhuang static struct resource onkey_resources[] __devinitdata = {
97c9f560b3SHaojian Zhuang 	{PM8607_IRQ_ONKEY, PM8607_IRQ_ONKEY, "onkey", IORESOURCE_IRQ,},
98c9f560b3SHaojian Zhuang };
99c9f560b3SHaojian Zhuang 
100a5156f1aSHaojian Zhuang static struct resource codec_resources[] __devinitdata = {
101c9f560b3SHaojian Zhuang 	/* Headset microphone insertion or removal */
102c9f560b3SHaojian Zhuang 	{PM8607_IRQ_MICIN,   PM8607_IRQ_MICIN,   "micin",   IORESOURCE_IRQ,},
103c9f560b3SHaojian Zhuang 	/* Hook-switch press or release */
104c9f560b3SHaojian Zhuang 	{PM8607_IRQ_HOOK,    PM8607_IRQ_HOOK,    "hook",    IORESOURCE_IRQ,},
105c9f560b3SHaojian Zhuang 	/* Headset insertion or removal */
106c9f560b3SHaojian Zhuang 	{PM8607_IRQ_HEADSET, PM8607_IRQ_HEADSET, "headset", IORESOURCE_IRQ,},
107c9f560b3SHaojian Zhuang 	/* Audio short */
108c9f560b3SHaojian Zhuang 	{PM8607_IRQ_AUDIO_SHORT, PM8607_IRQ_AUDIO_SHORT, "audio-short", IORESOURCE_IRQ,},
109c9f560b3SHaojian Zhuang };
110c9f560b3SHaojian Zhuang 
111a5156f1aSHaojian Zhuang static struct resource battery_resources[] __devinitdata = {
112c9f560b3SHaojian Zhuang 	{PM8607_IRQ_CC,  PM8607_IRQ_CC,  "columb counter", IORESOURCE_IRQ,},
113c9f560b3SHaojian Zhuang 	{PM8607_IRQ_BAT, PM8607_IRQ_BAT, "battery",        IORESOURCE_IRQ,},
114c9f560b3SHaojian Zhuang };
115c9f560b3SHaojian Zhuang 
116a5156f1aSHaojian Zhuang static struct resource charger_resources[] __devinitdata = {
117c9f560b3SHaojian Zhuang 	{PM8607_IRQ_CHG,  PM8607_IRQ_CHG,  "charger detect",  IORESOURCE_IRQ,},
118c9f560b3SHaojian Zhuang 	{PM8607_IRQ_CHG_DONE,  PM8607_IRQ_CHG_DONE,  "charging done",       IORESOURCE_IRQ,},
119c9f560b3SHaojian Zhuang 	{PM8607_IRQ_CHG_FAULT, PM8607_IRQ_CHG_FAULT, "charging timeout",    IORESOURCE_IRQ,},
120c9f560b3SHaojian Zhuang 	{PM8607_IRQ_GPADC1,    PM8607_IRQ_GPADC1,    "battery temperature", IORESOURCE_IRQ,},
121c9f560b3SHaojian Zhuang 	{PM8607_IRQ_VBAT, PM8607_IRQ_VBAT, "battery voltage", IORESOURCE_IRQ,},
122c9f560b3SHaojian Zhuang 	{PM8607_IRQ_VCHG, PM8607_IRQ_VCHG, "vchg voltage",    IORESOURCE_IRQ,},
123c9f560b3SHaojian Zhuang };
124c9f560b3SHaojian Zhuang 
1252573f6d3SJett.Zhou static struct resource preg_resources[] __devinitdata = {
12602367029SMark Brown 	{PM8606_ID_PREG,  PM8606_ID_PREG,  "preg",   IORESOURCE_REG,},
1272573f6d3SJett.Zhou };
1282573f6d3SJett.Zhou 
129008b3040SHaojian Zhuang static struct resource rtc_resources[] __devinitdata = {
13002367029SMark Brown 	{PM8607_IRQ_RTC, PM8607_IRQ_RTC, "rtc", IORESOURCE_IRQ,},
131008b3040SHaojian Zhuang };
132008b3040SHaojian Zhuang 
133a5156f1aSHaojian Zhuang static struct mfd_cell bk_devs[] = {
134a6ccdcd9SHaojian Zhuang 	{
135a6ccdcd9SHaojian Zhuang 		.name = "88pm860x-backlight",
136a6ccdcd9SHaojian Zhuang 		.id = 0,
137a6ccdcd9SHaojian Zhuang 		.num_resources = ARRAY_SIZE(bk0_resources),
138a6ccdcd9SHaojian Zhuang 		.resources = bk0_resources,
139a6ccdcd9SHaojian Zhuang 	}, {
140a6ccdcd9SHaojian Zhuang 		.name = "88pm860x-backlight",
141a6ccdcd9SHaojian Zhuang 		.id = 1,
142a6ccdcd9SHaojian Zhuang 		.num_resources = ARRAY_SIZE(bk1_resources),
143a6ccdcd9SHaojian Zhuang 		.resources = bk1_resources,
144a6ccdcd9SHaojian Zhuang 	}, {
145a6ccdcd9SHaojian Zhuang 		.name = "88pm860x-backlight",
146a6ccdcd9SHaojian Zhuang 		.id = 2,
147a6ccdcd9SHaojian Zhuang 		.num_resources = ARRAY_SIZE(bk2_resources),
148a6ccdcd9SHaojian Zhuang 		.resources = bk2_resources,
149a6ccdcd9SHaojian Zhuang 	},
150adb70483SHaojian Zhuang };
151adb70483SHaojian Zhuang 
152a5156f1aSHaojian Zhuang static struct mfd_cell led_devs[] = {
153894fc8f2SHaojian Zhuang 	{
154894fc8f2SHaojian Zhuang 		.name = "88pm860x-led",
155894fc8f2SHaojian Zhuang 		.id = 0,
156894fc8f2SHaojian Zhuang 		.num_resources = ARRAY_SIZE(led0_resources),
157894fc8f2SHaojian Zhuang 		.resources = led0_resources,
158894fc8f2SHaojian Zhuang 	}, {
159894fc8f2SHaojian Zhuang 		.name = "88pm860x-led",
160894fc8f2SHaojian Zhuang 		.id = 1,
161894fc8f2SHaojian Zhuang 		.num_resources = ARRAY_SIZE(led1_resources),
162894fc8f2SHaojian Zhuang 		.resources = led1_resources,
163894fc8f2SHaojian Zhuang 	}, {
164894fc8f2SHaojian Zhuang 		.name = "88pm860x-led",
165894fc8f2SHaojian Zhuang 		.id = 2,
166894fc8f2SHaojian Zhuang 		.num_resources = ARRAY_SIZE(led2_resources),
167894fc8f2SHaojian Zhuang 		.resources = led2_resources,
168894fc8f2SHaojian Zhuang 	}, {
169894fc8f2SHaojian Zhuang 		.name = "88pm860x-led",
170894fc8f2SHaojian Zhuang 		.id = 3,
171894fc8f2SHaojian Zhuang 		.num_resources = ARRAY_SIZE(led3_resources),
172894fc8f2SHaojian Zhuang 		.resources = led3_resources,
173894fc8f2SHaojian Zhuang 	}, {
174894fc8f2SHaojian Zhuang 		.name = "88pm860x-led",
175894fc8f2SHaojian Zhuang 		.id = 4,
176894fc8f2SHaojian Zhuang 		.num_resources = ARRAY_SIZE(led4_resources),
177894fc8f2SHaojian Zhuang 		.resources = led4_resources,
178894fc8f2SHaojian Zhuang 	}, {
179894fc8f2SHaojian Zhuang 		.name = "88pm860x-led",
180894fc8f2SHaojian Zhuang 		.id = 5,
181894fc8f2SHaojian Zhuang 		.num_resources = ARRAY_SIZE(led5_resources),
182894fc8f2SHaojian Zhuang 		.resources = led5_resources,
183894fc8f2SHaojian Zhuang 	},
1843154c344SHaojian Zhuang };
1853154c344SHaojian Zhuang 
186a5156f1aSHaojian Zhuang static struct mfd_cell regulator_devs[] = {
18722aad001SHaojian Zhuang 	{"88pm860x-regulator", 0,},
18822aad001SHaojian Zhuang 	{"88pm860x-regulator", 1,},
18922aad001SHaojian Zhuang 	{"88pm860x-regulator", 2,},
19022aad001SHaojian Zhuang 	{"88pm860x-regulator", 3,},
19122aad001SHaojian Zhuang 	{"88pm860x-regulator", 4,},
19222aad001SHaojian Zhuang 	{"88pm860x-regulator", 5,},
19322aad001SHaojian Zhuang 	{"88pm860x-regulator", 6,},
19422aad001SHaojian Zhuang 	{"88pm860x-regulator", 7,},
19522aad001SHaojian Zhuang 	{"88pm860x-regulator", 8,},
19622aad001SHaojian Zhuang 	{"88pm860x-regulator", 9,},
19722aad001SHaojian Zhuang 	{"88pm860x-regulator", 10,},
19822aad001SHaojian Zhuang 	{"88pm860x-regulator", 11,},
19922aad001SHaojian Zhuang 	{"88pm860x-regulator", 12,},
20022aad001SHaojian Zhuang 	{"88pm860x-regulator", 13,},
20122aad001SHaojian Zhuang 	{"88pm860x-regulator", 14,},
20222aad001SHaojian Zhuang 	{"88pm860x-regulator", 15,},
20322aad001SHaojian Zhuang 	{"88pm860x-regulator", 16,},
20422aad001SHaojian Zhuang 	{"88pm860x-regulator", 17,},
20522aad001SHaojian Zhuang };
20622aad001SHaojian Zhuang 
207a5156f1aSHaojian Zhuang static struct mfd_cell touch_devs[] = {
208c9f560b3SHaojian Zhuang 	{"88pm860x-touch", -1,},
209a16122bcSHaojian Zhuang };
210a16122bcSHaojian Zhuang 
211a5156f1aSHaojian Zhuang static struct mfd_cell onkey_devs[] = {
212c9f560b3SHaojian Zhuang 	{"88pm860x-onkey", -1,},
213a16122bcSHaojian Zhuang };
214bbd51b1fSHaojian Zhuang 
215a5156f1aSHaojian Zhuang static struct mfd_cell codec_devs[] = {
216c9f560b3SHaojian Zhuang 	{"88pm860x-codec", -1,},
2172afa62eaSHaojian Zhuang };
2182afa62eaSHaojian Zhuang 
2192573f6d3SJett.Zhou static struct regulator_consumer_supply preg_supply[] = {
2202573f6d3SJett.Zhou 	REGULATOR_SUPPLY("preg", "charger-manager"),
2212573f6d3SJett.Zhou };
2222573f6d3SJett.Zhou 
2232573f6d3SJett.Zhou static struct regulator_init_data preg_init_data = {
2242573f6d3SJett.Zhou 	.num_consumer_supplies	= ARRAY_SIZE(preg_supply),
2252573f6d3SJett.Zhou 	.consumer_supplies	= &preg_supply[0],
2262573f6d3SJett.Zhou };
2272573f6d3SJett.Zhou 
2282afa62eaSHaojian Zhuang static struct mfd_cell power_devs[] = {
229c9f560b3SHaojian Zhuang 	{"88pm860x-battery", -1,},
230c9f560b3SHaojian Zhuang 	{"88pm860x-charger", -1,},
2312573f6d3SJett.Zhou 	{"88pm860x-preg",    -1,},
2322afa62eaSHaojian Zhuang };
2332afa62eaSHaojian Zhuang 
234008b3040SHaojian Zhuang static struct mfd_cell rtc_devs[] = {
235008b3040SHaojian Zhuang 	{"88pm860x-rtc", -1,},
236008b3040SHaojian Zhuang };
237008b3040SHaojian Zhuang 
2382c36af7bSHaojian Zhuang 
2392afa62eaSHaojian Zhuang struct pm860x_irq_data {
2402afa62eaSHaojian Zhuang 	int	reg;
2412afa62eaSHaojian Zhuang 	int	mask_reg;
2422afa62eaSHaojian Zhuang 	int	enable;		/* enable or not */
2432afa62eaSHaojian Zhuang 	int	offs;		/* bit offset in mask register */
2442afa62eaSHaojian Zhuang };
2455c42e8c4SHaojian Zhuang 
2462afa62eaSHaojian Zhuang static struct pm860x_irq_data pm860x_irqs[] = {
2472afa62eaSHaojian Zhuang 	[PM8607_IRQ_ONKEY] = {
2482afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS1,
2492afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_1,
2502afa62eaSHaojian Zhuang 		.offs		= 1 << 0,
2512afa62eaSHaojian Zhuang 	},
2522afa62eaSHaojian Zhuang 	[PM8607_IRQ_EXTON] = {
2532afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS1,
2542afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_1,
2552afa62eaSHaojian Zhuang 		.offs		= 1 << 1,
2562afa62eaSHaojian Zhuang 	},
2572afa62eaSHaojian Zhuang 	[PM8607_IRQ_CHG] = {
2582afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS1,
2592afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_1,
2602afa62eaSHaojian Zhuang 		.offs		= 1 << 2,
2612afa62eaSHaojian Zhuang 	},
2622afa62eaSHaojian Zhuang 	[PM8607_IRQ_BAT] = {
2632afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS1,
2642afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_1,
2652afa62eaSHaojian Zhuang 		.offs		= 1 << 3,
2662afa62eaSHaojian Zhuang 	},
2672afa62eaSHaojian Zhuang 	[PM8607_IRQ_RTC] = {
2682afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS1,
2692afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_1,
2702afa62eaSHaojian Zhuang 		.offs		= 1 << 4,
2712afa62eaSHaojian Zhuang 	},
2722afa62eaSHaojian Zhuang 	[PM8607_IRQ_CC] = {
2732afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS1,
2742afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_1,
2752afa62eaSHaojian Zhuang 		.offs		= 1 << 5,
2762afa62eaSHaojian Zhuang 	},
2772afa62eaSHaojian Zhuang 	[PM8607_IRQ_VBAT] = {
2782afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS2,
2792afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_2,
2802afa62eaSHaojian Zhuang 		.offs		= 1 << 0,
2812afa62eaSHaojian Zhuang 	},
2822afa62eaSHaojian Zhuang 	[PM8607_IRQ_VCHG] = {
2832afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS2,
2842afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_2,
2852afa62eaSHaojian Zhuang 		.offs		= 1 << 1,
2862afa62eaSHaojian Zhuang 	},
2872afa62eaSHaojian Zhuang 	[PM8607_IRQ_VSYS] = {
2882afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS2,
2892afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_2,
2902afa62eaSHaojian Zhuang 		.offs		= 1 << 2,
2912afa62eaSHaojian Zhuang 	},
2922afa62eaSHaojian Zhuang 	[PM8607_IRQ_TINT] = {
2932afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS2,
2942afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_2,
2952afa62eaSHaojian Zhuang 		.offs		= 1 << 3,
2962afa62eaSHaojian Zhuang 	},
2972afa62eaSHaojian Zhuang 	[PM8607_IRQ_GPADC0] = {
2982afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS2,
2992afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_2,
3002afa62eaSHaojian Zhuang 		.offs		= 1 << 4,
3012afa62eaSHaojian Zhuang 	},
3022afa62eaSHaojian Zhuang 	[PM8607_IRQ_GPADC1] = {
3032afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS2,
3042afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_2,
3052afa62eaSHaojian Zhuang 		.offs		= 1 << 5,
3062afa62eaSHaojian Zhuang 	},
3072afa62eaSHaojian Zhuang 	[PM8607_IRQ_GPADC2] = {
3082afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS2,
3092afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_2,
3102afa62eaSHaojian Zhuang 		.offs		= 1 << 6,
3112afa62eaSHaojian Zhuang 	},
3122afa62eaSHaojian Zhuang 	[PM8607_IRQ_GPADC3] = {
3132afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS2,
3142afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_2,
3152afa62eaSHaojian Zhuang 		.offs		= 1 << 7,
3162afa62eaSHaojian Zhuang 	},
3172afa62eaSHaojian Zhuang 	[PM8607_IRQ_AUDIO_SHORT] = {
3182afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS3,
3192afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_3,
3202afa62eaSHaojian Zhuang 		.offs		= 1 << 0,
3212afa62eaSHaojian Zhuang 	},
3222afa62eaSHaojian Zhuang 	[PM8607_IRQ_PEN] = {
3232afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS3,
3242afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_3,
3252afa62eaSHaojian Zhuang 		.offs		= 1 << 1,
3262afa62eaSHaojian Zhuang 	},
3272afa62eaSHaojian Zhuang 	[PM8607_IRQ_HEADSET] = {
3282afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS3,
3292afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_3,
3302afa62eaSHaojian Zhuang 		.offs		= 1 << 2,
3312afa62eaSHaojian Zhuang 	},
3322afa62eaSHaojian Zhuang 	[PM8607_IRQ_HOOK] = {
3332afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS3,
3342afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_3,
3352afa62eaSHaojian Zhuang 		.offs		= 1 << 3,
3362afa62eaSHaojian Zhuang 	},
3372afa62eaSHaojian Zhuang 	[PM8607_IRQ_MICIN] = {
3382afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS3,
3392afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_3,
3402afa62eaSHaojian Zhuang 		.offs		= 1 << 4,
3412afa62eaSHaojian Zhuang 	},
3422afa62eaSHaojian Zhuang 	[PM8607_IRQ_CHG_FAIL] = {
3432afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS3,
3442afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_3,
3452afa62eaSHaojian Zhuang 		.offs		= 1 << 5,
3462afa62eaSHaojian Zhuang 	},
3472afa62eaSHaojian Zhuang 	[PM8607_IRQ_CHG_DONE] = {
3482afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS3,
3492afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_3,
3502afa62eaSHaojian Zhuang 		.offs		= 1 << 6,
3512afa62eaSHaojian Zhuang 	},
3522afa62eaSHaojian Zhuang 	[PM8607_IRQ_CHG_FAULT] = {
3532afa62eaSHaojian Zhuang 		.reg		= PM8607_INT_STATUS3,
3542afa62eaSHaojian Zhuang 		.mask_reg	= PM8607_INT_MASK_3,
3552afa62eaSHaojian Zhuang 		.offs		= 1 << 7,
3562afa62eaSHaojian Zhuang 	},
3572afa62eaSHaojian Zhuang };
3582afa62eaSHaojian Zhuang 
3592afa62eaSHaojian Zhuang static irqreturn_t pm860x_irq(int irq, void *data)
3605c42e8c4SHaojian Zhuang {
3615c42e8c4SHaojian Zhuang 	struct pm860x_chip *chip = data;
3622afa62eaSHaojian Zhuang 	struct pm860x_irq_data *irq_data;
3632afa62eaSHaojian Zhuang 	struct i2c_client *i2c;
3642afa62eaSHaojian Zhuang 	int read_reg = -1, value = 0;
3652afa62eaSHaojian Zhuang 	int i;
3665c42e8c4SHaojian Zhuang 
3672afa62eaSHaojian Zhuang 	i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
3682afa62eaSHaojian Zhuang 	for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) {
3692afa62eaSHaojian Zhuang 		irq_data = &pm860x_irqs[i];
3702afa62eaSHaojian Zhuang 		if (read_reg != irq_data->reg) {
3712afa62eaSHaojian Zhuang 			read_reg = irq_data->reg;
3722afa62eaSHaojian Zhuang 			value = pm860x_reg_read(i2c, irq_data->reg);
3735c42e8c4SHaojian Zhuang 		}
3742afa62eaSHaojian Zhuang 		if (value & irq_data->enable)
3752afa62eaSHaojian Zhuang 			handle_nested_irq(chip->irq_base + i);
3765c42e8c4SHaojian Zhuang 	}
3775c42e8c4SHaojian Zhuang 	return IRQ_HANDLED;
3785c42e8c4SHaojian Zhuang }
3795c42e8c4SHaojian Zhuang 
38049f89d9aSMark Brown static void pm860x_irq_lock(struct irq_data *data)
3815c42e8c4SHaojian Zhuang {
38249f89d9aSMark Brown 	struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
3835c42e8c4SHaojian Zhuang 
3845c42e8c4SHaojian Zhuang 	mutex_lock(&chip->irq_lock);
3855c42e8c4SHaojian Zhuang }
3865c42e8c4SHaojian Zhuang 
38749f89d9aSMark Brown static void pm860x_irq_sync_unlock(struct irq_data *data)
3885c42e8c4SHaojian Zhuang {
38949f89d9aSMark Brown 	struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
3902afa62eaSHaojian Zhuang 	struct pm860x_irq_data *irq_data;
3912afa62eaSHaojian Zhuang 	struct i2c_client *i2c;
3922afa62eaSHaojian Zhuang 	static unsigned char cached[3] = {0x0, 0x0, 0x0};
3932afa62eaSHaojian Zhuang 	unsigned char mask[3];
3942afa62eaSHaojian Zhuang 	int i;
3955c42e8c4SHaojian Zhuang 
3962afa62eaSHaojian Zhuang 	i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
3972afa62eaSHaojian Zhuang 	/* Load cached value. In initial, all IRQs are masked */
3982afa62eaSHaojian Zhuang 	for (i = 0; i < 3; i++)
3992afa62eaSHaojian Zhuang 		mask[i] = cached[i];
4002afa62eaSHaojian Zhuang 	for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) {
4012afa62eaSHaojian Zhuang 		irq_data = &pm860x_irqs[i];
4022afa62eaSHaojian Zhuang 		switch (irq_data->mask_reg) {
4032afa62eaSHaojian Zhuang 		case PM8607_INT_MASK_1:
4042afa62eaSHaojian Zhuang 			mask[0] &= ~irq_data->offs;
4052afa62eaSHaojian Zhuang 			mask[0] |= irq_data->enable;
4062afa62eaSHaojian Zhuang 			break;
4072afa62eaSHaojian Zhuang 		case PM8607_INT_MASK_2:
4082afa62eaSHaojian Zhuang 			mask[1] &= ~irq_data->offs;
4092afa62eaSHaojian Zhuang 			mask[1] |= irq_data->enable;
4102afa62eaSHaojian Zhuang 			break;
4112afa62eaSHaojian Zhuang 		case PM8607_INT_MASK_3:
4122afa62eaSHaojian Zhuang 			mask[2] &= ~irq_data->offs;
4132afa62eaSHaojian Zhuang 			mask[2] |= irq_data->enable;
4142afa62eaSHaojian Zhuang 			break;
4152afa62eaSHaojian Zhuang 		default:
4162afa62eaSHaojian Zhuang 			dev_err(chip->dev, "wrong IRQ\n");
4172afa62eaSHaojian Zhuang 			break;
4185c42e8c4SHaojian Zhuang 		}
4192afa62eaSHaojian Zhuang 	}
4202afa62eaSHaojian Zhuang 	/* update mask into registers */
4212afa62eaSHaojian Zhuang 	for (i = 0; i < 3; i++) {
4222afa62eaSHaojian Zhuang 		if (mask[i] != cached[i]) {
4232afa62eaSHaojian Zhuang 			cached[i] = mask[i];
4242afa62eaSHaojian Zhuang 			pm860x_reg_write(i2c, PM8607_INT_MASK_1 + i, mask[i]);
4252afa62eaSHaojian Zhuang 		}
4262afa62eaSHaojian Zhuang 	}
4272afa62eaSHaojian Zhuang 
4282afa62eaSHaojian Zhuang 	mutex_unlock(&chip->irq_lock);
4292afa62eaSHaojian Zhuang }
4302afa62eaSHaojian Zhuang 
43149f89d9aSMark Brown static void pm860x_irq_enable(struct irq_data *data)
4322afa62eaSHaojian Zhuang {
43349f89d9aSMark Brown 	struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
43449f89d9aSMark Brown 	pm860x_irqs[data->irq - chip->irq_base].enable
43549f89d9aSMark Brown 		= pm860x_irqs[data->irq - chip->irq_base].offs;
4362afa62eaSHaojian Zhuang }
4372afa62eaSHaojian Zhuang 
43849f89d9aSMark Brown static void pm860x_irq_disable(struct irq_data *data)
4392afa62eaSHaojian Zhuang {
44049f89d9aSMark Brown 	struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
44149f89d9aSMark Brown 	pm860x_irqs[data->irq - chip->irq_base].enable = 0;
4422afa62eaSHaojian Zhuang }
4432afa62eaSHaojian Zhuang 
4442afa62eaSHaojian Zhuang static struct irq_chip pm860x_irq_chip = {
4452afa62eaSHaojian Zhuang 	.name		= "88pm860x",
44649f89d9aSMark Brown 	.irq_bus_lock	= pm860x_irq_lock,
44749f89d9aSMark Brown 	.irq_bus_sync_unlock = pm860x_irq_sync_unlock,
44849f89d9aSMark Brown 	.irq_enable	= pm860x_irq_enable,
44949f89d9aSMark Brown 	.irq_disable	= pm860x_irq_disable,
4502afa62eaSHaojian Zhuang };
4515c42e8c4SHaojian Zhuang 
452a16122bcSHaojian Zhuang static int __devinit device_gpadc_init(struct pm860x_chip *chip,
453a16122bcSHaojian Zhuang 				       struct pm860x_platform_data *pdata)
454a16122bcSHaojian Zhuang {
455a16122bcSHaojian Zhuang 	struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \
456a16122bcSHaojian Zhuang 				: chip->companion;
457eb6e8ddfSDan Carpenter 	int data;
458eb6e8ddfSDan Carpenter 	int ret;
459a16122bcSHaojian Zhuang 
460a16122bcSHaojian Zhuang 	/* initialize GPADC without activating it */
461a16122bcSHaojian Zhuang 
462eb6e8ddfSDan Carpenter 	if (!pdata || !pdata->touch)
463eb6e8ddfSDan Carpenter 		return -EINVAL;
464eb6e8ddfSDan Carpenter 
465a16122bcSHaojian Zhuang 	/* set GPADC MISC1 register */
466a16122bcSHaojian Zhuang 	data = 0;
467eb6e8ddfSDan Carpenter 	data |= (pdata->touch->gpadc_prebias << 1) & PM8607_GPADC_PREBIAS_MASK;
468eb6e8ddfSDan Carpenter 	data |= (pdata->touch->slot_cycle << 3) & PM8607_GPADC_SLOT_CYCLE_MASK;
469eb6e8ddfSDan Carpenter 	data |= (pdata->touch->off_scale << 5) & PM8607_GPADC_OFF_SCALE_MASK;
470eb6e8ddfSDan Carpenter 	data |= (pdata->touch->sw_cal << 7) & PM8607_GPADC_SW_CAL_MASK;
471a16122bcSHaojian Zhuang 	if (data) {
472a16122bcSHaojian Zhuang 		ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data);
473a16122bcSHaojian Zhuang 		if (ret < 0)
474a16122bcSHaojian Zhuang 			goto out;
475a16122bcSHaojian Zhuang 	}
476a16122bcSHaojian Zhuang 	/* set tsi prebias time */
477a16122bcSHaojian Zhuang 	if (pdata->touch->tsi_prebias) {
478a16122bcSHaojian Zhuang 		data = pdata->touch->tsi_prebias;
479a16122bcSHaojian Zhuang 		ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data);
480a16122bcSHaojian Zhuang 		if (ret < 0)
481a16122bcSHaojian Zhuang 			goto out;
482a16122bcSHaojian Zhuang 	}
483a16122bcSHaojian Zhuang 	/* set prebias & prechg time of pen detect */
484a16122bcSHaojian Zhuang 	data = 0;
485a16122bcSHaojian Zhuang 	data |= pdata->touch->pen_prebias & PM8607_PD_PREBIAS_MASK;
486eb6e8ddfSDan Carpenter 	data |= (pdata->touch->pen_prechg << 5) & PM8607_PD_PRECHG_MASK;
487a16122bcSHaojian Zhuang 	if (data) {
488a16122bcSHaojian Zhuang 		ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data);
489a16122bcSHaojian Zhuang 		if (ret < 0)
490a16122bcSHaojian Zhuang 			goto out;
491a16122bcSHaojian Zhuang 	}
492a16122bcSHaojian Zhuang 
493a16122bcSHaojian Zhuang 	ret = pm860x_set_bits(i2c, PM8607_GPADC_MISC1,
494a16122bcSHaojian Zhuang 			      PM8607_GPADC_EN, PM8607_GPADC_EN);
495a16122bcSHaojian Zhuang out:
496a16122bcSHaojian Zhuang 	return ret;
497a16122bcSHaojian Zhuang }
498a16122bcSHaojian Zhuang 
4995c42e8c4SHaojian Zhuang static int __devinit device_irq_init(struct pm860x_chip *chip,
5005c42e8c4SHaojian Zhuang 				     struct pm860x_platform_data *pdata)
5015c42e8c4SHaojian Zhuang {
5025c42e8c4SHaojian Zhuang 	struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \
5035c42e8c4SHaojian Zhuang 				: chip->companion;
5045c42e8c4SHaojian Zhuang 	unsigned char status_buf[INT_STATUS_NUM];
5052afa62eaSHaojian Zhuang 	unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
5062afa62eaSHaojian Zhuang 	int i, data, mask, ret = -EINVAL;
5072afa62eaSHaojian Zhuang 	int __irq;
5085c42e8c4SHaojian Zhuang 
5092afa62eaSHaojian Zhuang 	if (!pdata || !pdata->irq_base) {
5102afa62eaSHaojian Zhuang 		dev_warn(chip->dev, "No interrupt support on IRQ base\n");
5112afa62eaSHaojian Zhuang 		return -EINVAL;
5122afa62eaSHaojian Zhuang 	}
5135c42e8c4SHaojian Zhuang 
5145c42e8c4SHaojian Zhuang 	mask = PM8607_B0_MISC1_INV_INT | PM8607_B0_MISC1_INT_CLEAR
5155c42e8c4SHaojian Zhuang 		| PM8607_B0_MISC1_INT_MASK;
5165c42e8c4SHaojian Zhuang 	data = 0;
5175c42e8c4SHaojian Zhuang 	chip->irq_mode = 0;
5185c42e8c4SHaojian Zhuang 	if (pdata && pdata->irq_mode) {
5195c42e8c4SHaojian Zhuang 		/*
5205c42e8c4SHaojian Zhuang 		 * irq_mode defines the way of clearing interrupt. If it's 1,
5215c42e8c4SHaojian Zhuang 		 * clear IRQ by write. Otherwise, clear it by read.
5225c42e8c4SHaojian Zhuang 		 * This control bit is valid from 88PM8607 B0 steping.
5235c42e8c4SHaojian Zhuang 		 */
5245c42e8c4SHaojian Zhuang 		data |= PM8607_B0_MISC1_INT_CLEAR;
5255c42e8c4SHaojian Zhuang 		chip->irq_mode = 1;
5265c42e8c4SHaojian Zhuang 	}
5275c42e8c4SHaojian Zhuang 	ret = pm860x_set_bits(i2c, PM8607_B0_MISC1, mask, data);
5285c42e8c4SHaojian Zhuang 	if (ret < 0)
5295c42e8c4SHaojian Zhuang 		goto out;
5305c42e8c4SHaojian Zhuang 
5315c42e8c4SHaojian Zhuang 	/* mask all IRQs */
5325c42e8c4SHaojian Zhuang 	memset(status_buf, 0, INT_STATUS_NUM);
5335c42e8c4SHaojian Zhuang 	ret = pm860x_bulk_write(i2c, PM8607_INT_MASK_1,
5345c42e8c4SHaojian Zhuang 				INT_STATUS_NUM, status_buf);
5355c42e8c4SHaojian Zhuang 	if (ret < 0)
5365c42e8c4SHaojian Zhuang 		goto out;
5375c42e8c4SHaojian Zhuang 
5385c42e8c4SHaojian Zhuang 	if (chip->irq_mode) {
5395c42e8c4SHaojian Zhuang 		/* clear interrupt status by write */
5405c42e8c4SHaojian Zhuang 		memset(status_buf, 0xFF, INT_STATUS_NUM);
5415c42e8c4SHaojian Zhuang 		ret = pm860x_bulk_write(i2c, PM8607_INT_STATUS1,
5425c42e8c4SHaojian Zhuang 					INT_STATUS_NUM, status_buf);
5435c42e8c4SHaojian Zhuang 	} else {
5445c42e8c4SHaojian Zhuang 		/* clear interrupt status by read */
5455c42e8c4SHaojian Zhuang 		ret = pm860x_bulk_read(i2c, PM8607_INT_STATUS1,
5465c42e8c4SHaojian Zhuang 					INT_STATUS_NUM, status_buf);
5475c42e8c4SHaojian Zhuang 	}
5485c42e8c4SHaojian Zhuang 	if (ret < 0)
5495c42e8c4SHaojian Zhuang 		goto out;
5505c42e8c4SHaojian Zhuang 
5512afa62eaSHaojian Zhuang 	mutex_init(&chip->irq_lock);
5522afa62eaSHaojian Zhuang 	chip->irq_base = pdata->irq_base;
5532afa62eaSHaojian Zhuang 	chip->core_irq = i2c->irq;
5542afa62eaSHaojian Zhuang 	if (!chip->core_irq)
5555c42e8c4SHaojian Zhuang 		goto out;
5562afa62eaSHaojian Zhuang 
5572afa62eaSHaojian Zhuang 	/* register IRQ by genirq */
5582afa62eaSHaojian Zhuang 	for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) {
5592afa62eaSHaojian Zhuang 		__irq = i + chip->irq_base;
560d5bb1221SThomas Gleixner 		irq_set_chip_data(__irq, chip);
561d5bb1221SThomas Gleixner 		irq_set_chip_and_handler(__irq, &pm860x_irq_chip,
5622afa62eaSHaojian Zhuang 					 handle_edge_irq);
563d5bb1221SThomas Gleixner 		irq_set_nested_thread(__irq, 1);
5642afa62eaSHaojian Zhuang #ifdef CONFIG_ARM
5652afa62eaSHaojian Zhuang 		set_irq_flags(__irq, IRQF_VALID);
5662afa62eaSHaojian Zhuang #else
567d5bb1221SThomas Gleixner 		irq_set_noprobe(__irq);
5682afa62eaSHaojian Zhuang #endif
5695c42e8c4SHaojian Zhuang 	}
5702afa62eaSHaojian Zhuang 
5712afa62eaSHaojian Zhuang 	ret = request_threaded_irq(chip->core_irq, NULL, pm860x_irq, flags,
5722afa62eaSHaojian Zhuang 				   "88pm860x", chip);
5732afa62eaSHaojian Zhuang 	if (ret) {
5742afa62eaSHaojian Zhuang 		dev_err(chip->dev, "Failed to request IRQ: %d\n", ret);
5752afa62eaSHaojian Zhuang 		chip->core_irq = 0;
5762afa62eaSHaojian Zhuang 	}
5772afa62eaSHaojian Zhuang 
5785c42e8c4SHaojian Zhuang 	return 0;
5795c42e8c4SHaojian Zhuang out:
5802afa62eaSHaojian Zhuang 	chip->core_irq = 0;
5815c42e8c4SHaojian Zhuang 	return ret;
5825c42e8c4SHaojian Zhuang }
5835c42e8c4SHaojian Zhuang 
584872c1b14SHenrik Kretzschmar static void device_irq_exit(struct pm860x_chip *chip)
5855c42e8c4SHaojian Zhuang {
5862afa62eaSHaojian Zhuang 	if (chip->core_irq)
5872afa62eaSHaojian Zhuang 		free_irq(chip->core_irq, chip);
5885c42e8c4SHaojian Zhuang }
5895c42e8c4SHaojian Zhuang 
59023de435aSJett.Zhou int pm8606_osc_enable(struct pm860x_chip *chip, unsigned short client)
59123de435aSJett.Zhou {
59223de435aSJett.Zhou 	int ret = -EIO;
59323de435aSJett.Zhou 	struct i2c_client *i2c = (chip->id == CHIP_PM8606) ?
59423de435aSJett.Zhou 		chip->client : chip->companion;
59523de435aSJett.Zhou 
59623de435aSJett.Zhou 	dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client);
59723de435aSJett.Zhou 	dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n",
59823de435aSJett.Zhou 			__func__, chip->osc_vote,
59923de435aSJett.Zhou 			chip->osc_status);
60023de435aSJett.Zhou 
60123de435aSJett.Zhou 	mutex_lock(&chip->osc_lock);
60223de435aSJett.Zhou 	/* Update voting status */
60323de435aSJett.Zhou 	chip->osc_vote |= client;
60423de435aSJett.Zhou 	/* If reference group is off - turn on*/
60523de435aSJett.Zhou 	if (chip->osc_status != PM8606_REF_GP_OSC_ON) {
60623de435aSJett.Zhou 		chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN;
60723de435aSJett.Zhou 		/* Enable Reference group Vsys */
60823de435aSJett.Zhou 		if (pm860x_set_bits(i2c, PM8606_VSYS,
60923de435aSJett.Zhou 				PM8606_VSYS_EN, PM8606_VSYS_EN))
61023de435aSJett.Zhou 			goto out;
61123de435aSJett.Zhou 
61223de435aSJett.Zhou 		/*Enable Internal Oscillator */
61323de435aSJett.Zhou 		if (pm860x_set_bits(i2c, PM8606_MISC,
61423de435aSJett.Zhou 				PM8606_MISC_OSC_EN, PM8606_MISC_OSC_EN))
61523de435aSJett.Zhou 			goto out;
61623de435aSJett.Zhou 		/* Update status (only if writes succeed) */
61723de435aSJett.Zhou 		chip->osc_status = PM8606_REF_GP_OSC_ON;
61823de435aSJett.Zhou 	}
61923de435aSJett.Zhou 	mutex_unlock(&chip->osc_lock);
62023de435aSJett.Zhou 
62123de435aSJett.Zhou 	dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n",
62223de435aSJett.Zhou 			__func__, chip->osc_vote,
62323de435aSJett.Zhou 			chip->osc_status, ret);
62423de435aSJett.Zhou 	return 0;
62523de435aSJett.Zhou out:
62623de435aSJett.Zhou 	mutex_unlock(&chip->osc_lock);
62723de435aSJett.Zhou 	return ret;
62823de435aSJett.Zhou }
6292f5f89beSSamuel Ortiz EXPORT_SYMBOL(pm8606_osc_enable);
63023de435aSJett.Zhou 
63123de435aSJett.Zhou int pm8606_osc_disable(struct pm860x_chip *chip, unsigned short client)
63223de435aSJett.Zhou {
63323de435aSJett.Zhou 	int ret = -EIO;
63423de435aSJett.Zhou 	struct i2c_client *i2c = (chip->id == CHIP_PM8606) ?
63523de435aSJett.Zhou 		chip->client : chip->companion;
63623de435aSJett.Zhou 
63723de435aSJett.Zhou 	dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client);
63823de435aSJett.Zhou 	dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n",
63923de435aSJett.Zhou 			__func__, chip->osc_vote,
64023de435aSJett.Zhou 			chip->osc_status);
64123de435aSJett.Zhou 
64223de435aSJett.Zhou 	mutex_lock(&chip->osc_lock);
64323de435aSJett.Zhou 	/*Update voting status */
64423de435aSJett.Zhou 	chip->osc_vote &= ~(client);
64523de435aSJett.Zhou 	/* If reference group is off and this is the last client to release
64623de435aSJett.Zhou 	 * - turn off */
64723de435aSJett.Zhou 	if ((chip->osc_status != PM8606_REF_GP_OSC_OFF) &&
64823de435aSJett.Zhou 			(chip->osc_vote == REF_GP_NO_CLIENTS)) {
64923de435aSJett.Zhou 		chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN;
65023de435aSJett.Zhou 		/* Disable Reference group Vsys */
65123de435aSJett.Zhou 		if (pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0))
65223de435aSJett.Zhou 			goto out;
65323de435aSJett.Zhou 		/* Disable Internal Oscillator */
65423de435aSJett.Zhou 		if (pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0))
65523de435aSJett.Zhou 			goto out;
65623de435aSJett.Zhou 		chip->osc_status = PM8606_REF_GP_OSC_OFF;
65723de435aSJett.Zhou 	}
65823de435aSJett.Zhou 	mutex_unlock(&chip->osc_lock);
65923de435aSJett.Zhou 
66023de435aSJett.Zhou 	dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n",
66123de435aSJett.Zhou 			__func__, chip->osc_vote,
66223de435aSJett.Zhou 			chip->osc_status, ret);
66323de435aSJett.Zhou 	return 0;
66423de435aSJett.Zhou out:
66523de435aSJett.Zhou 	mutex_unlock(&chip->osc_lock);
66623de435aSJett.Zhou 	return ret;
66723de435aSJett.Zhou }
6682f5f89beSSamuel Ortiz EXPORT_SYMBOL(pm8606_osc_disable);
66923de435aSJett.Zhou 
67023de435aSJett.Zhou static void __devinit device_osc_init(struct i2c_client *i2c)
67123de435aSJett.Zhou {
67223de435aSJett.Zhou 	struct pm860x_chip *chip = i2c_get_clientdata(i2c);
67323de435aSJett.Zhou 
67423de435aSJett.Zhou 	mutex_init(&chip->osc_lock);
67523de435aSJett.Zhou 	/* init portofino reference group voting and status */
67623de435aSJett.Zhou 	/* Disable Reference group Vsys */
67723de435aSJett.Zhou 	pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0);
67823de435aSJett.Zhou 	/* Disable Internal Oscillator */
67923de435aSJett.Zhou 	pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0);
68023de435aSJett.Zhou 
68123de435aSJett.Zhou 	chip->osc_vote = REF_GP_NO_CLIENTS;
68223de435aSJett.Zhou 	chip->osc_status = PM8606_REF_GP_OSC_OFF;
68323de435aSJett.Zhou }
68423de435aSJett.Zhou 
685adb70483SHaojian Zhuang static void __devinit device_bk_init(struct pm860x_chip *chip,
686adb70483SHaojian Zhuang 				     struct pm860x_platform_data *pdata)
687adb70483SHaojian Zhuang {
688a6ccdcd9SHaojian Zhuang 	int ret, i;
689adb70483SHaojian Zhuang 
690a6ccdcd9SHaojian Zhuang 	if (pdata && pdata->backlight) {
691adb70483SHaojian Zhuang 		if (pdata->num_backlights > ARRAY_SIZE(bk_devs))
692adb70483SHaojian Zhuang 			pdata->num_backlights = ARRAY_SIZE(bk_devs);
693adb70483SHaojian Zhuang 		for (i = 0; i < pdata->num_backlights; i++) {
694f5fb758dSHaojian Zhuang 			bk_devs[i].platform_data = &pdata->backlight[i];
695a6ccdcd9SHaojian Zhuang 			bk_devs[i].pdata_size =
696a6ccdcd9SHaojian Zhuang 				sizeof(struct pm860x_backlight_pdata);
697adb70483SHaojian Zhuang 		}
698adb70483SHaojian Zhuang 	}
699a6ccdcd9SHaojian Zhuang 	ret = mfd_add_devices(chip->dev, 0, bk_devs,
700a6ccdcd9SHaojian Zhuang 			      ARRAY_SIZE(bk_devs), NULL, 0);
701a6ccdcd9SHaojian Zhuang 	if (ret < 0)
702a6ccdcd9SHaojian Zhuang 		dev_err(chip->dev, "Failed to add backlight subdev\n");
703adb70483SHaojian Zhuang }
704adb70483SHaojian Zhuang 
7053154c344SHaojian Zhuang static void __devinit device_led_init(struct pm860x_chip *chip,
70653dbab7aSHaojian Zhuang 				      struct pm860x_platform_data *pdata)
70753dbab7aSHaojian Zhuang {
708894fc8f2SHaojian Zhuang 	int ret, i;
709a16122bcSHaojian Zhuang 
710894fc8f2SHaojian Zhuang 	if (pdata && pdata->led) {
7113154c344SHaojian Zhuang 		if (pdata->num_leds > ARRAY_SIZE(led_devs))
7123154c344SHaojian Zhuang 			pdata->num_leds = ARRAY_SIZE(led_devs);
7133154c344SHaojian Zhuang 		for (i = 0; i < pdata->num_leds; i++) {
714f5fb758dSHaojian Zhuang 			led_devs[i].platform_data = &pdata->led[i];
715894fc8f2SHaojian Zhuang 			led_devs[i].pdata_size =
716894fc8f2SHaojian Zhuang 				sizeof(struct pm860x_led_pdata);
717894fc8f2SHaojian Zhuang 		}
718894fc8f2SHaojian Zhuang 	}
719894fc8f2SHaojian Zhuang 	ret = mfd_add_devices(chip->dev, 0, led_devs,
720894fc8f2SHaojian Zhuang 			      ARRAY_SIZE(led_devs), NULL, 0);
7213154c344SHaojian Zhuang 	if (ret < 0) {
722894fc8f2SHaojian Zhuang 		dev_err(chip->dev, "Failed to add led subdev\n");
7233154c344SHaojian Zhuang 		return;
7243154c344SHaojian Zhuang 	}
7253154c344SHaojian Zhuang }
72653dbab7aSHaojian Zhuang 
72722aad001SHaojian Zhuang static void __devinit device_regulator_init(struct pm860x_chip *chip,
72822aad001SHaojian Zhuang 					    struct pm860x_platform_data *pdata)
72922aad001SHaojian Zhuang {
73022aad001SHaojian Zhuang 	struct regulator_init_data *initdata;
73122aad001SHaojian Zhuang 	int ret;
732586e1a17SHaojian Zhuang 	int i, seq;
73322aad001SHaojian Zhuang 
73422aad001SHaojian Zhuang 	if ((pdata == NULL) || (pdata->regulator == NULL))
73522aad001SHaojian Zhuang 		return;
73622aad001SHaojian Zhuang 
73722aad001SHaojian Zhuang 	if (pdata->num_regulators > ARRAY_SIZE(regulator_devs))
73822aad001SHaojian Zhuang 		pdata->num_regulators = ARRAY_SIZE(regulator_devs);
73922aad001SHaojian Zhuang 
740586e1a17SHaojian Zhuang 	for (i = 0, seq = -1; i < pdata->num_regulators; i++) {
74122aad001SHaojian Zhuang 		initdata = &pdata->regulator[i];
742586e1a17SHaojian Zhuang 		seq = *(unsigned int *)initdata->driver_data;
743586e1a17SHaojian Zhuang 		if ((seq < 0) || (seq > PM8607_ID_RG_MAX)) {
744586e1a17SHaojian Zhuang 			dev_err(chip->dev, "Wrong ID(%d) on regulator(%s)\n",
745586e1a17SHaojian Zhuang 				seq, initdata->constraints.name);
74622aad001SHaojian Zhuang 			goto out;
74722aad001SHaojian Zhuang 		}
748f5fb758dSHaojian Zhuang 		regulator_devs[i].platform_data = &pdata->regulator[i];
749f5fb758dSHaojian Zhuang 		regulator_devs[i].pdata_size = sizeof(struct regulator_init_data);
75022aad001SHaojian Zhuang 		regulator_devs[i].num_resources = 1;
751586e1a17SHaojian Zhuang 		regulator_devs[i].resources = &regulator_resources[seq];
75222aad001SHaojian Zhuang 
75322aad001SHaojian Zhuang 		ret = mfd_add_devices(chip->dev, 0, &regulator_devs[i], 1,
754586e1a17SHaojian Zhuang 				      &regulator_resources[seq], 0);
75522aad001SHaojian Zhuang 		if (ret < 0) {
75622aad001SHaojian Zhuang 			dev_err(chip->dev, "Failed to add regulator subdev\n");
75722aad001SHaojian Zhuang 			goto out;
75822aad001SHaojian Zhuang 		}
75922aad001SHaojian Zhuang 	}
76022aad001SHaojian Zhuang out:
76122aad001SHaojian Zhuang 	return;
76222aad001SHaojian Zhuang }
76322aad001SHaojian Zhuang 
764008b3040SHaojian Zhuang static void __devinit device_rtc_init(struct pm860x_chip *chip,
765008b3040SHaojian Zhuang 				      struct pm860x_platform_data *pdata)
766008b3040SHaojian Zhuang {
767008b3040SHaojian Zhuang 	int ret;
768008b3040SHaojian Zhuang 
769008b3040SHaojian Zhuang 	if ((pdata == NULL))
770008b3040SHaojian Zhuang 		return;
771008b3040SHaojian Zhuang 
772008b3040SHaojian Zhuang 	rtc_devs[0].platform_data = pdata->rtc;
773008b3040SHaojian Zhuang 	rtc_devs[0].pdata_size = sizeof(struct pm860x_rtc_pdata);
774008b3040SHaojian Zhuang 	rtc_devs[0].num_resources = ARRAY_SIZE(rtc_resources);
775008b3040SHaojian Zhuang 	rtc_devs[0].resources = &rtc_resources[0];
776008b3040SHaojian Zhuang 	ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
777008b3040SHaojian Zhuang 			      ARRAY_SIZE(rtc_devs), &rtc_resources[0],
778008b3040SHaojian Zhuang 			      chip->irq_base);
779008b3040SHaojian Zhuang 	if (ret < 0)
780008b3040SHaojian Zhuang 		dev_err(chip->dev, "Failed to add rtc subdev\n");
781008b3040SHaojian Zhuang }
782008b3040SHaojian Zhuang 
783c9f560b3SHaojian Zhuang static void __devinit device_touch_init(struct pm860x_chip *chip,
784c9f560b3SHaojian Zhuang 					struct pm860x_platform_data *pdata)
785c9f560b3SHaojian Zhuang {
786c9f560b3SHaojian Zhuang 	int ret;
787c9f560b3SHaojian Zhuang 
788f5fb758dSHaojian Zhuang 	if (pdata == NULL)
789c9f560b3SHaojian Zhuang 		return;
790c9f560b3SHaojian Zhuang 
791f5fb758dSHaojian Zhuang 	touch_devs[0].platform_data = pdata->touch;
792f5fb758dSHaojian Zhuang 	touch_devs[0].pdata_size = sizeof(struct pm860x_touch_pdata);
793c9f560b3SHaojian Zhuang 	touch_devs[0].num_resources = ARRAY_SIZE(touch_resources);
794c9f560b3SHaojian Zhuang 	touch_devs[0].resources = &touch_resources[0];
795c9f560b3SHaojian Zhuang 	ret = mfd_add_devices(chip->dev, 0, &touch_devs[0],
796c9f560b3SHaojian Zhuang 			      ARRAY_SIZE(touch_devs), &touch_resources[0],
797c9f560b3SHaojian Zhuang 			      chip->irq_base);
798c9f560b3SHaojian Zhuang 	if (ret < 0)
799c9f560b3SHaojian Zhuang 		dev_err(chip->dev, "Failed to add touch subdev\n");
800c9f560b3SHaojian Zhuang }
801c9f560b3SHaojian Zhuang 
802c9f560b3SHaojian Zhuang static void __devinit device_power_init(struct pm860x_chip *chip,
803c9f560b3SHaojian Zhuang 					struct pm860x_platform_data *pdata)
804c9f560b3SHaojian Zhuang {
805c9f560b3SHaojian Zhuang 	int ret;
806c9f560b3SHaojian Zhuang 
807f5fb758dSHaojian Zhuang 	if (pdata == NULL)
808c9f560b3SHaojian Zhuang 		return;
809c9f560b3SHaojian Zhuang 
810f5fb758dSHaojian Zhuang 	power_devs[0].platform_data = pdata->power;
811f5fb758dSHaojian Zhuang 	power_devs[0].pdata_size = sizeof(struct pm860x_power_pdata);
812c9f560b3SHaojian Zhuang 	power_devs[0].num_resources = ARRAY_SIZE(battery_resources);
813c9f560b3SHaojian Zhuang 	power_devs[0].resources = &battery_resources[0],
814c9f560b3SHaojian Zhuang 	ret = mfd_add_devices(chip->dev, 0, &power_devs[0], 1,
815c9f560b3SHaojian Zhuang 			      &battery_resources[0], chip->irq_base);
816c9f560b3SHaojian Zhuang 	if (ret < 0)
817c9f560b3SHaojian Zhuang 		dev_err(chip->dev, "Failed to add battery subdev\n");
818c9f560b3SHaojian Zhuang 
819f5fb758dSHaojian Zhuang 	power_devs[1].platform_data = pdata->power;
820f5fb758dSHaojian Zhuang 	power_devs[1].pdata_size = sizeof(struct pm860x_power_pdata);
821c9f560b3SHaojian Zhuang 	power_devs[1].num_resources = ARRAY_SIZE(charger_resources);
822c9f560b3SHaojian Zhuang 	power_devs[1].resources = &charger_resources[0],
823c9f560b3SHaojian Zhuang 	ret = mfd_add_devices(chip->dev, 0, &power_devs[1], 1,
824c9f560b3SHaojian Zhuang 			      &charger_resources[0], chip->irq_base);
825c9f560b3SHaojian Zhuang 	if (ret < 0)
826c9f560b3SHaojian Zhuang 		dev_err(chip->dev, "Failed to add charger subdev\n");
8272573f6d3SJett.Zhou 
8282573f6d3SJett.Zhou 	power_devs[2].platform_data = &preg_init_data;
8292573f6d3SJett.Zhou 	power_devs[2].pdata_size = sizeof(struct regulator_init_data);
8302573f6d3SJett.Zhou 	power_devs[2].num_resources = ARRAY_SIZE(preg_resources);
8312573f6d3SJett.Zhou 	power_devs[2].resources = &preg_resources[0],
8322573f6d3SJett.Zhou 	ret = mfd_add_devices(chip->dev, 0, &power_devs[2], 1,
8332573f6d3SJett.Zhou 			      &preg_resources[0], chip->irq_base);
8342573f6d3SJett.Zhou 	if (ret < 0)
8352573f6d3SJett.Zhou 		dev_err(chip->dev, "Failed to add preg subdev\n");
836c9f560b3SHaojian Zhuang }
837c9f560b3SHaojian Zhuang 
838c9f560b3SHaojian Zhuang static void __devinit device_onkey_init(struct pm860x_chip *chip,
839c9f560b3SHaojian Zhuang 					struct pm860x_platform_data *pdata)
840c9f560b3SHaojian Zhuang {
841c9f560b3SHaojian Zhuang 	int ret;
842c9f560b3SHaojian Zhuang 
843c9f560b3SHaojian Zhuang 	onkey_devs[0].num_resources = ARRAY_SIZE(onkey_resources);
844c9f560b3SHaojian Zhuang 	onkey_devs[0].resources = &onkey_resources[0],
845c9f560b3SHaojian Zhuang 	ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0],
846c9f560b3SHaojian Zhuang 			      ARRAY_SIZE(onkey_devs), &onkey_resources[0],
847c9f560b3SHaojian Zhuang 			      chip->irq_base);
848c9f560b3SHaojian Zhuang 	if (ret < 0)
849c9f560b3SHaojian Zhuang 		dev_err(chip->dev, "Failed to add onkey subdev\n");
850c9f560b3SHaojian Zhuang }
851c9f560b3SHaojian Zhuang 
852c9f560b3SHaojian Zhuang static void __devinit device_codec_init(struct pm860x_chip *chip,
853c9f560b3SHaojian Zhuang 					struct pm860x_platform_data *pdata)
854c9f560b3SHaojian Zhuang {
855c9f560b3SHaojian Zhuang 	int ret;
856c9f560b3SHaojian Zhuang 
857c9f560b3SHaojian Zhuang 	codec_devs[0].num_resources = ARRAY_SIZE(codec_resources);
858c9f560b3SHaojian Zhuang 	codec_devs[0].resources = &codec_resources[0],
859c9f560b3SHaojian Zhuang 	ret = mfd_add_devices(chip->dev, 0, &codec_devs[0],
860c9f560b3SHaojian Zhuang 			      ARRAY_SIZE(codec_devs), &codec_resources[0], 0);
861c9f560b3SHaojian Zhuang 	if (ret < 0)
862c9f560b3SHaojian Zhuang 		dev_err(chip->dev, "Failed to add codec subdev\n");
863c9f560b3SHaojian Zhuang }
864c9f560b3SHaojian Zhuang 
8655c42e8c4SHaojian Zhuang static void __devinit device_8607_init(struct pm860x_chip *chip,
8665c42e8c4SHaojian Zhuang 				       struct i2c_client *i2c,
86753dbab7aSHaojian Zhuang 				       struct pm860x_platform_data *pdata)
868bbd51b1fSHaojian Zhuang {
869a16122bcSHaojian Zhuang 	int data, ret;
870bbd51b1fSHaojian Zhuang 
87153dbab7aSHaojian Zhuang 	ret = pm860x_reg_read(i2c, PM8607_CHIP_ID);
872bbd51b1fSHaojian Zhuang 	if (ret < 0) {
873bbd51b1fSHaojian Zhuang 		dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
874bbd51b1fSHaojian Zhuang 		goto out;
875bbd51b1fSHaojian Zhuang 	}
87638b34052SHaojian Zhuang 	switch (ret & PM8607_VERSION_MASK) {
87738b34052SHaojian Zhuang 	case 0x40:
87838b34052SHaojian Zhuang 	case 0x50:
879bbd51b1fSHaojian Zhuang 		dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected\n",
880bbd51b1fSHaojian Zhuang 			 ret);
88138b34052SHaojian Zhuang 		break;
88238b34052SHaojian Zhuang 	default:
883bbd51b1fSHaojian Zhuang 		dev_err(chip->dev, "Failed to detect Marvell 88PM8607. "
884bbd51b1fSHaojian Zhuang 			"Chip ID: %02x\n", ret);
885bbd51b1fSHaojian Zhuang 		goto out;
886bbd51b1fSHaojian Zhuang 	}
887bbd51b1fSHaojian Zhuang 
88853dbab7aSHaojian Zhuang 	ret = pm860x_reg_read(i2c, PM8607_BUCK3);
889bbd51b1fSHaojian Zhuang 	if (ret < 0) {
890bbd51b1fSHaojian Zhuang 		dev_err(chip->dev, "Failed to read BUCK3 register: %d\n", ret);
891bbd51b1fSHaojian Zhuang 		goto out;
892bbd51b1fSHaojian Zhuang 	}
893bbd51b1fSHaojian Zhuang 	if (ret & PM8607_BUCK3_DOUBLE)
894bbd51b1fSHaojian Zhuang 		chip->buck3_double = 1;
895bbd51b1fSHaojian Zhuang 
8965c42e8c4SHaojian Zhuang 	ret = pm860x_reg_read(i2c, PM8607_B0_MISC1);
897bbd51b1fSHaojian Zhuang 	if (ret < 0) {
898bbd51b1fSHaojian Zhuang 		dev_err(chip->dev, "Failed to read MISC1 register: %d\n", ret);
899bbd51b1fSHaojian Zhuang 		goto out;
900bbd51b1fSHaojian Zhuang 	}
901bbd51b1fSHaojian Zhuang 
9025c42e8c4SHaojian Zhuang 	if (pdata && (pdata->i2c_port == PI2C_PORT))
9035c42e8c4SHaojian Zhuang 		data = PM8607_B0_MISC1_PI2C;
9045c42e8c4SHaojian Zhuang 	else
9055c42e8c4SHaojian Zhuang 		data = 0;
9065c42e8c4SHaojian Zhuang 	ret = pm860x_set_bits(i2c, PM8607_B0_MISC1, PM8607_B0_MISC1_PI2C, data);
9075c42e8c4SHaojian Zhuang 	if (ret < 0) {
9085c42e8c4SHaojian Zhuang 		dev_err(chip->dev, "Failed to access MISC1:%d\n", ret);
9095c42e8c4SHaojian Zhuang 		goto out;
9105c42e8c4SHaojian Zhuang 	}
9115c42e8c4SHaojian Zhuang 
912a16122bcSHaojian Zhuang 	ret = device_gpadc_init(chip, pdata);
913a16122bcSHaojian Zhuang 	if (ret < 0)
914a16122bcSHaojian Zhuang 		goto out;
915a16122bcSHaojian Zhuang 
9165c42e8c4SHaojian Zhuang 	ret = device_irq_init(chip, pdata);
9175c42e8c4SHaojian Zhuang 	if (ret < 0)
9185c42e8c4SHaojian Zhuang 		goto out;
9195c42e8c4SHaojian Zhuang 
920cea438ddSHaojian Zhuang 	device_regulator_init(chip, pdata);
921cea438ddSHaojian Zhuang 	device_rtc_init(chip, pdata);
922cea438ddSHaojian Zhuang 	device_onkey_init(chip, pdata);
923cea438ddSHaojian Zhuang 	device_touch_init(chip, pdata);
924cea438ddSHaojian Zhuang 	device_power_init(chip, pdata);
925cea438ddSHaojian Zhuang 	device_codec_init(chip, pdata);
926bbd51b1fSHaojian Zhuang out:
92753dbab7aSHaojian Zhuang 	return;
928bbd51b1fSHaojian Zhuang }
929bbd51b1fSHaojian Zhuang 
93078258064SJett.Zhou static void __devinit device_8606_init(struct pm860x_chip *chip,
93178258064SJett.Zhou 				       struct i2c_client *i2c,
93278258064SJett.Zhou 				       struct pm860x_platform_data *pdata)
93378258064SJett.Zhou {
93478258064SJett.Zhou 	device_osc_init(i2c);
93578258064SJett.Zhou 	device_bk_init(chip, pdata);
93678258064SJett.Zhou 	device_led_init(chip, pdata);
93778258064SJett.Zhou }
93878258064SJett.Zhou 
939872c1b14SHenrik Kretzschmar int __devinit pm860x_device_init(struct pm860x_chip *chip,
94053dbab7aSHaojian Zhuang 		       struct pm860x_platform_data *pdata)
94153dbab7aSHaojian Zhuang {
9422afa62eaSHaojian Zhuang 	chip->core_irq = 0;
9435c42e8c4SHaojian Zhuang 
94453dbab7aSHaojian Zhuang 	switch (chip->id) {
94553dbab7aSHaojian Zhuang 	case CHIP_PM8606:
94678258064SJett.Zhou 		device_8606_init(chip, chip->client, pdata);
94753dbab7aSHaojian Zhuang 		break;
94853dbab7aSHaojian Zhuang 	case CHIP_PM8607:
94953dbab7aSHaojian Zhuang 		device_8607_init(chip, chip->client, pdata);
95053dbab7aSHaojian Zhuang 		break;
95153dbab7aSHaojian Zhuang 	}
95253dbab7aSHaojian Zhuang 
95353dbab7aSHaojian Zhuang 	if (chip->companion) {
95453dbab7aSHaojian Zhuang 		switch (chip->id) {
95553dbab7aSHaojian Zhuang 		case CHIP_PM8607:
95678258064SJett.Zhou 			device_8606_init(chip, chip->companion, pdata);
95753dbab7aSHaojian Zhuang 			break;
95853dbab7aSHaojian Zhuang 		case CHIP_PM8606:
95953dbab7aSHaojian Zhuang 			device_8607_init(chip, chip->companion, pdata);
96053dbab7aSHaojian Zhuang 			break;
96153dbab7aSHaojian Zhuang 		}
96253dbab7aSHaojian Zhuang 	}
9635c42e8c4SHaojian Zhuang 
96453dbab7aSHaojian Zhuang 	return 0;
96553dbab7aSHaojian Zhuang }
96653dbab7aSHaojian Zhuang 
967872c1b14SHenrik Kretzschmar void __devexit pm860x_device_exit(struct pm860x_chip *chip)
968bbd51b1fSHaojian Zhuang {
9695c42e8c4SHaojian Zhuang 	device_irq_exit(chip);
970bbd51b1fSHaojian Zhuang 	mfd_remove_devices(chip->dev);
971bbd51b1fSHaojian Zhuang }
972bbd51b1fSHaojian Zhuang 
97353dbab7aSHaojian Zhuang MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM860x");
974bbd51b1fSHaojian Zhuang MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
975bbd51b1fSHaojian Zhuang MODULE_LICENSE("GPL");
976