Blame view

drivers/mfd/88pm860x-core.c 21.7 KB
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
1
2
3
4
5
6
7
8
9
10
11
12
13
  /*
   * Base driver for Marvell 88PM8607
   *
   * Copyright (C) 2009 Marvell International Ltd.
   * 	Haojian Zhuang <haojian.zhuang@marvell.com>
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   */
  
  #include <linux/kernel.h>
  #include <linux/module.h>
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
14
  #include <linux/i2c.h>
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
15
  #include <linux/irq.h>
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
16
17
18
  #include <linux/interrupt.h>
  #include <linux/platform_device.h>
  #include <linux/mfd/core.h>
53dbab7af   Haojian Zhuang   mfd: Support 88pm...
19
  #include <linux/mfd/88pm860x.h>
22aad0011   Haojian Zhuang   mfd: Adopt mfd_da...
20
  #include <linux/regulator/machine.h>
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
21

2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
22
  #define INT_STATUS_NUM			3
a5156f1ad   Haojian Zhuang   mfd: Fix build wa...
23
  static struct resource bk_resources[] __devinitdata = {
adb70483f   Haojian Zhuang   mfd: Adopt mfd_da...
24
25
26
  	{PM8606_BACKLIGHT1, PM8606_BACKLIGHT1, "backlight-0", IORESOURCE_IO,},
  	{PM8606_BACKLIGHT2, PM8606_BACKLIGHT2, "backlight-1", IORESOURCE_IO,},
  	{PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_IO,},
a16122bca   Haojian Zhuang   mfd: Append subde...
27
  };
adb70483f   Haojian Zhuang   mfd: Adopt mfd_da...
28

a5156f1ad   Haojian Zhuang   mfd: Fix build wa...
29
  static struct resource led_resources[] __devinitdata = {
3154c3446   Haojian Zhuang   mfd: Adopt mfd_da...
30
31
32
33
34
35
36
  	{PM8606_LED1_RED,   PM8606_LED1_RED,   "led0-red",   IORESOURCE_IO,},
  	{PM8606_LED1_GREEN, PM8606_LED1_GREEN, "led0-green", IORESOURCE_IO,},
  	{PM8606_LED1_BLUE,  PM8606_LED1_BLUE,  "led0-blue",  IORESOURCE_IO,},
  	{PM8606_LED2_RED,   PM8606_LED2_RED,   "led1-red",   IORESOURCE_IO,},
  	{PM8606_LED2_GREEN, PM8606_LED2_GREEN, "led1-green", IORESOURCE_IO,},
  	{PM8606_LED2_BLUE,  PM8606_LED2_BLUE,  "led1-blue",  IORESOURCE_IO,},
  };
a5156f1ad   Haojian Zhuang   mfd: Fix build wa...
37
  static struct resource regulator_resources[] __devinitdata = {
22aad0011   Haojian Zhuang   mfd: Adopt mfd_da...
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
  	{PM8607_ID_BUCK1, PM8607_ID_BUCK1, "buck-1", IORESOURCE_IO,},
  	{PM8607_ID_BUCK2, PM8607_ID_BUCK2, "buck-2", IORESOURCE_IO,},
  	{PM8607_ID_BUCK3, PM8607_ID_BUCK3, "buck-3", IORESOURCE_IO,},
  	{PM8607_ID_LDO1,  PM8607_ID_LDO1,  "ldo-01", IORESOURCE_IO,},
  	{PM8607_ID_LDO2,  PM8607_ID_LDO2,  "ldo-02", IORESOURCE_IO,},
  	{PM8607_ID_LDO3,  PM8607_ID_LDO3,  "ldo-03", IORESOURCE_IO,},
  	{PM8607_ID_LDO4,  PM8607_ID_LDO4,  "ldo-04", IORESOURCE_IO,},
  	{PM8607_ID_LDO5,  PM8607_ID_LDO5,  "ldo-05", IORESOURCE_IO,},
  	{PM8607_ID_LDO6,  PM8607_ID_LDO6,  "ldo-06", IORESOURCE_IO,},
  	{PM8607_ID_LDO7,  PM8607_ID_LDO7,  "ldo-07", IORESOURCE_IO,},
  	{PM8607_ID_LDO8,  PM8607_ID_LDO8,  "ldo-08", IORESOURCE_IO,},
  	{PM8607_ID_LDO9,  PM8607_ID_LDO9,  "ldo-09", IORESOURCE_IO,},
  	{PM8607_ID_LDO10, PM8607_ID_LDO10, "ldo-10", IORESOURCE_IO,},
  	{PM8607_ID_LDO11, PM8607_ID_LDO11, "ldo-11", IORESOURCE_IO,},
  	{PM8607_ID_LDO12, PM8607_ID_LDO12, "ldo-12", IORESOURCE_IO,},
  	{PM8607_ID_LDO13, PM8607_ID_LDO13, "ldo-13", IORESOURCE_IO,},
  	{PM8607_ID_LDO14, PM8607_ID_LDO14, "ldo-14", IORESOURCE_IO,},
  	{PM8607_ID_LDO15, PM8607_ID_LDO15, "ldo-15", IORESOURCE_IO,},
  };
a5156f1ad   Haojian Zhuang   mfd: Fix build wa...
57
  static struct resource touch_resources[] __devinitdata = {
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
58
59
  	{PM8607_IRQ_PEN, PM8607_IRQ_PEN, "touch", IORESOURCE_IRQ,},
  };
