diff options
Diffstat (limited to 'drivers/mfd/88pm860x-core.c')
| -rw-r--r-- | drivers/mfd/88pm860x-core.c | 110 | 
1 files changed, 106 insertions, 4 deletions
diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 17dfe9bb6d2..87bd5ba38d5 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);  |