aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
authorJett.Zhou <jtzhou@marvell.com>2012-03-01 05:59:19 -0500
committerSamuel Ortiz <sameo@linux.intel.com>2012-03-06 12:46:52 -0500
commit23de435a59b37eda468472ac67179eee5ef10a07 (patch)
treed0659611c578e0ae4779da35000ad510f1e426ba /drivers/mfd
parentfe2afaa5412126f7a41aec811228a1f439d232a0 (diff)
mfd: Add power control interface for pm8606 chip
The reference group and internal oscillator are shared by sub-devs like led, backlight and vibrator in PM8606 chip. Now introduce a voting mechanism to enable/disable it. Add pm8606_osc_enable() and pm8606_osc_disable() interface and related defines to support this. This interface will be called by vibrator led and backlight driver.The refernce group and internal oscillator are enabled only when at least one of it's clients holds it on or disabled only all the clients don't use it any more based on the above mechanism. Signed-off-by: Jett.Zhou <jtzhou@marvell.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/88pm860x-core.c95
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
506int 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;
541out:
542 mutex_unlock(&chip->osc_lock);
543 return ret;
544}
545
546int 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;
579out:
580 mutex_unlock(&chip->osc_lock);
581 return ret;
582}
583
584static 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
506static void __devinit device_bk_init(struct pm860x_chip *chip, 599static 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;