a5156f1ad   Haojian Zhuang   mfd: Fix build wa...
60
  static struct resource onkey_resources[] __devinitdata = {
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
61
62
  	{PM8607_IRQ_ONKEY, PM8607_IRQ_ONKEY, "onkey", IORESOURCE_IRQ,},
  };
a5156f1ad   Haojian Zhuang   mfd: Fix build wa...
63
  static struct resource codec_resources[] __devinitdata = {
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
64
65
66
67
68
69
70
71
72
  	/* Headset microphone insertion or removal */
  	{PM8607_IRQ_MICIN,   PM8607_IRQ_MICIN,   "micin",   IORESOURCE_IRQ,},
  	/* Hook-switch press or release */
  	{PM8607_IRQ_HOOK,    PM8607_IRQ_HOOK,    "hook",    IORESOURCE_IRQ,},
  	/* Headset insertion or removal */
  	{PM8607_IRQ_HEADSET, PM8607_IRQ_HEADSET, "headset", IORESOURCE_IRQ,},
  	/* Audio short */
  	{PM8607_IRQ_AUDIO_SHORT, PM8607_IRQ_AUDIO_SHORT, "audio-short", IORESOURCE_IRQ,},
  };
a5156f1ad   Haojian Zhuang   mfd: Fix build wa...
73
  static struct resource battery_resources[] __devinitdata = {
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
74
75
76
  	{PM8607_IRQ_CC,  PM8607_IRQ_CC,  "columb counter", IORESOURCE_IRQ,},
  	{PM8607_IRQ_BAT, PM8607_IRQ_BAT, "battery",        IORESOURCE_IRQ,},
  };
a5156f1ad   Haojian Zhuang   mfd: Fix build wa...
77
  static struct resource charger_resources[] __devinitdata = {
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
78
79
80
81
82
83
84
  	{PM8607_IRQ_CHG,  PM8607_IRQ_CHG,  "charger detect",  IORESOURCE_IRQ,},
  	{PM8607_IRQ_CHG_DONE,  PM8607_IRQ_CHG_DONE,  "charging done",       IORESOURCE_IRQ,},
  	{PM8607_IRQ_CHG_FAULT, PM8607_IRQ_CHG_FAULT, "charging timeout",    IORESOURCE_IRQ,},
  	{PM8607_IRQ_GPADC1,    PM8607_IRQ_GPADC1,    "battery temperature", IORESOURCE_IRQ,},
  	{PM8607_IRQ_VBAT, PM8607_IRQ_VBAT, "battery voltage", IORESOURCE_IRQ,},
  	{PM8607_IRQ_VCHG, PM8607_IRQ_VCHG, "vchg voltage",    IORESOURCE_IRQ,},
  };
008b30408   Haojian Zhuang   mfd: Add rtc supp...
85
86
87
  static struct resource rtc_resources[] __devinitdata = {
  	{PM8607_IRQ_RTC, PM8607_IRQ_RTC, "rtc", IORESOURCE_IRQ,},
  };
a5156f1ad   Haojian Zhuang   mfd: Fix build wa...
88
  static struct mfd_cell bk_devs[] = {
adb70483f   Haojian Zhuang   mfd: Adopt mfd_da...
89
90
91
92
  	{"88pm860x-backlight", 0,},
  	{"88pm860x-backlight", 1,},
  	{"88pm860x-backlight", 2,},
  };
a5156f1ad   Haojian Zhuang   mfd: Fix build wa...
93
  static struct mfd_cell led_devs[] = {
3154c3446   Haojian Zhuang   mfd: Adopt mfd_da...
94
95
96
97
98
99
  	{"88pm860x-led", 0,},
  	{"88pm860x-led", 1,},
  	{"88pm860x-led", 2,},
  	{"88pm860x-led", 3,},
  	{"88pm860x-led", 4,},
  	{"88pm860x-led", 5,},
a16122bca   Haojian Zhuang   mfd: Append subde...
100
  };
a5156f1ad   Haojian Zhuang   mfd: Fix build wa...
101
  static struct mfd_cell regulator_devs[] = {
22aad0011   Haojian Zhuang   mfd: Adopt mfd_da...
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
  	{"88pm860x-regulator", 0,},
  	{"88pm860x-regulator", 1,},
  	{"88pm860x-regulator", 2,},
  	{"88pm860x-regulator", 3,},
  	{"88pm860x-regulator", 4,},
  	{"88pm860x-regulator", 5,},
  	{"88pm860x-regulator", 6,},
  	{"88pm860x-regulator", 7,},
  	{"88pm860x-regulator", 8,},
  	{"88pm860x-regulator", 9,},
  	{"88pm860x-regulator", 10,},
  	{"88pm860x-regulator", 11,},
  	{"88pm860x-regulator", 12,},
  	{"88pm860x-regulator", 13,},
  	{"88pm860x-regulator", 14,},
  	{"88pm860x-regulator", 15,},
  	{"88pm860x-regulator", 16,},
  	{"88pm860x-regulator", 17,},
  };
a5156f1ad   Haojian Zhuang   mfd: Fix build wa...
121
  static struct mfd_cell touch_devs[] = {
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
122
  	{"88pm860x-touch", -1,},
a16122bca   Haojian Zhuang   mfd: Append subde...
123
  };
a5156f1ad   Haojian Zhuang   mfd: Fix build wa...
124
  static struct mfd_cell onkey_devs[] = {
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
125
  	{"88pm860x-onkey", -1,},
a16122bca   Haojian Zhuang   mfd: Append subde...
126
  };
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
127

