2 * Base driver for Marvell 88PM8607
4 * Copyright (C) 2009 Marvell International Ltd.
5 * Haojian Zhuang <haojian.zhuang@marvell.com>
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.
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>
22 #define INT_STATUS_NUM 3
24 static struct resource io_parent
= {
27 .flags
= IORESOURCE_IO
,
30 static struct resource bk_resources
[] __devinitdata
= {
31 {PM8606_BACKLIGHT1
, PM8606_BACKLIGHT1
, "backlight-0", IORESOURCE_IO
,
33 {PM8606_BACKLIGHT2
, PM8606_BACKLIGHT2
, "backlight-1", IORESOURCE_IO
,
35 {PM8606_BACKLIGHT3
, PM8606_BACKLIGHT3
, "backlight-2", IORESOURCE_IO
,
39 static struct resource led_resources
[] __devinitdata
= {
40 {PM8606_LED1_RED
, PM8606_LED1_RED
, "led0-red", IORESOURCE_IO
,
42 {PM8606_LED1_GREEN
, PM8606_LED1_GREEN
, "led0-green", IORESOURCE_IO
,
44 {PM8606_LED1_BLUE
, PM8606_LED1_BLUE
, "led0-blue", IORESOURCE_IO
,
46 {PM8606_LED2_RED
, PM8606_LED2_RED
, "led1-red", IORESOURCE_IO
,
48 {PM8606_LED2_GREEN
, PM8606_LED2_GREEN
, "led1-green", IORESOURCE_IO
,
50 {PM8606_LED2_BLUE
, PM8606_LED2_BLUE
, "led1-blue", IORESOURCE_IO
,
54 static struct resource regulator_resources
[] __devinitdata
= {
55 {PM8607_ID_BUCK1
, PM8607_ID_BUCK1
, "buck-1", IORESOURCE_IO
,
57 {PM8607_ID_BUCK2
, PM8607_ID_BUCK2
, "buck-2", IORESOURCE_IO
,
59 {PM8607_ID_BUCK3
, PM8607_ID_BUCK3
, "buck-3", IORESOURCE_IO
,
61 {PM8607_ID_LDO1
, PM8607_ID_LDO1
, "ldo-01", IORESOURCE_IO
,
63 {PM8607_ID_LDO2
, PM8607_ID_LDO2
, "ldo-02", IORESOURCE_IO
,
65 {PM8607_ID_LDO3
, PM8607_ID_LDO3
, "ldo-03", IORESOURCE_IO
,
67 {PM8607_ID_LDO4
, PM8607_ID_LDO4
, "ldo-04", IORESOURCE_IO
,
69 {PM8607_ID_LDO5
, PM8607_ID_LDO5
, "ldo-05", IORESOURCE_IO
,
71 {PM8607_ID_LDO6
, PM8607_ID_LDO6
, "ldo-06", IORESOURCE_IO
,
73 {PM8607_ID_LDO7
, PM8607_ID_LDO7
, "ldo-07", IORESOURCE_IO
,
75 {PM8607_ID_LDO8
, PM8607_ID_LDO8
, "ldo-08", IORESOURCE_IO
,
77 {PM8607_ID_LDO9
, PM8607_ID_LDO9
, "ldo-09", IORESOURCE_IO
,
79 {PM8607_ID_LDO10
, PM8607_ID_LDO10
, "ldo-10", IORESOURCE_IO
,
81 {PM8607_ID_LDO11
, PM8607_ID_LDO11
, "ldo-11", IORESOURCE_IO
,
83 {PM8607_ID_LDO12
, PM8607_ID_LDO12
, "ldo-12", IORESOURCE_IO
,
85 {PM8607_ID_LDO13
, PM8607_ID_LDO13
, "ldo-13", IORESOURCE_IO
,
87 {PM8607_ID_LDO14
, PM8607_ID_LDO14
, "ldo-14", IORESOURCE_IO
,
89 {PM8607_ID_LDO15
, PM8607_ID_LDO15
, "ldo-15", IORESOURCE_IO
,
93 static struct resource touch_resources
[] __devinitdata
= {
94 {PM8607_IRQ_PEN
, PM8607_IRQ_PEN
, "touch", IORESOURCE_IRQ
,},
97 static struct resource onkey_resources
[] __devinitdata
= {
98 {PM8607_IRQ_ONKEY
, PM8607_IRQ_ONKEY
, "onkey", IORESOURCE_IRQ
,},
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
,},
109 {PM8607_IRQ_AUDIO_SHORT
, PM8607_IRQ_AUDIO_SHORT
, "audio-short", IORESOURCE_IRQ
,},
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
,},
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
,},
126 static struct resource preg_resources
[] __devinitdata
= {
127 {PM8606_ID_PREG
, PM8606_ID_PREG
, "preg", IORESOURCE_IO
,
131 static struct resource rtc_resources
[] __devinitdata
= {
132 {PM8607_IRQ_RTC
, PM8607_IRQ_RTC
, "rtc", IORESOURCE_IRQ
, &io_parent
,},
135 static struct mfd_cell bk_devs
[] = {
136 {"88pm860x-backlight", 0,},
137 {"88pm860x-backlight", 1,},
138 {"88pm860x-backlight", 2,},
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,},
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,},
171 static struct mfd_cell touch_devs
[] = {
172 {"88pm860x-touch", -1,},
175 static struct mfd_cell onkey_devs
[] = {
176 {"88pm860x-onkey", -1,},
179 static struct mfd_cell codec_devs
[] = {
180 {"88pm860x-codec", -1,},
183 static struct regulator_consumer_supply preg_supply
[] = {
184 REGULATOR_SUPPLY("preg", "charger-manager"),
187 static struct regulator_init_data preg_init_data
= {
188 .num_consumer_supplies
= ARRAY_SIZE(preg_supply
),
189 .consumer_supplies
= &preg_supply
[0],
192 static struct mfd_cell power_devs
[] = {
193 {"88pm860x-battery", -1,},
194 {"88pm860x-charger", -1,},
195 {"88pm860x-preg", -1,},
198 static struct mfd_cell rtc_devs
[] = {
199 {"88pm860x-rtc", -1,},
203 struct pm860x_irq_data
{
206 int enable
; /* enable or not */
207 int offs
; /* bit offset in mask register */
210 static struct pm860x_irq_data pm860x_irqs
[] = {
211 [PM8607_IRQ_ONKEY
] = {
212 .reg
= PM8607_INT_STATUS1
,
213 .mask_reg
= PM8607_INT_MASK_1
,
216 [PM8607_IRQ_EXTON
] = {
217 .reg
= PM8607_INT_STATUS1
,
218 .mask_reg
= PM8607_INT_MASK_1
,
222 .reg
= PM8607_INT_STATUS1
,
223 .mask_reg
= PM8607_INT_MASK_1
,
227 .reg
= PM8607_INT_STATUS1
,
228 .mask_reg
= PM8607_INT_MASK_1
,
232 .reg
= PM8607_INT_STATUS1
,
233 .mask_reg
= PM8607_INT_MASK_1
,
237 .reg
= PM8607_INT_STATUS1
,
238 .mask_reg
= PM8607_INT_MASK_1
,
241 [PM8607_IRQ_VBAT
] = {
242 .reg
= PM8607_INT_STATUS2
,
243 .mask_reg
= PM8607_INT_MASK_2
,
246 [PM8607_IRQ_VCHG
] = {
247 .reg
= PM8607_INT_STATUS2
,
248 .mask_reg
= PM8607_INT_MASK_2
,
251 [PM8607_IRQ_VSYS
] = {
252 .reg
= PM8607_INT_STATUS2
,
253 .mask_reg
= PM8607_INT_MASK_2
,
256 [PM8607_IRQ_TINT
] = {
257 .reg
= PM8607_INT_STATUS2
,
258 .mask_reg
= PM8607_INT_MASK_2
,
261 [PM8607_IRQ_GPADC0
] = {
262 .reg
= PM8607_INT_STATUS2
,
263 .mask_reg
= PM8607_INT_MASK_2
,
266 [PM8607_IRQ_GPADC1
] = {
267 .reg
= PM8607_INT_STATUS2
,
268 .mask_reg
= PM8607_INT_MASK_2
,
271 [PM8607_IRQ_GPADC2
] = {
272 .reg
= PM8607_INT_STATUS2
,
273 .mask_reg
= PM8607_INT_MASK_2
,
276 [PM8607_IRQ_GPADC3
] = {
277 .reg
= PM8607_INT_STATUS2
,
278 .mask_reg
= PM8607_INT_MASK_2
,
281 [PM8607_IRQ_AUDIO_SHORT
] = {
282 .reg
= PM8607_INT_STATUS3
,
283 .mask_reg
= PM8607_INT_MASK_3
,
287 .reg
= PM8607_INT_STATUS3
,
288 .mask_reg
= PM8607_INT_MASK_3
,
291 [PM8607_IRQ_HEADSET
] = {
292 .reg
= PM8607_INT_STATUS3
,
293 .mask_reg
= PM8607_INT_MASK_3
,
296 [PM8607_IRQ_HOOK
] = {
297 .reg
= PM8607_INT_STATUS3
,
298 .mask_reg
= PM8607_INT_MASK_3
,
301 [PM8607_IRQ_MICIN
] = {
302 .reg
= PM8607_INT_STATUS3
,
303 .mask_reg
= PM8607_INT_MASK_3
,
306 [PM8607_IRQ_CHG_FAIL
] = {
307 .reg
= PM8607_INT_STATUS3
,
308 .mask_reg
= PM8607_INT_MASK_3
,
311 [PM8607_IRQ_CHG_DONE
] = {
312 .reg
= PM8607_INT_STATUS3
,
313 .mask_reg
= PM8607_INT_MASK_3
,
316 [PM8607_IRQ_CHG_FAULT
] = {
317 .reg
= PM8607_INT_STATUS3
,
318 .mask_reg
= PM8607_INT_MASK_3
,
323 static irqreturn_t
pm860x_irq(int irq
, void *data
)
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;
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
);
338 if (value
& irq_data
->enable
)
339 handle_nested_irq(chip
->irq_base
+ i
);
344 static void pm860x_irq_lock(struct irq_data
*data
)
346 struct pm860x_chip
*chip
= irq_data_get_irq_chip_data(data
);
348 mutex_lock(&chip
->irq_lock
);
351 static void pm860x_irq_sync_unlock(struct irq_data
*data
)
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];
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
++)
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
;
371 case PM8607_INT_MASK_2
:
372 mask
[1] &= ~irq_data
->offs
;
373 mask
[1] |= irq_data
->enable
;
375 case PM8607_INT_MASK_3
:
376 mask
[2] &= ~irq_data
->offs
;
377 mask
[2] |= irq_data
->enable
;
380 dev_err(chip
->dev
, "wrong IRQ\n");
384 /* update mask into registers */
385 for (i
= 0; i
< 3; i
++) {
386 if (mask
[i
] != cached
[i
]) {
388 pm860x_reg_write(i2c
, PM8607_INT_MASK_1
+ i
, mask
[i
]);
392 mutex_unlock(&chip
->irq_lock
);
395 static void pm860x_irq_enable(struct irq_data
*data
)
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
;
402 static void pm860x_irq_disable(struct irq_data
*data
)
404 struct pm860x_chip
*chip
= irq_data_get_irq_chip_data(data
);
405 pm860x_irqs
[data
->irq
- chip
->irq_base
].enable
= 0;
408 static struct irq_chip pm860x_irq_chip
= {
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
,
416 static int __devinit
device_gpadc_init(struct pm860x_chip
*chip
,
417 struct pm860x_platform_data
*pdata
)
419 struct i2c_client
*i2c
= (chip
->id
== CHIP_PM8607
) ? chip
->client \
424 /* initialize GPADC without activating it */
426 if (!pdata
|| !pdata
->touch
)
429 /* set GPADC MISC1 register */
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
;
436 ret
= pm860x_reg_write(i2c
, PM8607_GPADC_MISC1
, data
);
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
);
447 /* set prebias & prechg time of pen detect */
449 data
|= pdata
->touch
->pen_prebias
& PM8607_PD_PREBIAS_MASK
;
450 data
|= (pdata
->touch
->pen_prechg
<< 5) & PM8607_PD_PRECHG_MASK
;
452 ret
= pm860x_reg_write(i2c
, PM8607_PD_PREBIAS
, data
);
457 ret
= pm860x_set_bits(i2c
, PM8607_GPADC_MISC1
,
458 PM8607_GPADC_EN
, PM8607_GPADC_EN
);
463 static int __devinit
device_irq_init(struct pm860x_chip
*chip
,
464 struct pm860x_platform_data
*pdata
)
466 struct i2c_client
*i2c
= (chip
->id
== CHIP_PM8607
) ? chip
->client \
468 unsigned char status_buf
[INT_STATUS_NUM
];
469 unsigned long flags
= IRQF_TRIGGER_FALLING
| IRQF_ONESHOT
;
470 int i
, data
, mask
, ret
= -EINVAL
;
473 if (!pdata
|| !pdata
->irq_base
) {
474 dev_warn(chip
->dev
, "No interrupt support on IRQ base\n");
478 mask
= PM8607_B0_MISC1_INV_INT
| PM8607_B0_MISC1_INT_CLEAR
479 | PM8607_B0_MISC1_INT_MASK
;
482 if (pdata
&& pdata
->irq_mode
) {
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.
488 data
|= PM8607_B0_MISC1_INT_CLEAR
;
491 ret
= pm860x_set_bits(i2c
, PM8607_B0_MISC1
, mask
, data
);
496 memset(status_buf
, 0, INT_STATUS_NUM
);
497 ret
= pm860x_bulk_write(i2c
, PM8607_INT_MASK_1
,
498 INT_STATUS_NUM
, status_buf
);
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
);
508 /* clear interrupt status by read */
509 ret
= pm860x_bulk_read(i2c
, PM8607_INT_STATUS1
,
510 INT_STATUS_NUM
, status_buf
);
515 mutex_init(&chip
->irq_lock
);
516 chip
->irq_base
= pdata
->irq_base
;
517 chip
->core_irq
= i2c
->irq
;
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
,
527 irq_set_nested_thread(__irq
, 1);
529 set_irq_flags(__irq
, IRQF_VALID
);
531 irq_set_noprobe(__irq
);
535 ret
= request_threaded_irq(chip
->core_irq
, NULL
, pm860x_irq
, flags
,
538 dev_err(chip
->dev
, "Failed to request IRQ: %d\n", ret
);
548 static void device_irq_exit(struct pm860x_chip
*chip
)
551 free_irq(chip
->core_irq
, chip
);
554 int pm8606_osc_enable(struct pm860x_chip
*chip
, unsigned short client
)
557 struct i2c_client
*i2c
= (chip
->id
== CHIP_PM8606
) ?
558 chip
->client
: chip
->companion
;
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
,
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
))
576 /*Enable Internal Oscillator */
577 if (pm860x_set_bits(i2c
, PM8606_MISC
,
578 PM8606_MISC_OSC_EN
, PM8606_MISC_OSC_EN
))
580 /* Update status (only if writes succeed) */
581 chip
->osc_status
= PM8606_REF_GP_OSC_ON
;
583 mutex_unlock(&chip
->osc_lock
);
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
);
590 mutex_unlock(&chip
->osc_lock
);
593 EXPORT_SYMBOL(pm8606_osc_enable
);
595 int pm8606_osc_disable(struct pm860x_chip
*chip
, unsigned short client
)
598 struct i2c_client
*i2c
= (chip
->id
== CHIP_PM8606
) ?
599 chip
->client
: chip
->companion
;
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
,
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
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))
617 /* Disable Internal Oscillator */
618 if (pm860x_set_bits(i2c
, PM8606_MISC
, PM8606_MISC_OSC_EN
, 0))
620 chip
->osc_status
= PM8606_REF_GP_OSC_OFF
;
622 mutex_unlock(&chip
->osc_lock
);
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
);
629 mutex_unlock(&chip
->osc_lock
);
632 EXPORT_SYMBOL(pm8606_osc_disable
);
634 static void __devinit
device_osc_init(struct i2c_client
*i2c
)
636 struct pm860x_chip
*chip
= i2c_get_clientdata(i2c
);
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);
645 chip
->osc_vote
= REF_GP_NO_CLIENTS
;
646 chip
->osc_status
= PM8606_REF_GP_OSC_OFF
;
649 static void __devinit
device_bk_init(struct pm860x_chip
*chip
,
650 struct pm860x_platform_data
*pdata
)
655 if ((pdata
== NULL
) || (pdata
->backlight
== NULL
))
658 if (pdata
->num_backlights
> ARRAY_SIZE(bk_devs
))
659 pdata
->num_backlights
= ARRAY_SIZE(bk_devs
);
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
);
665 for (j
= 0; j
< ARRAY_SIZE(bk_devs
); j
++) {
666 id
= bk_resources
[j
].start
;
667 if (pdata
->backlight
[i
].flags
!= id
)
670 bk_devs
[i
].num_resources
= 1;
671 bk_devs
[i
].resources
= &bk_resources
[j
];
672 ret
= mfd_add_devices(chip
->dev
, 0,
674 &bk_resources
[j
], 0, NULL
);
676 dev_err(chip
->dev
, "Failed to add "
677 "backlight subdev\n");
684 static void __devinit
device_led_init(struct pm860x_chip
*chip
,
685 struct pm860x_platform_data
*pdata
)
690 if ((pdata
== NULL
) || (pdata
->led
== NULL
))
693 if (pdata
->num_leds
> ARRAY_SIZE(led_devs
))
694 pdata
->num_leds
= ARRAY_SIZE(led_devs
);
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
);
700 for (j
= 0; j
< ARRAY_SIZE(led_devs
); j
++) {
701 id
= led_resources
[j
].start
;
702 if (pdata
->led
[i
].flags
!= id
)
705 led_devs
[i
].num_resources
= 1;
706 led_devs
[i
].resources
= &led_resources
[j
],
707 ret
= mfd_add_devices(chip
->dev
, 0,
709 &led_resources
[j
], 0, NULL
);
711 dev_err(chip
->dev
, "Failed to add "
719 static void __devinit
device_regulator_init(struct pm860x_chip
*chip
,
720 struct pm860x_platform_data
*pdata
)
722 struct regulator_init_data
*initdata
;
726 if ((pdata
== NULL
) || (pdata
->regulator
== NULL
))
729 if (pdata
->num_regulators
> ARRAY_SIZE(regulator_devs
))
730 pdata
->num_regulators
= ARRAY_SIZE(regulator_devs
);
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
);
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
= ®ulator_resources
[seq
];
745 ret
= mfd_add_devices(chip
->dev
, 0, ®ulator_devs
[i
], 1,
746 ®ulator_resources
[seq
], 0, NULL
);
748 dev_err(chip
->dev
, "Failed to add regulator subdev\n");
756 static void __devinit
device_rtc_init(struct pm860x_chip
*chip
,
757 struct pm860x_platform_data
*pdata
)
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
, NULL
);
772 dev_err(chip
->dev
, "Failed to add rtc subdev\n");
775 static void __devinit
device_touch_init(struct pm860x_chip
*chip
,
776 struct pm860x_platform_data
*pdata
)
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
, NULL
);
791 dev_err(chip
->dev
, "Failed to add touch subdev\n");
794 static void __devinit
device_power_init(struct pm860x_chip
*chip
,
795 struct pm860x_platform_data
*pdata
)
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
, NULL
);
809 dev_err(chip
->dev
, "Failed to add battery subdev\n");
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
, NULL
);
818 dev_err(chip
->dev
, "Failed to add charger subdev\n");
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
, NULL
);
827 dev_err(chip
->dev
, "Failed to add preg subdev\n");
830 static void __devinit
device_onkey_init(struct pm860x_chip
*chip
,
831 struct pm860x_platform_data
*pdata
)
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
, NULL
);
841 dev_err(chip
->dev
, "Failed to add onkey subdev\n");
844 static void __devinit
device_codec_init(struct pm860x_chip
*chip
,
845 struct pm860x_platform_data
*pdata
)
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,
855 dev_err(chip
->dev
, "Failed to add codec subdev\n");
858 static void __devinit
device_8607_init(struct pm860x_chip
*chip
,
859 struct i2c_client
*i2c
,
860 struct pm860x_platform_data
*pdata
)
864 ret
= pm860x_reg_read(i2c
, PM8607_CHIP_ID
);
866 dev_err(chip
->dev
, "Failed to read CHIP ID: %d\n", ret
);
869 switch (ret
& PM8607_VERSION_MASK
) {
872 dev_info(chip
->dev
, "Marvell 88PM8607 (ID: %02x) detected\n",
876 dev_err(chip
->dev
, "Failed to detect Marvell 88PM8607. "
877 "Chip ID: %02x\n", ret
);
881 ret
= pm860x_reg_read(i2c
, PM8607_BUCK3
);
883 dev_err(chip
->dev
, "Failed to read BUCK3 register: %d\n", ret
);
886 if (ret
& PM8607_BUCK3_DOUBLE
)
887 chip
->buck3_double
= 1;
889 ret
= pm860x_reg_read(i2c
, PM8607_B0_MISC1
);
891 dev_err(chip
->dev
, "Failed to read MISC1 register: %d\n", ret
);
895 if (pdata
&& (pdata
->i2c_port
== PI2C_PORT
))
896 data
= PM8607_B0_MISC1_PI2C
;
899 ret
= pm860x_set_bits(i2c
, PM8607_B0_MISC1
, PM8607_B0_MISC1_PI2C
, data
);
901 dev_err(chip
->dev
, "Failed to access MISC1:%d\n", ret
);
905 ret
= device_gpadc_init(chip
, pdata
);
909 ret
= device_irq_init(chip
, pdata
);
913 device_regulator_init(chip
, pdata
);
914 device_rtc_init(chip
, pdata
);
915 device_onkey_init(chip
, pdata
);
916 device_touch_init(chip
, pdata
);
917 device_power_init(chip
, pdata
);
918 device_codec_init(chip
, pdata
);
923 static void __devinit
device_8606_init(struct pm860x_chip
*chip
,
924 struct i2c_client
*i2c
,
925 struct pm860x_platform_data
*pdata
)
927 device_osc_init(i2c
);
928 device_bk_init(chip
, pdata
);
929 device_led_init(chip
, pdata
);
932 int __devinit
pm860x_device_init(struct pm860x_chip
*chip
,
933 struct pm860x_platform_data
*pdata
)
939 device_8606_init(chip
, chip
->client
, pdata
);
942 device_8607_init(chip
, chip
->client
, pdata
);
946 if (chip
->companion
) {
949 device_8606_init(chip
, chip
->companion
, pdata
);
952 device_8607_init(chip
, chip
->companion
, pdata
);
960 void __devexit
pm860x_device_exit(struct pm860x_chip
*chip
)
962 device_irq_exit(chip
);
963 mfd_remove_devices(chip
->dev
);
966 MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM860x");
967 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
968 MODULE_LICENSE("GPL");