diff options
-rw-r--r-- | drivers/mfd/88pm860x-core.c | 95 | ||||
-rw-r--r-- | include/linux/mfd/88pm860x.h | 22 |
2 files changed, 117 insertions, 0 deletions
diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 17dfe9bb6d27..78c3a9e1fa1e 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c | |||
@@ -503,6 +503,99 @@ static void device_irq_exit(struct pm860x_chip *chip) | |||
503 | free_irq(chip->core_irq, chip); | 503 | free_irq(chip->core_irq, chip); |
504 | } | 504 | } |
505 | 505 | ||
506 | int pm8606_osc_enable(struct pm860x_chip *chip, unsigned short client) | ||
507 | { | ||
508 | int ret = -EIO; | ||
509 | struct i2c_client *i2c = (chip->id == CHIP_PM8606) ? | ||
510 | chip->client : chip->companion; | ||
511 | |||
512 | dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client); | ||
513 | dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n", | ||
514 | __func__, chip->osc_vote, | ||
515 | chip->osc_status); | ||
516 | |||
517 | mutex_lock(&chip->osc_lock); | ||
518 | /* Update voting status */ | ||
519 | chip->osc_vote |= client; | ||
520 | /* If reference group is off - turn on*/ | ||
521 | if (chip->osc_status != PM8606_REF_GP_OSC_ON) { | ||
522 | chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN; | ||
523 | /* Enable Reference group Vsys */ | ||
524 | if (pm860x_set_bits(i2c, PM8606_VSYS, | ||
525 | PM8606_VSYS_EN, PM8606_VSYS_EN)) | ||
526 | goto out; | ||
527 | |||
528 | /*Enable Internal Oscillator */ | ||
529 | if (pm860x_set_bits(i2c, PM8606_MISC, | ||
530 | PM8606_MISC_OSC_EN, PM8606_MISC_OSC_EN)) | ||
531 | goto out; | ||
532 | /* Update status (only if writes succeed) */ | ||
533 | chip->osc_status = PM8606_REF_GP_OSC_ON; | ||
534 | } | ||
535 | mutex_unlock(&chip->osc_lock); | ||
536 | |||
537 | dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n", | ||
538 | __func__, chip->osc_vote, | ||
539 | chip->osc_status, ret); | ||
540 | return 0; | ||
541 | out: | ||
542 | mutex_unlock(&chip->osc_lock); | ||
543 | return ret; | ||
544 | } | ||
545 | |||
546 | int pm8606_osc_disable(struct pm860x_chip *chip, unsigned short client) | ||
547 | { | ||
548 | int ret = -EIO; | ||
549 | struct i2c_client *i2c = (chip->id == CHIP_PM8606) ? | ||
550 | chip->client : chip->companion; | ||
551 | |||
552 | dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client); | ||
553 | dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n", | ||
554 | __func__, chip->osc_vote, | ||
555 | chip->osc_status); | ||
556 | |||
557 | mutex_lock(&chip->osc_lock); | ||
558 | /*Update voting status */ | ||
559 | chip->osc_vote &= ~(client); | ||
560 | /* If reference group is off and this is the last client to release | ||
561 | * - turn off */ | ||
562 | if ((chip->osc_status != PM8606_REF_GP_OSC_OFF) && | ||
563 | (chip->osc_vote == REF_GP_NO_CLIENTS)) { | ||
564 | chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN; | ||
565 | /* Disable Reference group Vsys */ | ||
566 | if (pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0)) | ||
567 | goto out; | ||
568 | /* Disable Internal Oscillator */ | ||
569 | if (pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0)) | ||
570 | goto out; | ||
571 | chip->osc_status = PM8606_REF_GP_OSC_OFF; | ||
572 | } | ||
573 | mutex_unlock(&chip->osc_lock); | ||
574 | |||
575 | dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n", | ||
576 | __func__, chip->osc_vote, | ||
577 | chip->osc_status, ret); | ||
578 | return 0; | ||
579 | out: | ||
580 | mutex_unlock(&chip->osc_lock); | ||
581 | return ret; | ||
582 | } | ||
583 | |||
584 | static void __devinit device_osc_init(struct i2c_client *i2c) | ||
585 | { | ||
586 | struct pm860x_chip *chip = i2c_get_clientdata(i2c); | ||
587 | |||
588 | mutex_init(&chip->osc_lock); | ||
589 | /* init portofino reference group voting and status */ | ||
590 | /* Disable Reference group Vsys */ | ||
591 | pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0); | ||
592 | /* Disable Internal Oscillator */ | ||
593 | pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0); | ||
594 | |||
595 | chip->osc_vote = REF_GP_NO_CLIENTS; | ||
596 | chip->osc_status = PM8606_REF_GP_OSC_OFF; | ||
597 | } | ||
598 | |||
506 | static void __devinit device_bk_init(struct pm860x_chip *chip, | 599 | static void __devinit device_bk_init(struct pm860x_chip *chip, |
507 | struct pm860x_platform_data *pdata) | 600 | struct pm860x_platform_data *pdata) |
508 | { | 601 | { |
@@ -774,6 +867,7 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip, | |||
774 | 867 | ||
775 | switch (chip->id) { | 868 | switch (chip->id) { |
776 | case CHIP_PM8606: | 869 | case CHIP_PM8606: |
870 | device_osc_init(chip->client); | ||
777 | device_bk_init(chip, pdata); | 871 | device_bk_init(chip, pdata); |
778 | device_led_init(chip, pdata); | 872 | device_led_init(chip, pdata); |
779 | break; | 873 | break; |
@@ -785,6 +879,7 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip, | |||
785 | if (chip->companion) { | 879 | if (chip->companion) { |
786 | switch (chip->id) { | 880 | switch (chip->id) { |
787 | case CHIP_PM8607: | 881 | case CHIP_PM8607: |
882 | device_osc_init(chip->companion); | ||
788 | device_bk_init(chip, pdata); | 883 | device_bk_init(chip, pdata); |
789 | device_led_init(chip, pdata); | 884 | device_led_init(chip, pdata); |
790 | break; | 885 | break; |
diff --git a/include/linux/mfd/88pm860x.h b/include/linux/mfd/88pm860x.h index 8b583f3f7926..84d071ade1d8 100644 --- a/include/linux/mfd/88pm860x.h +++ b/include/linux/mfd/88pm860x.h | |||
@@ -263,6 +263,22 @@ enum { | |||
263 | #define PM8607_PD_PREBIAS_MASK (0x1F << 0) | 263 | #define PM8607_PD_PREBIAS_MASK (0x1F << 0) |
264 | #define PM8607_PD_PRECHG_MASK (7 << 5) | 264 | #define PM8607_PD_PRECHG_MASK (7 << 5) |
265 | 265 | ||
266 | #define PM8606_REF_GP_OSC_OFF 0 | ||
267 | #define PM8606_REF_GP_OSC_ON 1 | ||
268 | #define PM8606_REF_GP_OSC_UNKNOWN 2 | ||
269 | |||
270 | /* Clients of reference group and 8MHz oscillator in 88PM8606 */ | ||
271 | enum pm8606_ref_gp_and_osc_clients { | ||
272 | REF_GP_NO_CLIENTS = 0, | ||
273 | WLED1_DUTY = (1<<0), /*PF 0x02.7:0*/ | ||
274 | WLED2_DUTY = (1<<1), /*PF 0x04.7:0*/ | ||
275 | WLED3_DUTY = (1<<2), /*PF 0x06.7:0*/ | ||
276 | RGB1_ENABLE = (1<<3), /*PF 0x07.1*/ | ||
277 | RGB2_ENABLE = (1<<4), /*PF 0x07.2*/ | ||
278 | LDO_VBR_EN = (1<<5), /*PF 0x12.0*/ | ||
279 | REF_GP_MAX_CLIENT = 0xFFFF | ||
280 | }; | ||
281 | |||
266 | /* Interrupt Number in 88PM8607 */ | 282 | /* Interrupt Number in 88PM8607 */ |
267 | enum { | 283 | enum { |
268 | PM8607_IRQ_ONKEY, | 284 | PM8607_IRQ_ONKEY, |
@@ -298,6 +314,7 @@ enum { | |||
298 | struct pm860x_chip { | 314 | struct pm860x_chip { |
299 | struct device *dev; | 315 | struct device *dev; |
300 | struct mutex irq_lock; | 316 | struct mutex irq_lock; |
317 | struct mutex osc_lock; | ||
301 | struct i2c_client *client; | 318 | struct i2c_client *client; |
302 | struct i2c_client *companion; /* companion chip client */ | 319 | struct i2c_client *companion; /* companion chip client */ |
303 | struct regmap *regmap; | 320 | struct regmap *regmap; |
@@ -305,11 +322,13 @@ struct pm860x_chip { | |||
305 | 322 | ||
306 | int buck3_double; /* DVC ramp slope double */ | 323 | int buck3_double; /* DVC ramp slope double */ |
307 | unsigned short companion_addr; | 324 | unsigned short companion_addr; |
325 | unsigned short osc_vote; | ||
308 | int id; | 326 | int id; |
309 | int irq_mode; | 327 | int irq_mode; |
310 | int irq_base; | 328 | int irq_base; |
311 | int core_irq; | 329 | int core_irq; |
312 | unsigned char chip_version; | 330 | unsigned char chip_version; |
331 | unsigned char osc_status; | ||
313 | 332 | ||
314 | unsigned int wakeup_flag; | 333 | unsigned int wakeup_flag; |
315 | }; | 334 | }; |
@@ -370,6 +389,9 @@ struct pm860x_platform_data { | |||
370 | int num_regulators; | 389 | int num_regulators; |
371 | }; | 390 | }; |
372 | 391 | ||
392 | extern int pm8606_osc_enable(struct pm860x_chip *, unsigned short); | ||
393 | extern int pm8606_osc_disable(struct pm860x_chip *, unsigned short); | ||
394 | |||
373 | extern int pm860x_reg_read(struct i2c_client *, int); | 395 | extern int pm860x_reg_read(struct i2c_client *, int); |
374 | extern int pm860x_reg_write(struct i2c_client *, int, unsigned char); | 396 | extern int pm860x_reg_write(struct i2c_client *, int, unsigned char); |
375 | extern int pm860x_bulk_read(struct i2c_client *, int, int, unsigned char *); | 397 | extern int pm860x_bulk_read(struct i2c_client *, int, int, unsigned char *); |