a5156f1ad   Haojian Zhuang   mfd: Fix build wa...
128
  static struct mfd_cell codec_devs[] = {
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
129
  	{"88pm860x-codec", -1,},
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
130
131
132
  };
  
  static struct mfd_cell power_devs[] = {
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
133
134
  	{"88pm860x-battery", -1,},
  	{"88pm860x-charger", -1,},
2c36af7b5   Haojian Zhuang   mfd: Add codec re...
135
  };
008b30408   Haojian Zhuang   mfd: Add rtc supp...
136
137
138
  static struct mfd_cell rtc_devs[] = {
  	{"88pm860x-rtc", -1,},
  };
2c36af7b5   Haojian Zhuang   mfd: Add codec re...
139

2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
140
141
142
143
144
145
  struct pm860x_irq_data {
  	int	reg;
  	int	mask_reg;
  	int	enable;		/* enable or not */
  	int	offs;		/* bit offset in mask register */
  };
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
146

2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
  static struct pm860x_irq_data pm860x_irqs[] = {
  	[PM8607_IRQ_ONKEY] = {
  		.reg		= PM8607_INT_STATUS1,
  		.mask_reg	= PM8607_INT_MASK_1,
  		.offs		= 1 << 0,
  	},
  	[PM8607_IRQ_EXTON] = {
  		.reg		= PM8607_INT_STATUS1,
  		.mask_reg	= PM8607_INT_MASK_1,
  		.offs		= 1 << 1,
  	},
  	[PM8607_IRQ_CHG] = {
  		.reg		= PM8607_INT_STATUS1,
  		.mask_reg	= PM8607_INT_MASK_1,
  		.offs		= 1 << 2,
  	},
  	[PM8607_IRQ_BAT] = {
  		.reg		= PM8607_INT_STATUS1,
  		.mask_reg	= PM8607_INT_MASK_1,
  		.offs		= 1 << 3,
  	},
  	[PM8607_IRQ_RTC] = {
  		.reg		= PM8607_INT_STATUS1,
  		.mask_reg	= PM8607_INT_MASK_1,
  		.offs		= 1 << 4,
  	},
  	[PM8607_IRQ_CC] = {
  		.reg		= PM8607_INT_STATUS1,
  		.mask_reg	= PM8607_INT_MASK_1,
  		.offs		= 1 << 5,
  	},
  	[PM8607_IRQ_VBAT] = {
  		.reg		= PM8607_INT_STATUS2,
  		.mask_reg	= PM8607_INT_MASK_2,
  		.offs		= 1 << 0,
  	},
  	[PM8607_IRQ_VCHG] = {
  		.reg		= PM8607_INT_STATUS2,
  		.mask_reg	= PM8607_INT_MASK_2,
  		.offs		= 1 << 1,
  	},
  	[PM8607_IRQ_VSYS] = {
  		.reg		= PM8607_INT_STATUS2,
  		.mask_reg	= PM8607_INT_MASK_2,
  		.offs		= 1 << 2,
  	},
  	[PM8607_IRQ_TINT] = {
  		.reg		= PM8607_INT_STATUS2,
  		.mask_reg	= PM8607_INT_MASK_2,
  		.offs		= 1 << 3,
  	},
  	[PM8607_IRQ_GPADC0] = {
  		.reg		= PM8607_INT_STATUS2,
  		.mask_reg	= PM8607_INT_MASK_2,
  		.offs		= 1 << 4,
  	},
  	[PM8607_IRQ_GPADC1] = {
  		.reg		= PM8607_INT_STATUS2,
  		.mask_reg	= PM8607_INT_MASK_2,
  		.offs		= 1 << 5,
  	},
  	[PM8607_IRQ_GPADC2] = {
  		.reg		= PM8607_INT_STATUS2,
  		.mask_reg	= PM8607_INT_MASK_2,
  		.offs		= 1 << 6,
  	},
  	[PM8607_IRQ_GPADC3] = {
  		.reg		= PM8607_INT_STATUS2,
  		.mask_reg	= PM8607_INT_MASK_2,
  		.offs		= 1 << 7,
  	},
  	[PM8607_IRQ_AUDIO_SHORT] = {
  		.reg		= PM8607_INT_STATUS3,
  		.mask_reg	= PM8607_INT_MASK_3,
  		.offs		= 1 << 0,
  	},
  	[PM8607_IRQ_PEN] = {
  		.reg		= PM8607_INT_STATUS3,
  		.mask_reg	= PM8607_INT_MASK_3,
  		.offs		= 1 << 1,
  	},
  	[PM8607_IRQ_HEADSET] = {
  		.reg		= PM8607_INT_STATUS3,
  		.mask_reg	= PM8607_INT_MASK_3,
  		.offs		= 1 << 2,
  	},
  	[PM8607_IRQ_HOOK] = {
  		.reg		= PM8607_INT_STATUS3,
  		.mask_reg	= PM8607_INT_MASK_3,
  		.offs		= 1 << 3,
  	},
  	[PM8607_IRQ_MICIN] = {
  		.reg		= PM8607_INT_STATUS3,
  		.mask_reg	= PM8607_INT_MASK_3,
  		.offs		= 1 << 4,
  	},
  	[PM8607_IRQ_CHG_FAIL] = {
  		.reg		= PM8607_INT_STATUS3,
  		.mask_reg	= PM8607_INT_MASK_3,
  		.offs		= 1 << 5,
  	},
  	[PM8607_IRQ_CHG_DONE] = {
  		.reg		= PM8607_INT_STATUS3,
  		.mask_reg	= PM8607_INT_MASK_3,
  		.offs		= 1 << 6,
  	},
  	[PM8607_IRQ_CHG_FAULT] = {
  		.reg		= PM8607_INT_STATUS3,
  		.mask_reg	= PM8607_INT_MASK_3,
  		.offs		= 1 << 7,
  	},
  };
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
259

