X-Git-Url: https://git.karo-electronics.de/?a=blobdiff_plain;f=drivers%2Fmfd%2F88pm860x-core.c;h=87bd5ba38d5b649db355f252d326fe28116041c0;hb=b7574a22a24c9417ae4cc416785556bad0a0a371;hp=17dfe9bb6d2745c2bb5f6123b1afbc6c6d997ca6;hpb=7b28afe01ab6ffb5f152f47831b44933facd2328;p=karo-tx-linux.git diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 17dfe9bb6d27..87bd5ba38d5b 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -503,6 +503,101 @@ static void device_irq_exit(struct pm860x_chip *chip) free_irq(chip->core_irq, chip); } +int pm8606_osc_enable(struct pm860x_chip *chip, unsigned short client) +{ + int ret = -EIO; + struct i2c_client *i2c = (chip->id == CHIP_PM8606) ? + chip->client : chip->companion; + + dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client); + dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n", + __func__, chip->osc_vote, + chip->osc_status); + + mutex_lock(&chip->osc_lock); + /* Update voting status */ + chip->osc_vote |= client; + /* If reference group is off - turn on*/ + if (chip->osc_status != PM8606_REF_GP_OSC_ON) { + chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN; + /* Enable Reference group Vsys */ + if (pm860x_set_bits(i2c, PM8606_VSYS, + PM8606_VSYS_EN, PM8606_VSYS_EN)) + goto out; + + /*Enable Internal Oscillator */ + if (pm860x_set_bits(i2c, PM8606_MISC, + PM8606_MISC_OSC_EN, PM8606_MISC_OSC_EN)) + goto out; + /* Update status (only if writes succeed) */ + chip->osc_status = PM8606_REF_GP_OSC_ON; + } + mutex_unlock(&chip->osc_lock); + + dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n", + __func__, chip->osc_vote, + chip->osc_status, ret); + return 0; +out: + mutex_unlock(&chip->osc_lock); + return ret; +} +EXPORT_SYMBOL(pm8606_osc_enable); + +int pm8606_osc_disable(struct pm860x_chip *chip, unsigned short client) +{ + int ret = -EIO; + struct i2c_client *i2c = (chip->id == CHIP_PM8606) ? + chip->client : chip->companion; + + dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client); + dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n", + __func__, chip->osc_vote, + chip->osc_status); + + mutex_lock(&chip->osc_lock); + /*Update voting status */ + chip->osc_vote &= ~(client); + /* If reference group is off and this is the last client to release + * - turn off */ + if ((chip->osc_status != PM8606_REF_GP_OSC_OFF) && + (chip->osc_vote == REF_GP_NO_CLIENTS)) { + chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN; + /* Disable Reference group Vsys */ + if (pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0)) + goto out; + /* Disable Internal Oscillator */ + if (pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0)) + goto out; + chip->osc_status = PM8606_REF_GP_OSC_OFF; + } + mutex_unlock(&chip->osc_lock); + + dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n", + __func__, chip->osc_vote, + chip->osc_status, ret); + return 0; +out: + mutex_unlock(&chip->osc_lock); + return ret; +} +EXPORT_SYMBOL(pm8606_osc_disable); + +static void __devinit device_osc_init(struct i2c_client *i2c) +{ + struct pm860x_chip *chip = i2c_get_clientdata(i2c); + + mutex_init(&chip->osc_lock); + /* init portofino reference group voting and status */ + /* Disable Reference group Vsys */ + pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0); + /* Disable Internal Oscillator */ + pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0); + + chip->osc_vote = REF_GP_NO_CLIENTS; + chip->osc_status = PM8606_REF_GP_OSC_OFF; +} + static void __devinit device_bk_init(struct pm860x_chip *chip, struct pm860x_platform_data *pdata) { @@ -767,6 +862,15 @@ out: return; } +static void __devinit device_8606_init(struct pm860x_chip *chip, + struct i2c_client *i2c, + struct pm860x_platform_data *pdata) +{ + device_osc_init(i2c); + device_bk_init(chip, pdata); + device_led_init(chip, pdata); +} + int __devinit pm860x_device_init(struct pm860x_chip *chip, struct pm860x_platform_data *pdata) { @@ -774,8 +878,7 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip, switch (chip->id) { case CHIP_PM8606: - device_bk_init(chip, pdata); - device_led_init(chip, pdata); + device_8606_init(chip, chip->client, pdata); break; case CHIP_PM8607: device_8607_init(chip, chip->client, pdata); @@ -785,8 +888,7 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip, if (chip->companion) { switch (chip->id) { case CHIP_PM8607: - device_bk_init(chip, pdata); - device_led_init(chip, pdata); + device_8606_init(chip, chip->companion, pdata); break; case CHIP_PM8606: device_8607_init(chip, chip->companion, pdata);