xref: /openbmc/linux/drivers/mfd/88pm860x-core.c (revision c10c2aab)
1 /*
2  * Base driver for Marvell 88PM8607
3  *
4  * Copyright (C) 2009 Marvell International Ltd.
5  * 	Haojian Zhuang <haojian.zhuang@marvell.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11 
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/i2c.h>
15 #include <linux/irq.h>
16 #include <linux/interrupt.h>
17 #include <linux/platform_device.h>
18 #include <linux/mfd/core.h>
19 #include <linux/mfd/88pm860x.h>
20 #include <linux/regulator/machine.h>
21 
22 #define INT_STATUS_NUM			3
23 
24 static struct resource io_parent = {
25 	.start = 0,
26 	.end   = 0xffffffff,
27 	.flags = IORESOURCE_IO,
28 };
29 
30 static struct resource bk_resources[] __devinitdata = {
31 	{PM8606_BACKLIGHT1, PM8606_BACKLIGHT1, "backlight-0", IORESOURCE_IO,
32 	 &io_parent,},
33 	{PM8606_BACKLIGHT2, PM8606_BACKLIGHT2, "backlight-1", IORESOURCE_IO,
34 	 &io_parent,},
35 	{PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_IO,
36 	 &io_parent,},
37 };
38 
39 static struct resource led_resources[] __devinitdata = {
40 	{PM8606_LED1_RED,   PM8606_LED1_RED,   "led0-red",   IORESOURCE_IO,
41 	 &io_parent,},
42 	{PM8606_LED1_GREEN, PM8606_LED1_GREEN, "led0-green", IORESOURCE_IO,
43 	 &io_parent,},
44 	{PM8606_LED1_BLUE,  PM8606_LED1_BLUE,  "led0-blue",  IORESOURCE_IO,
45 	 &io_parent,},
46 	{PM8606_LED2_RED,   PM8606_LED2_RED,   "led1-red",   IORESOURCE_IO,
47 	 &io_parent,},
48 	{PM8606_LED2_GREEN, PM8606_LED2_GREEN, "led1-green", IORESOURCE_IO,
49 	 &io_parent,},
50 	{PM8606_LED2_BLUE,  PM8606_LED2_BLUE,  "led1-blue",  IORESOURCE_IO,
51 	 &io_parent,},
52 };
53 
54 static struct resource regulator_resources[] __devinitdata = {
55 	{PM8607_ID_BUCK1, PM8607_ID_BUCK1, "buck-1", IORESOURCE_IO,
56 	 &io_parent,},
57 	{PM8607_ID_BUCK2, PM8607_ID_BUCK2, "buck-2", IORESOURCE_IO,
58 	 &io_parent,},
59 	{PM8607_ID_BUCK3, PM8607_ID_BUCK3, "buck-3", IORESOURCE_IO,
60 	 &io_parent,},
61 	{PM8607_ID_LDO1,  PM8607_ID_LDO1,  "ldo-01", IORESOURCE_IO,
62 	 &io_parent,},
63 	{PM8607_ID_LDO2,  PM8607_ID_LDO2,  "ldo-02", IORESOURCE_IO,
64 	 &io_parent,},
65 	{PM8607_ID_LDO3,  PM8607_ID_LDO3,  "ldo-03", IORESOURCE_IO,
66 	 &io_parent,},
67 	{PM8607_ID_LDO4,  PM8607_ID_LDO4,  "ldo-04", IORESOURCE_IO,
68 	 &io_parent,},
69 	{PM8607_ID_LDO5,  PM8607_ID_LDO5,  "ldo-05", IORESOURCE_IO,
70 	 &io_parent,},
71 	{PM8607_ID_LDO6,  PM8607_ID_LDO6,  "ldo-06", IORESOURCE_IO,
72 	 &io_parent,},
73 	{PM8607_ID_LDO7,  PM8607_ID_LDO7,  "ldo-07", IORESOURCE_IO,
74 	 &io_parent,},
75 	{PM8607_ID_LDO8,  PM8607_ID_LDO8,  "ldo-08", IORESOURCE_IO,
76 	 &io_parent,},
77 	{PM8607_ID_LDO9,  PM8607_ID_LDO9,  "ldo-09", IORESOURCE_IO,
78 	 &io_parent,},
79 	{PM8607_ID_LDO10, PM8607_ID_LDO10, "ldo-10", IORESOURCE_IO,
80 	 &io_parent,},
81 	{PM8607_ID_LDO11, PM8607_ID_LDO11, "ldo-11", IORESOURCE_IO,
82 	 &io_parent,},
83 	{PM8607_ID_LDO12, PM8607_ID_LDO12, "ldo-12", IORESOURCE_IO,
84 	 &io_parent,},
85 	{PM8607_ID_LDO13, PM8607_ID_LDO13, "ldo-13", IORESOURCE_IO,
86 	 &io_parent,},
87 	{PM8607_ID_LDO14, PM8607_ID_LDO14, "ldo-14", IORESOURCE_IO,
88 	 &io_parent,},
89 	{PM8607_ID_LDO15, PM8607_ID_LDO15, "ldo-15", IORESOURCE_IO,
90 	 &io_parent,},
91 };
92 
93 static struct resource touch_resources[] __devinitdata = {
94 	{PM8607_IRQ_PEN, PM8607_IRQ_PEN, "touch", IORESOURCE_IRQ,},
95 };
96 
97 static struct resource onkey_resources[] __devinitdata = {
98 	{PM8607_IRQ_ONKEY, PM8607_IRQ_ONKEY, "onkey", IORESOURCE_IRQ,},
99 };
100 
101 static struct resource codec_resources[] __devinitdata = {
102 	/* Headset microphone insertion or removal */
103 	{PM8607_IRQ_MICIN,   PM8607_IRQ_MICIN,   "micin",   IORESOURCE_IRQ,},
104 	/* Hook-switch press or release */
105 	{PM8607_IRQ_HOOK,    PM8607_IRQ_HOOK,    "hook",    IORESOURCE_IRQ,},
106 	/* Headset insertion or removal */
107 	{PM8607_IRQ_HEADSET, PM8607_IRQ_HEADSET, "headset", IORESOURCE_IRQ,},
108 	/* Audio short */
109 	{PM8607_IRQ_AUDIO_SHORT, PM8607_IRQ_AUDIO_SHORT, "audio-short", IORESOURCE_IRQ,},
110 };
111 
112 static struct resource battery_resources[] __devinitdata = {
113 	{PM8607_IRQ_CC,  PM8607_IRQ_CC,  "columb counter", IORESOURCE_IRQ,},
114 	{PM8607_IRQ_BAT, PM8607_IRQ_BAT, "battery",        IORESOURCE_IRQ,},
115 };
116 
117 static struct resource charger_resources[] __devinitdata = {
118 	{PM8607_IRQ_CHG,  PM8607_IRQ_CHG,  "charger detect",  IORESOURCE_IRQ,},
119 	{PM8607_IRQ_CHG_DONE,  PM8607_IRQ_CHG_DONE,  "charging done",       IORESOURCE_IRQ,},
120 	{PM8607_IRQ_CHG_FAULT, PM8607_IRQ_CHG_FAULT, "charging timeout",    IORESOURCE_IRQ,},
121 	{PM8607_IRQ_GPADC1,    PM8607_IRQ_GPADC1,    "battery temperature", IORESOURCE_IRQ,},
122 	{PM8607_IRQ_VBAT, PM8607_IRQ_VBAT, "battery voltage", IORESOURCE_IRQ,},
123 	{PM8607_IRQ_VCHG, PM8607_IRQ_VCHG, "vchg voltage",    IORESOURCE_IRQ,},
124 };
125 
126 static struct resource preg_resources[] __devinitdata = {
127 	{PM8606_ID_PREG,  PM8606_ID_PREG,  "preg",   IORESOURCE_IO,
128 	 &io_parent,},
129 };
130 
131 static struct resource rtc_resources[] __devinitdata = {
132 	{PM8607_IRQ_RTC, PM8607_IRQ_RTC, "rtc", IORESOURCE_IRQ, &io_parent,},
133 };
134 
135 static struct mfd_cell bk_devs[] = {
136 	{"88pm860x-backlight", 0,},
137 	{"88pm860x-backlight", 1,},
138 	{"88pm860x-backlight", 2,},
139 };
140 
141 static struct mfd_cell led_devs[] = {
142 	{"88pm860x-led", 0,},
143 	{"88pm860x-led", 1,},
144 	{"88pm860x-led", 2,},
145 	{"88pm860x-led", 3,},
146 	{"88pm860x-led", 4,},
147 	{"88pm860x-led", 5,},
148 };
149 
150 static struct mfd_cell regulator_devs[] = {
151 	{"88pm860x-regulator", 0,},
152 	{"88pm860x-regulator", 1,},
153 	{"88pm860x-regulator", 2,},
154 	{"88pm860x-regulator", 3,},
155 	{"88pm860x-regulator", 4,},
156 	{"88pm860x-regulator", 5,},
157 	{"88pm860x-regulator", 6,},
158 	{"88pm860x-regulator", 7,},
159 	{"88pm860x-regulator", 8,},
160 	{"88pm860x-regulator", 9,},
161 	{"88pm860x-regulator", 10,},
162 	{"88pm860x-regulator", 11,},
163 	{"88pm860x-regulator", 12,},
164 	{"88pm860x-regulator", 13,},
165 	{"88pm860x-regulator", 14,},
166 	{"88pm860x-regulator", 15,},
167 	{"88pm860x-regulator", 16,},
168 	{"88pm860x-regulator", 17,},
169 };
170 
171 static struct mfd_cell touch_devs[] = {
172 	{"88pm860x-touch", -1,},
173 };
174 
175 static struct mfd_cell onkey_devs[] = {
176 	{"88pm860x-onkey", -1,},
177 };
178 
179 static struct mfd_cell codec_devs[] = {
180 	{"88pm860x-codec", -1,},
181 };
182 
183 static struct regulator_consumer_supply preg_supply[] = {
184 	REGULATOR_SUPPLY("preg", "charger-manager"),
185 };
186 
187 static struct regulator_init_data preg_init_data = {
188 	.num_consumer_supplies	= ARRAY_SIZE(preg_supply),
189 	.consumer_supplies	= &preg_supply[0],
190 };
191 
192 static struct mfd_cell power_devs[] = {
193 	{"88pm860x-battery", -1,},
194 	{"88pm860x-charger", -1,},
195 	{"88pm860x-preg",    -1,},
196 };
197 
198 static struct mfd_cell rtc_devs[] = {
199 	{"88pm860x-rtc", -1,},
200 };
201 
202 
203 struct pm860x_irq_data {
204 	int	reg;
205 	int	mask_reg;
206 	int	enable;		/* enable or not */
207 	int	offs;		/* bit offset in mask register */
208 };
209 
210 static struct pm860x_irq_data pm860x_irqs[] = {
211 	[PM8607_IRQ_ONKEY] = {
212 		.reg		= PM8607_INT_STATUS1,
213 		.mask_reg	= PM8607_INT_MASK_1,
214 		.offs		= 1 << 0,
215 	},
216 	[PM8607_IRQ_EXTON] = {
217 		.reg		= PM8607_INT_STATUS1,
218 		.mask_reg	= PM8607_INT_MASK_1,
219 		.offs		= 1 << 1,
220 	},
221 	[PM8607_IRQ_CHG] = {
222 		.reg		= PM8607_INT_STATUS1,
223 		.mask_reg	= PM8607_INT_MASK_1,
224 		.offs		= 1 << 2,
225 	},
226 	[PM8607_IRQ_BAT] = {
227 		.reg		= PM8607_INT_STATUS1,
228 		.mask_reg	= PM8607_INT_MASK_1,
229 		.offs		= 1 << 3,
230 	},
231 	[PM8607_IRQ_RTC] = {
232 		.reg		= PM8607_INT_STATUS1,
233 		.mask_reg	= PM8607_INT_MASK_1,
234 		.offs		= 1 << 4,
235 	},
236 	[PM8607_IRQ_CC] = {
237 		.reg		= PM8607_INT_STATUS1,
238 		.mask_reg	= PM8607_INT_MASK_1,
239 		.offs		= 1 << 5,
240 	},
241 	[PM8607_IRQ_VBAT] = {
242 		.reg		= PM8607_INT_STATUS2,
243 		.mask_reg	= PM8607_INT_MASK_2,
244 		.offs		= 1 << 0,
245 	},
246 	[PM8607_IRQ_VCHG] = {
247 		.reg		= PM8607_INT_STATUS2,
248 		.mask_reg	= PM8607_INT_MASK_2,
249 		.offs		= 1 << 1,
250 	},
251 	[PM8607_IRQ_VSYS] = {
252 		.reg		= PM8607_INT_STATUS2,
253 		.mask_reg	= PM8607_INT_MASK_2,
254 		.offs		= 1 << 2,
255 	},
256 	[PM8607_IRQ_TINT] = {
257 		.reg		= PM8607_INT_STATUS2,
258 		.mask_reg	= PM8607_INT_MASK_2,
259 		.offs		= 1 << 3,
260 	},
261 	[PM8607_IRQ_GPADC0] = {
262 		.reg		= PM8607_INT_STATUS2,
263 		.mask_reg	= PM8607_INT_MASK_2,
264 		.offs		= 1 << 4,
265 	},
266 	[PM8607_IRQ_GPADC1] = {
267 		.reg		= PM8607_INT_STATUS2,
268 		.mask_reg	= PM8607_INT_MASK_2,
269 		.offs		= 1 << 5,
270 	},
271 	[PM8607_IRQ_GPADC2] = {
272 		.reg		= PM8607_INT_STATUS2,
273 		.mask_reg	= PM8607_INT_MASK_2,
274 		.offs		= 1 << 6,
275 	},
276 	[PM8607_IRQ_GPADC3] = {
277 		.reg		= PM8607_INT_STATUS2,
278 		.mask_reg	= PM8607_INT_MASK_2,
279 		.offs		= 1 << 7,
280 	},
281 	[PM8607_IRQ_AUDIO_SHORT] = {
282 		.reg		= PM8607_INT_STATUS3,
283 		.mask_reg	= PM8607_INT_MASK_3,
284 		.offs		= 1 << 0,
285 	},
286 	[PM8607_IRQ_PEN] = {
287 		.reg		= PM8607_INT_STATUS3,
288 		.mask_reg	= PM8607_INT_MASK_3,
289 		.offs		= 1 << 1,
290 	},
291 	[PM8607_IRQ_HEADSET] = {
292 		.reg		= PM8607_INT_STATUS3,
293 		.mask_reg	= PM8607_INT_MASK_3,
294 		.offs		= 1 << 2,
295 	},
296 	[PM8607_IRQ_HOOK] = {
297 		.reg		= PM8607_INT_STATUS3,
298 		.mask_reg	= PM8607_INT_MASK_3,
299 		.offs		= 1 << 3,
300 	},
301 	[PM8607_IRQ_MICIN] = {
302 		.reg		= PM8607_INT_STATUS3,
303 		.mask_reg	= PM8607_INT_MASK_3,
304 		.offs		= 1 << 4,
305 	},
306 	[PM8607_IRQ_CHG_FAIL] = {
307 		.reg		= PM8607_INT_STATUS3,
308 		.mask_reg	= PM8607_INT_MASK_3,
309 		.offs		= 1 << 5,
310 	},
311 	[PM8607_IRQ_CHG_DONE] = {
312 		.reg		= PM8607_INT_STATUS3,
313 		.mask_reg	= PM8607_INT_MASK_3,
314 		.offs		= 1 << 6,
315 	},
316 	[PM8607_IRQ_CHG_FAULT] = {
317 		.reg		= PM8607_INT_STATUS3,
318 		.mask_reg	= PM8607_INT_MASK_3,
319 		.offs		= 1 << 7,
320 	},
321 };
322 
323 static irqreturn_t pm860x_irq(int irq, void *data)
324 {
325 	struct pm860x_chip *chip = data;
326 	struct pm860x_irq_data *irq_data;
327 	struct i2c_client *i2c;
328 	int read_reg = -1, value = 0;
329 	int i;
330 
331 	i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
332 	for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) {
333 		irq_data = &pm860x_irqs[i];
334 		if (read_reg != irq_data->reg) {
335 			read_reg = irq_data->reg;
336 			value = pm860x_reg_read(i2c, irq_data->reg);
337 		}
338 		if (value & irq_data->enable)
339 			handle_nested_irq(chip->irq_base + i);
340 	}
341 	return IRQ_HANDLED;
342 }
343 
344 static void pm860x_irq_lock(struct irq_data *data)
345 {
346 	struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
347 
348 	mutex_lock(&chip->irq_lock);
349 }
350 
351 static void pm860x_irq_sync_unlock(struct irq_data *data)
352 {
353 	struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
354 	struct pm860x_irq_data *irq_data;
355 	struct i2c_client *i2c;
356 	static unsigned char cached[3] = {0x0, 0x0, 0x0};
357 	unsigned char mask[3];
358 	int i;
359 
360 	i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
361 	/* Load cached value. In initial, all IRQs are masked */
362 	for (i = 0; i < 3; i++)
363 		mask[i] = cached[i];
364 	for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) {
365 		irq_data = &pm860x_irqs[i];
366 		switch (irq_data->mask_reg) {
367 		case PM8607_INT_MASK_1:
368 			mask[0] &= ~irq_data->offs;
369 			mask[0] |= irq_data->enable;
370 			break;
371 		case PM8607_INT_MASK_2:
372 			mask[1] &= ~irq_data->offs;
373 			mask[1] |= irq_data->enable;
374 			break;
375 		case PM8607_INT_MASK_3:
376 			mask[2] &= ~irq_data->offs;
377 			mask[2] |= irq_data->enable;
378 			break;
379 		default:
380 			dev_err(chip->dev, "wrong IRQ\n");
381 			break;
382 		}
383 	}
384 	/* update mask into registers */
385 	for (i = 0; i < 3; i++) {
386 		if (mask[i] != cached[i]) {
387 			cached[i] = mask[i];
388 			pm860x_reg_write(i2c, PM8607_INT_MASK_1 + i, mask[i]);
389 		}
390 	}
391 
392 	mutex_unlock(&chip->irq_lock);
393 }
394 
395 static void pm860x_irq_enable(struct irq_data *data)
396 {
397 	struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
398 	pm860x_irqs[data->irq - chip->irq_base].enable
399 		= pm860x_irqs[data->irq - chip->irq_base].offs;
400 }
401 
402 static void pm860x_irq_disable(struct irq_data *data)
403 {
404 	struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
405 	pm860x_irqs[data->irq - chip->irq_base].enable = 0;
406 }
407 
408 static struct irq_chip pm860x_irq_chip = {
409 	.name		= "88pm860x",
410 	.irq_bus_lock	= pm860x_irq_lock,
411 	.irq_bus_sync_unlock = pm860x_irq_sync_unlock,
412 	.irq_enable	= pm860x_irq_enable,
413 	.irq_disable	= pm860x_irq_disable,
414 };
415 
416 static int __devinit device_gpadc_init(struct pm860x_chip *chip,
417 				       struct pm860x_platform_data *pdata)
418 {
419 	struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \
420 				: chip->companion;
421 	int data;
422 	int ret;
423 
424 	/* initialize GPADC without activating it */
425 
426 	if (!pdata || !pdata->touch)
427 		return -EINVAL;
428 
429 	/* set GPADC MISC1 register */
430 	data = 0;
431 	data |= (pdata->touch->gpadc_prebias << 1) & PM8607_GPADC_PREBIAS_MASK;
432 	data |= (pdata->touch->slot_cycle << 3) & PM8607_GPADC_SLOT_CYCLE_MASK;
433 	data |= (pdata->touch->off_scale << 5) & PM8607_GPADC_OFF_SCALE_MASK;
434 	data |= (pdata->touch->sw_cal << 7) & PM8607_GPADC_SW_CAL_MASK;
435 	if (data) {
436 		ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data);
437 		if (ret < 0)
438 			goto out;
439 	}
440 	/* set tsi prebias time */
441 	if (pdata->touch->tsi_prebias) {
442 		data = pdata->touch->tsi_prebias;
443 		ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data);
444 		if (ret < 0)
445 			goto out;
446 	}
447 	/* set prebias & prechg time of pen detect */
448 	data = 0;
449 	data |= pdata->touch->pen_prebias & PM8607_PD_PREBIAS_MASK;
450 	data |= (pdata->touch->pen_prechg << 5) & PM8607_PD_PRECHG_MASK;
451 	if (data) {
452 		ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data);
453 		if (ret < 0)
454 			goto out;
455 	}
456 
457 	ret = pm860x_set_bits(i2c, PM8607_GPADC_MISC1,
458 			      PM8607_GPADC_EN, PM8607_GPADC_EN);
459 out:
460 	return ret;
461 }
462 
463 static int __devinit device_irq_init(struct pm860x_chip *chip,
464 				     struct pm860x_platform_data *pdata)
465 {
466 	struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \
467 				: chip->companion;
468 	unsigned char status_buf[INT_STATUS_NUM];
469 	unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
470 	int i, data, mask, ret = -EINVAL;
471 	int __irq;
472 
473 	if (!pdata || !pdata->irq_base) {
474 		dev_warn(chip->dev, "No interrupt support on IRQ base\n");
475 		return -EINVAL;
476 	}
477 
478 	mask = PM8607_B0_MISC1_INV_INT | PM8607_B0_MISC1_INT_CLEAR
479 		| PM8607_B0_MISC1_INT_MASK;
480 	data = 0;
481 	chip->irq_mode = 0;
482 	if (pdata && pdata->irq_mode) {
483 		/*
484 		 * irq_mode defines the way of clearing interrupt. If it's 1,
485 		 * clear IRQ by write. Otherwise, clear it by read.
486 		 * This control bit is valid from 88PM8607 B0 steping.
487 		 */
488 		data |= PM8607_B0_MISC1_INT_CLEAR;
489 		chip->irq_mode = 1;
490 	}
491 	ret = pm860x_set_bits(i2c, PM8607_B0_MISC1, mask, data);
492 	if (ret < 0)
493 		goto out;
494 
495 	/* mask all IRQs */
496 	memset(status_buf, 0, INT_STATUS_NUM);
497 	ret = pm860x_bulk_write(i2c, PM8607_INT_MASK_1,
498 				INT_STATUS_NUM, status_buf);
499 	if (ret < 0)
500 		goto out;
501 
502 	if (chip->irq_mode) {
503 		/* clear interrupt status by write */
504 		memset(status_buf, 0xFF, INT_STATUS_NUM);
505 		ret = pm860x_bulk_write(i2c, PM8607_INT_STATUS1,
506 					INT_STATUS_NUM, status_buf);
507 	} else {
508 		/* clear interrupt status by read */
509 		ret = pm860x_bulk_read(i2c, PM8607_INT_STATUS1,
510 					INT_STATUS_NUM, status_buf);
511 	}
512 	if (ret < 0)
513 		goto out;
514 
515 	mutex_init(&chip->irq_lock);
516 	chip->irq_base = pdata->irq_base;
517 	chip->core_irq = i2c->irq;
518 	if (!chip->core_irq)
519 		goto out;
520 
521 	/* register IRQ by genirq */
522 	for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) {
523 		__irq = i + chip->irq_base;
524 		irq_set_chip_data(__irq, chip);
525 		irq_set_chip_and_handler(__irq, &pm860x_irq_chip,
526 					 handle_edge_irq);
527 		irq_set_nested_thread(__irq, 1);
528 #ifdef CONFIG_ARM
529 		set_irq_flags(__irq, IRQF_VALID);
530 #else
531 		irq_set_noprobe(__irq);
532 #endif
533 	}
534 
535 	ret = request_threaded_irq(chip->core_irq, NULL, pm860x_irq, flags,
536 				   "88pm860x", chip);
537 	if (ret) {
538 		dev_err(chip->dev, "Failed to request IRQ: %d\n", ret);
539 		chip->core_irq = 0;
540 	}
541 
542 	return 0;
543 out:
544 	chip->core_irq = 0;
545 	return ret;
546 }
547 
548 static void device_irq_exit(struct pm860x_chip *chip)
549 {
550 	if (chip->core_irq)
551 		free_irq(chip->core_irq, chip);
552 }
553 
554 int pm8606_osc_enable(struct pm860x_chip *chip, unsigned short client)
555 {
556 	int ret = -EIO;
557 	struct i2c_client *i2c = (chip->id == CHIP_PM8606) ?
558 		chip->client : chip->companion;
559 
560 	dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client);
561 	dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n",
562 			__func__, chip->osc_vote,
563 			chip->osc_status);
564 
565 	mutex_lock(&chip->osc_lock);
566 	/* Update voting status */
567 	chip->osc_vote |= client;
568 	/* If reference group is off - turn on*/
569 	if (chip->osc_status != PM8606_REF_GP_OSC_ON) {
570 		chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN;
571 		/* Enable Reference group Vsys */
572 		if (pm860x_set_bits(i2c, PM8606_VSYS,
573 				PM8606_VSYS_EN, PM8606_VSYS_EN))
574 			goto out;
575 
576 		/*Enable Internal Oscillator */
577 		if (pm860x_set_bits(i2c, PM8606_MISC,
578 				PM8606_MISC_OSC_EN, PM8606_MISC_OSC_EN))
579 			goto out;
580 		/* Update status (only if writes succeed) */
581 		chip->osc_status = PM8606_REF_GP_OSC_ON;
582 	}
583 	mutex_unlock(&chip->osc_lock);
584 
585 	dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n",
586 			__func__, chip->osc_vote,
587 			chip->osc_status, ret);
588 	return 0;
589 out:
590 	mutex_unlock(&chip->osc_lock);
591 	return ret;
592 }
593 EXPORT_SYMBOL(pm8606_osc_enable);
594 
595 int pm8606_osc_disable(struct pm860x_chip *chip, unsigned short client)
596 {
597 	int ret = -EIO;
598 	struct i2c_client *i2c = (chip->id == CHIP_PM8606) ?
599 		chip->client : chip->companion;
600 
601 	dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client);
602 	dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n",
603 			__func__, chip->osc_vote,
604 			chip->osc_status);
605 
606 	mutex_lock(&chip->osc_lock);
607 	/*Update voting status */
608 	chip->osc_vote &= ~(client);
609 	/* If reference group is off and this is the last client to release
610 	 * - turn off */
611 	if ((chip->osc_status != PM8606_REF_GP_OSC_OFF) &&
612 			(chip->osc_vote == REF_GP_NO_CLIENTS)) {
613 		chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN;
614 		/* Disable Reference group Vsys */
615 		if (pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0))
616 			goto out;
617 		/* Disable Internal Oscillator */
618 		if (pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0))
619 			goto out;
620 		chip->osc_status = PM8606_REF_GP_OSC_OFF;
621 	}
622 	mutex_unlock(&chip->osc_lock);
623 
624 	dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n",
625 			__func__, chip->osc_vote,
626 			chip->osc_status, ret);
627 	return 0;
628 out:
629 	mutex_unlock(&chip->osc_lock);
630 	return ret;
631 }
632 EXPORT_SYMBOL(pm8606_osc_disable);
633 
634 static void __devinit device_osc_init(struct i2c_client *i2c)
635 {
636 	struct pm860x_chip *chip = i2c_get_clientdata(i2c);
637 
638 	mutex_init(&chip->osc_lock);
639 	/* init portofino reference group voting and status */
640 	/* Disable Reference group Vsys */
641 	pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0);
642 	/* Disable Internal Oscillator */
643 	pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0);
644 
645 	chip->osc_vote = REF_GP_NO_CLIENTS;
646 	chip->osc_status = PM8606_REF_GP_OSC_OFF;
647 }
648 
649 static void __devinit device_bk_init(struct pm860x_chip *chip,
650 				     struct pm860x_platform_data *pdata)
651 {
652 	int ret;
653 	int i, j, id;
654 
655 	if ((pdata == NULL) || (pdata->backlight == NULL))
656 		return;
657 
658 	if (pdata->num_backlights > ARRAY_SIZE(bk_devs))
659 		pdata->num_backlights = ARRAY_SIZE(bk_devs);
660 
661 	for (i = 0; i < pdata->num_backlights; i++) {
662 		bk_devs[i].platform_data = &pdata->backlight[i];
663 		bk_devs[i].pdata_size = sizeof(struct pm860x_backlight_pdata);
664 
665 		for (j = 0; j < ARRAY_SIZE(bk_devs); j++) {
666 			id = bk_resources[j].start;
667 			if (pdata->backlight[i].flags != id)
668 				continue;
669 
670 			bk_devs[i].num_resources = 1;
671 			bk_devs[i].resources = &bk_resources[j];
672 			ret = mfd_add_devices(chip->dev, 0,
673 					      &bk_devs[i], 1,
674 					      &bk_resources[j], 0);
675 			if (ret < 0) {
676 				dev_err(chip->dev, "Failed to add "
677 					"backlight subdev\n");
678 				return;
679 			}
680 		}
681 	}
682 }
683 
684 static void __devinit device_led_init(struct pm860x_chip *chip,
685 				      struct pm860x_platform_data *pdata)
686 {
687 	int ret;
688 	int i, j, id;
689 
690 	if ((pdata == NULL) || (pdata->led == NULL))
691 		return;
692 
693 	if (pdata->num_leds > ARRAY_SIZE(led_devs))
694 		pdata->num_leds = ARRAY_SIZE(led_devs);
695 
696 	for (i = 0; i < pdata->num_leds; i++) {
697 		led_devs[i].platform_data = &pdata->led[i];
698 		led_devs[i].pdata_size = sizeof(struct pm860x_led_pdata);
699 
700 		for (j = 0; j < ARRAY_SIZE(led_devs); j++) {
701 			id = led_resources[j].start;
702 			if (pdata->led[i].flags != id)
703 				continue;
704 
705 			led_devs[i].num_resources = 1;
706 			led_devs[i].resources = &led_resources[j],
707 			ret = mfd_add_devices(chip->dev, 0,
708 					      &led_devs[i], 1,
709 					      &led_resources[j], 0);
710 			if (ret < 0) {
711 				dev_err(chip->dev, "Failed to add "
712 					"led subdev\n");
713 				return;
714 			}
715 		}
716 	}
717 }
718 
719 static void __devinit device_regulator_init(struct pm860x_chip *chip,
720 					    struct pm860x_platform_data *pdata)
721 {
722 	struct regulator_init_data *initdata;
723 	int ret;
724 	int i, seq;
725 
726 	if ((pdata == NULL) || (pdata->regulator == NULL))
727 		return;
728 
729 	if (pdata->num_regulators > ARRAY_SIZE(regulator_devs))
730 		pdata->num_regulators = ARRAY_SIZE(regulator_devs);
731 
732 	for (i = 0, seq = -1; i < pdata->num_regulators; i++) {
733 		initdata = &pdata->regulator[i];
734 		seq = *(unsigned int *)initdata->driver_data;
735 		if ((seq < 0) || (seq > PM8607_ID_RG_MAX)) {
736 			dev_err(chip->dev, "Wrong ID(%d) on regulator(%s)\n",
737 				seq, initdata->constraints.name);
738 			goto out;
739 		}
740 		regulator_devs[i].platform_data = &pdata->regulator[i];
741 		regulator_devs[i].pdata_size = sizeof(struct regulator_init_data);
742 		regulator_devs[i].num_resources = 1;
743 		regulator_devs[i].resources = &regulator_resources[seq];
744 
745 		ret = mfd_add_devices(chip->dev, 0, &regulator_devs[i], 1,
746 				      &regulator_resources[seq], 0);
747 		if (ret < 0) {
748 			dev_err(chip->dev, "Failed to add regulator subdev\n");
749 			goto out;
750 		}
751 	}
752 out:
753 	return;
754 }
755 
756 static void __devinit device_rtc_init(struct pm860x_chip *chip,
757 				      struct pm860x_platform_data *pdata)
758 {
759 	int ret;
760 
761 	if ((pdata == NULL))
762 		return;
763 
764 	rtc_devs[0].platform_data = pdata->rtc;
765 	rtc_devs[0].pdata_size = sizeof(struct pm860x_rtc_pdata);
766 	rtc_devs[0].num_resources = ARRAY_SIZE(rtc_resources);
767 	rtc_devs[0].resources = &rtc_resources[0];
768 	ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
769 			      ARRAY_SIZE(rtc_devs), &rtc_resources[0],
770 			      chip->irq_base);
771 	if (ret < 0)
772 		dev_err(chip->dev, "Failed to add rtc subdev\n");
773 }
774 
775 static void __devinit device_touch_init(struct pm860x_chip *chip,
776 					struct pm860x_platform_data *pdata)
777 {
778 	int ret;
779 
780 	if (pdata == NULL)
781 		return;
782 
783 	touch_devs[0].platform_data = pdata->touch;
784 	touch_devs[0].pdata_size = sizeof(struct pm860x_touch_pdata);
785 	touch_devs[0].num_resources = ARRAY_SIZE(touch_resources);
786 	touch_devs[0].resources = &touch_resources[0];
787 	ret = mfd_add_devices(chip->dev, 0, &touch_devs[0],
788 			      ARRAY_SIZE(touch_devs), &touch_resources[0],
789 			      chip->irq_base);
790 	if (ret < 0)
791 		dev_err(chip->dev, "Failed to add touch subdev\n");
792 }
793 
794 static void __devinit device_power_init(struct pm860x_chip *chip,
795 					struct pm860x_platform_data *pdata)
796 {
797 	int ret;
798 
799 	if (pdata == NULL)
800 		return;
801 
802 	power_devs[0].platform_data = pdata->power;
803 	power_devs[0].pdata_size = sizeof(struct pm860x_power_pdata);
804 	power_devs[0].num_resources = ARRAY_SIZE(battery_resources);
805 	power_devs[0].resources = &battery_resources[0],
806 	ret = mfd_add_devices(chip->dev, 0, &power_devs[0], 1,
807 			      &battery_resources[0], chip->irq_base);
808 	if (ret < 0)
809 		dev_err(chip->dev, "Failed to add battery subdev\n");
810 
811 	power_devs[1].platform_data = pdata->power;
812 	power_devs[1].pdata_size = sizeof(struct pm860x_power_pdata);
813 	power_devs[1].num_resources = ARRAY_SIZE(charger_resources);
814 	power_devs[1].resources = &charger_resources[0],
815 	ret = mfd_add_devices(chip->dev, 0, &power_devs[1], 1,
816 			      &charger_resources[0], chip->irq_base);
817 	if (ret < 0)
818 		dev_err(chip->dev, "Failed to add charger subdev\n");
819 
820 	power_devs[2].platform_data = &preg_init_data;
821 	power_devs[2].pdata_size = sizeof(struct regulator_init_data);
822 	power_devs[2].num_resources = ARRAY_SIZE(preg_resources);
823 	power_devs[2].resources = &preg_resources[0],
824 	ret = mfd_add_devices(chip->dev, 0, &power_devs[2], 1,
825 			      &preg_resources[0], chip->irq_base);
826 	if (ret < 0)
827 		dev_err(chip->dev, "Failed to add preg subdev\n");
828 }
829 
830 static void __devinit device_onkey_init(struct pm860x_chip *chip,
831 					struct pm860x_platform_data *pdata)
832 {
833 	int ret;
834 
835 	onkey_devs[0].num_resources = ARRAY_SIZE(onkey_resources);
836 	onkey_devs[0].resources = &onkey_resources[0],
837 	ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0],
838 			      ARRAY_SIZE(onkey_devs), &onkey_resources[0],
839 			      chip->irq_base);
840 	if (ret < 0)
841 		dev_err(chip->dev, "Failed to add onkey subdev\n");
842 }
843 
844 static void __devinit device_codec_init(struct pm860x_chip *chip,
845 					struct pm860x_platform_data *pdata)
846 {
847 	int ret;
848 
849 	codec_devs[0].num_resources = ARRAY_SIZE(codec_resources);
850 	codec_devs[0].resources = &codec_resources[0],
851 	ret = mfd_add_devices(chip->dev, 0, &codec_devs[0],
852 			      ARRAY_SIZE(codec_devs), &codec_resources[0], 0);
853 	if (ret < 0)
854 		dev_err(chip->dev, "Failed to add codec subdev\n");
855 }
856 
857 static void __devinit device_8607_init(struct pm860x_chip *chip,
858 				       struct i2c_client *i2c,
859 				       struct pm860x_platform_data *pdata)
860 {
861 	int data, ret;
862 
863 	ret = pm860x_reg_read(i2c, PM8607_CHIP_ID);
864 	if (ret < 0) {
865 		dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
866 		goto out;
867 	}
868 	switch (ret & PM8607_VERSION_MASK) {
869 	case 0x40:
870 	case 0x50:
871 		dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected\n",
872 			 ret);
873 		break;
874 	default:
875 		dev_err(chip->dev, "Failed to detect Marvell 88PM8607. "
876 			"Chip ID: %02x\n", ret);
877 		goto out;
878 	}
879 
880 	ret = pm860x_reg_read(i2c, PM8607_BUCK3);
881 	if (ret < 0) {
882 		dev_err(chip->dev, "Failed to read BUCK3 register: %d\n", ret);
883 		goto out;
884 	}
885 	if (ret & PM8607_BUCK3_DOUBLE)
886 		chip->buck3_double = 1;
887 
888 	ret = pm860x_reg_read(i2c, PM8607_B0_MISC1);
889 	if (ret < 0) {
890 		dev_err(chip->dev, "Failed to read MISC1 register: %d\n", ret);
891 		goto out;
892 	}
893 
894 	if (pdata && (pdata->i2c_port == PI2C_PORT))
895 		data = PM8607_B0_MISC1_PI2C;
896 	else
897 		data = 0;
898 	ret = pm860x_set_bits(i2c, PM8607_B0_MISC1, PM8607_B0_MISC1_PI2C, data);
899 	if (ret < 0) {
900 		dev_err(chip->dev, "Failed to access MISC1:%d\n", ret);
901 		goto out;
902 	}
903 
904 	ret = device_gpadc_init(chip, pdata);
905 	if (ret < 0)
906 		goto out;
907 
908 	ret = device_irq_init(chip, pdata);
909 	if (ret < 0)
910 		goto out;
911 
912 	device_regulator_init(chip, pdata);
913 	device_rtc_init(chip, pdata);
914 	device_onkey_init(chip, pdata);
915 	device_touch_init(chip, pdata);
916 	device_power_init(chip, pdata);
917 	device_codec_init(chip, pdata);
918 out:
919 	return;
920 }
921 
922 static void __devinit device_8606_init(struct pm860x_chip *chip,
923 				       struct i2c_client *i2c,
924 				       struct pm860x_platform_data *pdata)
925 {
926 	device_osc_init(i2c);
927 	device_bk_init(chip, pdata);
928 	device_led_init(chip, pdata);
929 }
930 
931 int __devinit pm860x_device_init(struct pm860x_chip *chip,
932 		       struct pm860x_platform_data *pdata)
933 {
934 	chip->core_irq = 0;
935 
936 	switch (chip->id) {
937 	case CHIP_PM8606:
938 		device_8606_init(chip, chip->client, pdata);
939 		break;
940 	case CHIP_PM8607:
941 		device_8607_init(chip, chip->client, pdata);
942 		break;
943 	}
944 
945 	if (chip->companion) {
946 		switch (chip->id) {
947 		case CHIP_PM8607:
948 			device_8606_init(chip, chip->companion, pdata);
949 			break;
950 		case CHIP_PM8606:
951 			device_8607_init(chip, chip->companion, pdata);
952 			break;
953 		}
954 	}
955 
956 	return 0;
957 }
958 
959 void __devexit pm860x_device_exit(struct pm860x_chip *chip)
960 {
961 	device_irq_exit(chip);
962 	mfd_remove_devices(chip->dev);
963 }
964 
965 MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM860x");
966 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
967 MODULE_LICENSE("GPL");
968