2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
260
  static irqreturn_t pm860x_irq(int irq, void *data)
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
261
  {
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
262
  	struct pm860x_chip *chip = data;
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
263
264
265
266
267
268
269
270
271
272
273
  	struct pm860x_irq_data *irq_data;
  	struct i2c_client *i2c;
  	int read_reg = -1, value = 0;
  	int i;
  
  	i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
  	for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) {
  		irq_data = &pm860x_irqs[i];
  		if (read_reg != irq_data->reg) {
  			read_reg = irq_data->reg;
  			value = pm860x_reg_read(i2c, irq_data->reg);
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
274
  		}
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
275
276
  		if (value & irq_data->enable)
  			handle_nested_irq(chip->irq_base + i);
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
277
  	}
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
278
279
  	return IRQ_HANDLED;
  }
49f89d9ac   Mark Brown   mfd: Convert 88PM...
280
  static void pm860x_irq_lock(struct irq_data *data)
53dbab7af   Haojian Zhuang   mfd: Support 88pm...
281
  {
49f89d9ac   Mark Brown   mfd: Convert 88PM...
282
  	struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
283
284
  
  	mutex_lock(&chip->irq_lock);
53dbab7af   Haojian Zhuang   mfd: Support 88pm...
285
  }
49f89d9ac   Mark Brown   mfd: Convert 88PM...
286
  static void pm860x_irq_sync_unlock(struct irq_data *data)
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
287
  {
49f89d9ac   Mark Brown   mfd: Convert 88PM...
288
  	struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
  	struct pm860x_irq_data *irq_data;
  	struct i2c_client *i2c;
  	static unsigned char cached[3] = {0x0, 0x0, 0x0};
  	unsigned char mask[3];
  	int i;
  
  	i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
  	/* Load cached value. In initial, all IRQs are masked */
  	for (i = 0; i < 3; i++)
  		mask[i] = cached[i];
  	for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) {
  		irq_data = &pm860x_irqs[i];
  		switch (irq_data->mask_reg) {
  		case PM8607_INT_MASK_1:
  			mask[0] &= ~irq_data->offs;
  			mask[0] |= irq_data->enable;
  			break;
  		case PM8607_INT_MASK_2:
  			mask[1] &= ~irq_data->offs;
  			mask[1] |= irq_data->enable;
  			break;
  		case PM8607_INT_MASK_3:
  			mask[2] &= ~irq_data->offs;
  			mask[2] |= irq_data->enable;
  			break;
  		default:
  			dev_err(chip->dev, "wrong IRQ
  ");
  			break;
  		}
  	}
  	/* update mask into registers */
  	for (i = 0; i < 3; i++) {
  		if (mask[i] != cached[i]) {
  			cached[i] = mask[i];
  			pm860x_reg_write(i2c, PM8607_INT_MASK_1 + i, mask[i]);
  		}
  	}
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
327

5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
328
  	mutex_unlock(&chip->irq_lock);
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
329
  }
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
330

49f89d9ac   Mark Brown   mfd: Convert 88PM...
331
  static void pm860x_irq_enable(struct irq_data *data)
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
332
  {
49f89d9ac   Mark Brown   mfd: Convert 88PM...
333
334
335
  	struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
  	pm860x_irqs[data->irq - chip->irq_base].enable
  		= pm860x_irqs[data->irq - chip->irq_base].offs;
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
336
  }
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
337

49f89d9ac   Mark Brown   mfd: Convert 88PM...
338
  static void pm860x_irq_disable(struct irq_data *data)
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
339
  {
49f89d9ac   Mark Brown   mfd: Convert 88PM...
340
341
  	struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
  	pm860x_irqs[data->irq - chip->irq_base].enable = 0;
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
342
343
344
345
  }
  
  static struct irq_chip pm860x_irq_chip = {
  	.name		= "88pm860x",
49f89d9ac   Mark Brown   mfd: Convert 88PM...
346
347
348
349
  	.irq_bus_lock	= pm860x_irq_lock,
  	.irq_bus_sync_unlock = pm860x_irq_sync_unlock,
  	.irq_enable	= pm860x_irq_enable,
  	.irq_disable	= pm860x_irq_disable,
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
350
  };
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
351

a16122bca   Haojian Zhuang   mfd: Append subde...
352
353
354
355
356
  static int __devinit device_gpadc_init(struct pm860x_chip *chip,
  				       struct pm860x_platform_data *pdata)
  {
  	struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \
  				: chip->companion;
eb6e8ddf0   Dan Carpenter   mfd: Fix 88pm860x...
357
358
  	int data;
  	int ret;
a16122bca   Haojian Zhuang   mfd: Append subde...
359
360
  
  	/* initialize GPADC without activating it */
eb6e8ddf0   Dan Carpenter   mfd: Fix 88pm860x...
361
362
363
364
365
366
367
368
369
370
371
372
373
  	if (!pdata || !pdata->touch)
  		return -EINVAL;
  
  	/* set GPADC MISC1 register */
  	data = 0;
  	data |= (pdata->touch->gpadc_prebias << 1) & PM8607_GPADC_PREBIAS_MASK;
  	data |= (pdata->touch->slot_cycle << 3) & PM8607_GPADC_SLOT_CYCLE_MASK;
  	data |= (pdata->touch->off_scale << 5) & PM8607_GPADC_OFF_SCALE_MASK;
  	data |= (pdata->touch->sw_cal << 7) & PM8607_GPADC_SW_CAL_MASK;
  	if (data) {
  		ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data);
  		if (ret < 0)
  			goto out;
a16122bca   Haojian Zhuang   mfd: Append subde...
374
  	}
