Commit 3a7aaed7 authored by Ilkka Koskinen's avatar Ilkka Koskinen Committed by Mark Brown

ASoC: tlv320dac33: Add support for regulator framework

Take the regulator framework in use for managing the power sources.
Signed-off-by: default avatarIlkka Koskinen <ilkka.koskinen@nokia.com>
Acked-by: default avatarPeter Ujfalusi <peter.ujfalusi@nokia.com>
Acked-by: default avatarLiam Girdwood <lrg@slimlogic.co.uk>
Signed-off-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
parent f1608cca
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/pcm.h> #include <sound/pcm.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
...@@ -58,11 +59,19 @@ enum dac33_state { ...@@ -58,11 +59,19 @@ enum dac33_state {
DAC33_FLUSH, DAC33_FLUSH,
}; };
#define DAC33_NUM_SUPPLIES 3
static const char *dac33_supply_names[DAC33_NUM_SUPPLIES] = {
"AVDD",
"DVDD",
"IOVDD",
};
struct tlv320dac33_priv { struct tlv320dac33_priv {
struct mutex mutex; struct mutex mutex;
struct workqueue_struct *dac33_wq; struct workqueue_struct *dac33_wq;
struct work_struct work; struct work_struct work;
struct snd_soc_codec codec; struct snd_soc_codec codec;
struct regulator_bulk_data supplies[DAC33_NUM_SUPPLIES];
int power_gpio; int power_gpio;
int chip_power; int chip_power;
int irq; int irq;
...@@ -297,28 +306,49 @@ static inline void dac33_soft_power(struct snd_soc_codec *codec, int power) ...@@ -297,28 +306,49 @@ static inline void dac33_soft_power(struct snd_soc_codec *codec, int power)
dac33_write(codec, DAC33_PWR_CTRL, reg); dac33_write(codec, DAC33_PWR_CTRL, reg);
} }
static void dac33_hard_power(struct snd_soc_codec *codec, int power) static int dac33_hard_power(struct snd_soc_codec *codec, int power)
{ {
struct tlv320dac33_priv *dac33 = codec->private_data; struct tlv320dac33_priv *dac33 = codec->private_data;
int ret;
mutex_lock(&dac33->mutex); mutex_lock(&dac33->mutex);
if (power) { if (power) {
if (dac33->power_gpio >= 0) { ret = regulator_bulk_enable(ARRAY_SIZE(dac33->supplies),
gpio_set_value(dac33->power_gpio, 1); dac33->supplies);
dac33->chip_power = 1; if (ret != 0) {
/* Restore registers */ dev_err(codec->dev,
dac33_restore_regs(codec); "Failed to enable supplies: %d\n", ret);
goto exit;
} }
if (dac33->power_gpio >= 0)
gpio_set_value(dac33->power_gpio, 1);
dac33->chip_power = 1;
/* Restore registers */
dac33_restore_regs(codec);
dac33_soft_power(codec, 1); dac33_soft_power(codec, 1);
} else { } else {
dac33_soft_power(codec, 0); dac33_soft_power(codec, 0);
if (dac33->power_gpio >= 0) { if (dac33->power_gpio >= 0)
gpio_set_value(dac33->power_gpio, 0); gpio_set_value(dac33->power_gpio, 0);
dac33->chip_power = 0;
ret = regulator_bulk_disable(ARRAY_SIZE(dac33->supplies),
dac33->supplies);
if (ret != 0) {
dev_err(codec->dev,
"Failed to disable supplies: %d\n", ret);
goto exit;
} }
dac33->chip_power = 0;
} }
mutex_unlock(&dac33->mutex);
exit:
mutex_unlock(&dac33->mutex);
return ret;
} }
static int dac33_get_nsample(struct snd_kcontrol *kcontrol, static int dac33_get_nsample(struct snd_kcontrol *kcontrol,
...@@ -469,6 +499,8 @@ static int dac33_add_widgets(struct snd_soc_codec *codec) ...@@ -469,6 +499,8 @@ static int dac33_add_widgets(struct snd_soc_codec *codec)
static int dac33_set_bias_level(struct snd_soc_codec *codec, static int dac33_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level) enum snd_soc_bias_level level)
{ {
int ret;
switch (level) { switch (level) {
case SND_SOC_BIAS_ON: case SND_SOC_BIAS_ON:
dac33_soft_power(codec, 1); dac33_soft_power(codec, 1);
...@@ -476,12 +508,19 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec, ...@@ -476,12 +508,19 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE: case SND_SOC_BIAS_PREPARE:
break; break;
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
if (codec->bias_level == SND_SOC_BIAS_OFF) if (codec->bias_level == SND_SOC_BIAS_OFF) {
dac33_hard_power(codec, 1); ret = dac33_hard_power(codec, 1);
if (ret != 0)
return ret;
}
dac33_soft_power(codec, 0); dac33_soft_power(codec, 0);
break; break;
case SND_SOC_BIAS_OFF: case SND_SOC_BIAS_OFF:
dac33_hard_power(codec, 0); ret = dac33_hard_power(codec, 0);
if (ret != 0)
return ret;
break; break;
} }
codec->bias_level = level; codec->bias_level = level;
...@@ -959,6 +998,9 @@ static int dac33_soc_probe(struct platform_device *pdev) ...@@ -959,6 +998,9 @@ static int dac33_soc_probe(struct platform_device *pdev)
/* power on device */ /* power on device */
dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY); dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* Bias level configuration has enabled regulator an extra time */
regulator_bulk_disable(ARRAY_SIZE(dac33->supplies), dac33->supplies);
return 0; return 0;
pcm_err: pcm_err:
...@@ -1039,7 +1081,7 @@ static int dac33_i2c_probe(struct i2c_client *client, ...@@ -1039,7 +1081,7 @@ static int dac33_i2c_probe(struct i2c_client *client,
struct tlv320dac33_platform_data *pdata; struct tlv320dac33_platform_data *pdata;
struct tlv320dac33_priv *dac33; struct tlv320dac33_priv *dac33;
struct snd_soc_codec *codec; struct snd_soc_codec *codec;
int ret = 0; int ret, i;
if (client->dev.platform_data == NULL) { if (client->dev.platform_data == NULL) {
dev_err(&client->dev, "Platform data not set\n"); dev_err(&client->dev, "Platform data not set\n");
...@@ -1130,6 +1172,24 @@ static int dac33_i2c_probe(struct i2c_client *client, ...@@ -1130,6 +1172,24 @@ static int dac33_i2c_probe(struct i2c_client *client,
} }
} }
for (i = 0; i < ARRAY_SIZE(dac33->supplies); i++)
dac33->supplies[i].supply = dac33_supply_names[i];
ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(dac33->supplies),
dac33->supplies);
if (ret != 0) {
dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
goto err_get;
}
ret = regulator_bulk_enable(ARRAY_SIZE(dac33->supplies),
dac33->supplies);
if (ret != 0) {
dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
goto err_enable;
}
ret = snd_soc_register_codec(codec); ret = snd_soc_register_codec(codec);
if (ret != 0) { if (ret != 0) {
dev_err(codec->dev, "Failed to register codec: %d\n", ret); dev_err(codec->dev, "Failed to register codec: %d\n", ret);
...@@ -1149,6 +1209,10 @@ static int dac33_i2c_probe(struct i2c_client *client, ...@@ -1149,6 +1209,10 @@ static int dac33_i2c_probe(struct i2c_client *client,
return ret; return ret;
error_codec: error_codec:
regulator_bulk_disable(ARRAY_SIZE(dac33->supplies), dac33->supplies);
err_enable:
regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies);
err_get:
if (dac33->irq >= 0) { if (dac33->irq >= 0) {
free_irq(dac33->irq, &dac33->codec); free_irq(dac33->irq, &dac33->codec);
destroy_workqueue(dac33->dac33_wq); destroy_workqueue(dac33->dac33_wq);
...@@ -1177,6 +1241,8 @@ static int dac33_i2c_remove(struct i2c_client *client) ...@@ -1177,6 +1241,8 @@ static int dac33_i2c_remove(struct i2c_client *client)
if (dac33->irq >= 0) if (dac33->irq >= 0)
free_irq(dac33->irq, &dac33->codec); free_irq(dac33->irq, &dac33->codec);
regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies);
destroy_workqueue(dac33->dac33_wq); destroy_workqueue(dac33->dac33_wq);
snd_soc_unregister_dai(&dac33_dai); snd_soc_unregister_dai(&dac33_dai);
snd_soc_unregister_codec(&dac33->codec); snd_soc_unregister_codec(&dac33->codec);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment