mirror of
https://github.com/edk2-porting/linux-next.git
synced 2025-01-26 07:35:44 +08:00
ASoC: tlv320dac33: Add support for regulator framework
Take the regulator framework in use for managing the power sources. Signed-off-by: Ilkka Koskinen <ilkka.koskinen@nokia.com> Acked-by: Peter Ujfalusi <peter.ujfalusi@nokia.com> Acked-by: Liam Girdwood <lrg@slimlogic.co.uk> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
This commit is contained in:
parent
f1608cca9d
commit
3a7aaed714
@ -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 {
|
|||||||
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)
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mutex_unlock(&dac33->mutex);
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
|||||||
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,
|
|||||||
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)
|
|||||||
/* 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,
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
|||||||
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)
|
|||||||
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);
|
||||||
|
Loading…
Reference in New Issue
Block a user