eb6e8ddf0   Dan Carpenter   mfd: Fix 88pm860x...
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
  	/* set tsi prebias time */
  	if (pdata->touch->tsi_prebias) {
  		data = pdata->touch->tsi_prebias;
  		ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data);
  		if (ret < 0)
  			goto out;
  	}
  	/* set prebias & prechg time of pen detect */
  	data = 0;
  	data |= pdata->touch->pen_prebias & PM8607_PD_PREBIAS_MASK;
  	data |= (pdata->touch->pen_prechg << 5) & PM8607_PD_PRECHG_MASK;
  	if (data) {
  		ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data);
  		if (ret < 0)
  			goto out;
a16122bca   Haojian Zhuang   mfd: Append subde...
390
  	}
eb6e8ddf0   Dan Carpenter   mfd: Fix 88pm860x...
391
392
393
  
  	ret = pm860x_set_bits(i2c, PM8607_GPADC_MISC1,
  			      PM8607_GPADC_EN, PM8607_GPADC_EN);
a16122bca   Haojian Zhuang   mfd: Append subde...
394
395
396
  out:
  	return ret;
  }
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
397
398
399
400
401
402
  static int __devinit device_irq_init(struct pm860x_chip *chip,
  				     struct pm860x_platform_data *pdata)
  {
  	struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \
  				: chip->companion;
  	unsigned char status_buf[INT_STATUS_NUM];
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
403
  	unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
404
405
  	int i, data, mask, ret = -EINVAL;
  	int __irq;
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
406

2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
407
408
409
410
411
  	if (!pdata || !pdata->irq_base) {
  		dev_warn(chip->dev, "No interrupt support on IRQ base
  ");
  		return -EINVAL;
  	}
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
  
  	mask = PM8607_B0_MISC1_INV_INT | PM8607_B0_MISC1_INT_CLEAR
  		| PM8607_B0_MISC1_INT_MASK;
  	data = 0;
  	chip->irq_mode = 0;
  	if (pdata && pdata->irq_mode) {
  		/*
  		 * irq_mode defines the way of clearing interrupt. If it's 1,
  		 * clear IRQ by write. Otherwise, clear it by read.
  		 * This control bit is valid from 88PM8607 B0 steping.
  		 */
  		data |= PM8607_B0_MISC1_INT_CLEAR;
  		chip->irq_mode = 1;
  	}
  	ret = pm860x_set_bits(i2c, PM8607_B0_MISC1, mask, data);
  	if (ret < 0)
  		goto out;
  
  	/* mask all IRQs */
  	memset(status_buf, 0, INT_STATUS_NUM);
  	ret = pm860x_bulk_write(i2c, PM8607_INT_MASK_1,
  				INT_STATUS_NUM, status_buf);
  	if (ret < 0)
  		goto out;
  
  	if (chip->irq_mode) {
  		/* clear interrupt status by write */
  		memset(status_buf, 0xFF, INT_STATUS_NUM);
  		ret = pm860x_bulk_write(i2c, PM8607_INT_STATUS1,
  					INT_STATUS_NUM, status_buf);
  	} else {
  		/* clear interrupt status by read */
  		ret = pm860x_bulk_read(i2c, PM8607_INT_STATUS1,
  					INT_STATUS_NUM, status_buf);
  	}
  	if (ret < 0)
  		goto out;
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
449
450
451
452
  	mutex_init(&chip->irq_lock);
  	chip->irq_base = pdata->irq_base;
  	chip->core_irq = i2c->irq;
  	if (!chip->core_irq)
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
453
  		goto out;
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
454

2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
455
456
457
  	/* register IRQ by genirq */
  	for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) {
  		__irq = i + chip->irq_base;
d5bb12216   Thomas Gleixner   mfd: Cleanup irq ...
458
459
  		irq_set_chip_data(__irq, chip);
  		irq_set_chip_and_handler(__irq, &pm860x_irq_chip,
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
460
  					 handle_edge_irq);
d5bb12216   Thomas Gleixner   mfd: Cleanup irq ...
461
  		irq_set_nested_thread(__irq, 1);
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
462
463
464
  #ifdef CONFIG_ARM
  		set_irq_flags(__irq, IRQF_VALID);
  #else
d5bb12216   Thomas Gleixner   mfd: Cleanup irq ...
465
  		irq_set_noprobe(__irq);
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
466
  #endif
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
467
  	}
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
468
469
470
471
472
473
474
475
  
  	ret = request_threaded_irq(chip->core_irq, NULL, pm860x_irq, flags,
  				   "88pm860x", chip);
  	if (ret) {
  		dev_err(chip->dev, "Failed to request IRQ: %d
  ", ret);
  		chip->core_irq = 0;
  	}
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
476
477
  	return 0;
  out:
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
478
  	chip->core_irq = 0;
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
479
480
  	return ret;
  }
872c1b14e   Henrik Kretzschmar   mfd: Section clea...
481
  static void device_irq_exit(struct pm860x_chip *chip)
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
482
  {
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
483
484
  	if (chip->core_irq)
  		free_irq(chip->core_irq, chip);
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
485
  }
adb70483f   Haojian Zhuang   mfd: Adopt mfd_da...
486
  static void __devinit device_bk_init(struct pm860x_chip *chip,
adb70483f   Haojian Zhuang   mfd: Adopt mfd_da...
487
488
489
490
491
492
493
494
495
496
497
498
  				     struct pm860x_platform_data *pdata)
  {
  	int ret;
  	int i, j, id;
  
  	if ((pdata == NULL) || (pdata->backlight == NULL))
  		return;
  
  	if (pdata->num_backlights > ARRAY_SIZE(bk_devs))
  		pdata->num_backlights = ARRAY_SIZE(bk_devs);
  
  	for (i = 0; i < pdata->num_backlights; i++) {
f5fb758de   Haojian Zhuang   mfd: Avoid to all...
499
500
  		bk_devs[i].platform_data = &pdata->backlight[i];
  		bk_devs[i].pdata_size = sizeof(struct pm860x_backlight_pdata);
adb70483f   Haojian Zhuang   mfd: Adopt mfd_da...
501
502
503
  
  		for (j = 0; j < ARRAY_SIZE(bk_devs); j++) {
  			id = bk_resources[j].start;
f5fb758de   Haojian Zhuang   mfd: Avoid to all...
504
  			if (pdata->backlight[i].flags != id)
adb70483f   Haojian Zhuang   mfd: Adopt mfd_da...
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
  				continue;
  
  			bk_devs[i].num_resources = 1;
  			bk_devs[i].resources = &bk_resources[j];
  			ret = mfd_add_devices(chip->dev, 0,
  					      &bk_devs[i], 1,
  					      &bk_resources[j], 0);
  			if (ret < 0) {
  				dev_err(chip->dev, "Failed to add "
  					"backlight subdev
  ");
  				return;
  			}
  		}
  	}
  }
3154c3446   Haojian Zhuang   mfd: Adopt mfd_da...
521
  static void __devinit device_led_init(struct pm860x_chip *chip,
3154c3446   Haojian Zhuang   mfd: Adopt mfd_da...
522
  				      struct pm860x_platform_data *pdata)
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
523
  {
a16122bca   Haojian Zhuang   mfd: Append subde...
524
  	int ret;
3154c3446   Haojian Zhuang   mfd: Adopt mfd_da...
525
  	int i, j, id;
a16122bca   Haojian Zhuang   mfd: Append subde...
526

3154c3446   Haojian Zhuang   mfd: Adopt mfd_da...
527
528
529
530
531
532
533
  	if ((pdata == NULL) || (pdata->led == NULL))
  		return;
  
  	if (pdata->num_leds > ARRAY_SIZE(led_devs))
  		pdata->num_leds = ARRAY_SIZE(led_devs);
  
  	for (i = 0; i < pdata->num_leds; i++) {
f5fb758de   Haojian Zhuang   mfd: Avoid to all...
534
535
  		led_devs[i].platform_data = &pdata->led[i];
  		led_devs[i].pdata_size = sizeof(struct pm860x_led_pdata);
3154c3446   Haojian Zhuang   mfd: Adopt mfd_da...
536
537
538
  
  		for (j = 0; j < ARRAY_SIZE(led_devs); j++) {
  			id = led_resources[j].start;
f5fb758de   Haojian Zhuang   mfd: Avoid to all...
539
  			if (pdata->led[i].flags != id)
3154c3446   Haojian Zhuang   mfd: Adopt mfd_da...
540
541
542
543
544
545
546
547
548
549
550
551
552
  				continue;
  
  			led_devs[i].num_resources = 1;
  			led_devs[i].resources = &led_resources[j],
  			ret = mfd_add_devices(chip->dev, 0,
  					      &led_devs[i], 1,
  					      &led_resources[j], 0);
  			if (ret < 0) {
  				dev_err(chip->dev, "Failed to add "
  					"led subdev
  ");
  				return;
  			}
a16122bca   Haojian Zhuang   mfd: Append subde...
553
554
  		}
  	}
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
555
  }
22aad0011   Haojian Zhuang   mfd: Adopt mfd_da...
556
  static void __devinit device_regulator_init(struct pm860x_chip *chip,
22aad0011   Haojian Zhuang   mfd: Adopt mfd_da...
557
558
559
560
  					    struct pm860x_platform_data *pdata)
  {
  	struct regulator_init_data *initdata;
  	int ret;
586e1a176   Haojian Zhuang   mfd: Avoid to use...
561
  	int i, seq;
22aad0011   Haojian Zhuang   mfd: Adopt mfd_da...
562
563
564
565
566
567
  
  	if ((pdata == NULL) || (pdata->regulator == NULL))
  		return;
  
  	if (pdata->num_regulators > ARRAY_SIZE(regulator_devs))
  		pdata->num_regulators = ARRAY_SIZE(regulator_devs);
586e1a176   Haojian Zhuang   mfd: Avoid to use...
568
  	for (i = 0, seq = -1; i < pdata->num_regulators; i++) {
22aad0011   Haojian Zhuang   mfd: Adopt mfd_da...
569
  		initdata = &pdata->regulator[i];
586e1a176   Haojian Zhuang   mfd: Avoid to use...
570
571
572
573
574
  		seq = *(unsigned int *)initdata->driver_data;
  		if ((seq < 0) || (seq > PM8607_ID_RG_MAX)) {
  			dev_err(chip->dev, "Wrong ID(%d) on regulator(%s)
  ",
  				seq, initdata->constraints.name);
22aad0011   Haojian Zhuang   mfd: Adopt mfd_da...
575
576
  			goto out;
  		}
f5fb758de   Haojian Zhuang   mfd: Avoid to all...
577
578
  		regulator_devs[i].platform_data = &pdata->regulator[i];
  		regulator_devs[i].pdata_size = sizeof(struct regulator_init_data);
22aad0011   Haojian Zhuang   mfd: Adopt mfd_da...
579
  		regulator_devs[i].num_resources = 1;
586e1a176   Haojian Zhuang   mfd: Avoid to use...
580
  		regulator_devs[i].resources = &regulator_resources[seq];
22aad0011   Haojian Zhuang   mfd: Adopt mfd_da...
581
582
  
  		ret = mfd_add_devices(chip->dev, 0, &regulator_devs[i], 1,
586e1a176   Haojian Zhuang   mfd: Avoid to use...
583
  				      &regulator_resources[seq], 0);
22aad0011   Haojian Zhuang   mfd: Adopt mfd_da...
584
585
586
587
588
589
590
591
592
  		if (ret < 0) {
  			dev_err(chip->dev, "Failed to add regulator subdev
  ");
  			goto out;
  		}
  	}
  out:
  	return;
  }
008b30408   Haojian Zhuang   mfd: Add rtc supp...
593
  static void __devinit device_rtc_init(struct pm860x_chip *chip,
008b30408   Haojian Zhuang   mfd: Add rtc supp...
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
  				      struct pm860x_platform_data *pdata)
  {
  	int ret;
  
  	if ((pdata == NULL))
  		return;
  
  	rtc_devs[0].platform_data = pdata->rtc;
  	rtc_devs[0].pdata_size = sizeof(struct pm860x_rtc_pdata);
  	rtc_devs[0].num_resources = ARRAY_SIZE(rtc_resources);
  	rtc_devs[0].resources = &rtc_resources[0];
  	ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
  			      ARRAY_SIZE(rtc_devs), &rtc_resources[0],
  			      chip->irq_base);
  	if (ret < 0)
  		dev_err(chip->dev, "Failed to add rtc subdev
  ");
  }
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
612
  static void __devinit device_touch_init(struct pm860x_chip *chip,
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
613
614
615
  					struct pm860x_platform_data *pdata)
  {
  	int ret;
f5fb758de   Haojian Zhuang   mfd: Avoid to all...
616
  	if (pdata == NULL)
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
617
  		return;
f5fb758de   Haojian Zhuang   mfd: Avoid to all...
618
619
  	touch_devs[0].platform_data = pdata->touch;
  	touch_devs[0].pdata_size = sizeof(struct pm860x_touch_pdata);
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
620
621
622
623
624
625
626
627
628
629
630
  	touch_devs[0].num_resources = ARRAY_SIZE(touch_resources);
  	touch_devs[0].resources = &touch_resources[0];
  	ret = mfd_add_devices(chip->dev, 0, &touch_devs[0],
  			      ARRAY_SIZE(touch_devs), &touch_resources[0],
  			      chip->irq_base);
  	if (ret < 0)
  		dev_err(chip->dev, "Failed to add touch subdev
  ");
  }
  
  static void __devinit device_power_init(struct pm860x_chip *chip,
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
631
632
633
  					struct pm860x_platform_data *pdata)
  {
  	int ret;
f5fb758de   Haojian Zhuang   mfd: Avoid to all...
634
  	if (pdata == NULL)
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
635
  		return;
f5fb758de   Haojian Zhuang   mfd: Avoid to all...
636
637
  	power_devs[0].platform_data = pdata->power;
  	power_devs[0].pdata_size = sizeof(struct pm860x_power_pdata);
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
638
639
640
641
642
643
644
  	power_devs[0].num_resources = ARRAY_SIZE(battery_resources);
  	power_devs[0].resources = &battery_resources[0],
  	ret = mfd_add_devices(chip->dev, 0, &power_devs[0], 1,
  			      &battery_resources[0], chip->irq_base);
  	if (ret < 0)
  		dev_err(chip->dev, "Failed to add battery subdev
  ");
f5fb758de   Haojian Zhuang   mfd: Avoid to all...
645
646
  	power_devs[1].platform_data = pdata->power;
  	power_devs[1].pdata_size = sizeof(struct pm860x_power_pdata);
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
647
648
649
650
651
652
653
654
655
656
  	power_devs[1].num_resources = ARRAY_SIZE(charger_resources);
  	power_devs[1].resources = &charger_resources[0],
  	ret = mfd_add_devices(chip->dev, 0, &power_devs[1], 1,
  			      &charger_resources[0], chip->irq_base);
  	if (ret < 0)
  		dev_err(chip->dev, "Failed to add charger subdev
  ");
  }
  
  static void __devinit device_onkey_init(struct pm860x_chip *chip,
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
  					struct pm860x_platform_data *pdata)
  {
  	int ret;
  
  	onkey_devs[0].num_resources = ARRAY_SIZE(onkey_resources);
  	onkey_devs[0].resources = &onkey_resources[0],
  	ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0],
  			      ARRAY_SIZE(onkey_devs), &onkey_resources[0],
  			      chip->irq_base);
  	if (ret < 0)
  		dev_err(chip->dev, "Failed to add onkey subdev
  ");
  }
  
  static void __devinit device_codec_init(struct pm860x_chip *chip,
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
672
673
674
675
676
677
678
679
680
681
682
683
  					struct pm860x_platform_data *pdata)
  {
  	int ret;
  
  	codec_devs[0].num_resources = ARRAY_SIZE(codec_resources);
  	codec_devs[0].resources = &codec_resources[0],
  	ret = mfd_add_devices(chip->dev, 0, &codec_devs[0],
  			      ARRAY_SIZE(codec_devs), &codec_resources[0], 0);
  	if (ret < 0)
  		dev_err(chip->dev, "Failed to add codec subdev
  ");
  }
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
684
685
686
687
  static void __devinit device_8607_init(struct pm860x_chip *chip,
  				       struct i2c_client *i2c,
  				       struct pm860x_platform_data *pdata)
  {
a16122bca   Haojian Zhuang   mfd: Append subde...
688
  	int data, ret;
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
689

53dbab7af   Haojian Zhuang   mfd: Support 88pm...
690
  	ret = pm860x_reg_read(i2c, PM8607_CHIP_ID);
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
691
692
693
694
695
  	if (ret < 0) {
  		dev_err(chip->dev, "Failed to read CHIP ID: %d
  ", ret);
  		goto out;
  	}
38b340527   Haojian Zhuang   mfd: Update chip ...
696
697
698
  	switch (ret & PM8607_VERSION_MASK) {
  	case 0x40:
  	case 0x50:
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
699
700
701
  		dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected
  ",
  			 ret);
38b340527   Haojian Zhuang   mfd: Update chip ...
702
703
  		break;
  	default:
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
704
705
706
707
708
  		dev_err(chip->dev, "Failed to detect Marvell 88PM8607. "
  			"Chip ID: %02x
  ", ret);
  		goto out;
  	}
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
709

53dbab7af   Haojian Zhuang   mfd: Support 88pm...
710
  	ret = pm860x_reg_read(i2c, PM8607_BUCK3);
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
711
712
713
714
715
716
717
  	if (ret < 0) {
  		dev_err(chip->dev, "Failed to read BUCK3 register: %d
  ", ret);
  		goto out;
  	}
  	if (ret & PM8607_BUCK3_DOUBLE)
  		chip->buck3_double = 1;
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
718
  	ret = pm860x_reg_read(i2c, PM8607_B0_MISC1);
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
719
720
721
722
723
  	if (ret < 0) {
  		dev_err(chip->dev, "Failed to read MISC1 register: %d
  ", ret);
  		goto out;
  	}
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
724

5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
725
726
727
728
729
730
731
732
733
734
  	if (pdata && (pdata->i2c_port == PI2C_PORT))
  		data = PM8607_B0_MISC1_PI2C;
  	else
  		data = 0;
  	ret = pm860x_set_bits(i2c, PM8607_B0_MISC1, PM8607_B0_MISC1_PI2C, data);
  	if (ret < 0) {
  		dev_err(chip->dev, "Failed to access MISC1:%d
  ", ret);
  		goto out;
  	}
a16122bca   Haojian Zhuang   mfd: Append subde...
735
736
737
  	ret = device_gpadc_init(chip, pdata);
  	if (ret < 0)
  		goto out;
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
738
739
740
  	ret = device_irq_init(chip, pdata);
  	if (ret < 0)
  		goto out;
cea438dda   Haojian Zhuang   mfd: Remove unuse...
741
742
743
744
745
746
  	device_regulator_init(chip, pdata);
  	device_rtc_init(chip, pdata);
  	device_onkey_init(chip, pdata);
  	device_touch_init(chip, pdata);
  	device_power_init(chip, pdata);
  	device_codec_init(chip, pdata);
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
747
  out:
53dbab7af   Haojian Zhuang   mfd: Support 88pm...
748
749
  	return;
  }
872c1b14e   Henrik Kretzschmar   mfd: Section clea...
750
  int __devinit pm860x_device_init(struct pm860x_chip *chip,
53dbab7af   Haojian Zhuang   mfd: Support 88pm...
751
752
  		       struct pm860x_platform_data *pdata)
  {
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
753
  	chip->core_irq = 0;
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
754

53dbab7af   Haojian Zhuang   mfd: Support 88pm...
755
756
  	switch (chip->id) {
  	case CHIP_PM8606:
cea438dda   Haojian Zhuang   mfd: Remove unuse...
757
758
  		device_bk_init(chip, pdata);
  		device_led_init(chip, pdata);
53dbab7af   Haojian Zhuang   mfd: Support 88pm...
759
760
761
762
763
764
765
766
767
  		break;
  	case CHIP_PM8607:
  		device_8607_init(chip, chip->client, pdata);
  		break;
  	}
  
  	if (chip->companion) {
  		switch (chip->id) {
  		case CHIP_PM8607:
cea438dda   Haojian Zhuang   mfd: Remove unuse...
768
769
  			device_bk_init(chip, pdata);
  			device_led_init(chip, pdata);
53dbab7af   Haojian Zhuang   mfd: Support 88pm...
770
771
772
773
774
775
  			break;
  		case CHIP_PM8606:
  			device_8607_init(chip, chip->companion, pdata);
  			break;
  		}
  	}
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
776

53dbab7af   Haojian Zhuang   mfd: Support 88pm...
777
  	return 0;
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
778
  }
872c1b14e   Henrik Kretzschmar   mfd: Section clea...
779
  void __devexit pm860x_device_exit(struct pm860x_chip *chip)
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
780
  {
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
781
  	device_irq_exit(chip);
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
782
783
  	mfd_remove_devices(chip->dev);
  }
53dbab7af   Haojian Zhuang   mfd: Support 88pm...
784
  MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM860x");
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
785
786
  MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
  MODULE_LICENSE("GPL");