diff options
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/88pm860x-core.c | 95 |
1 files changed, 95 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; |