Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+79 −13
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -58,11 +59,19 @@ enum dac33_state {
	DAC33_FLUSH,
};

#define DAC33_NUM_SUPPLIES 3
static const char *dac33_supply_names[DAC33_NUM_SUPPLIES] = {
	"AVDD",
	"DVDD",
	"IOVDD",
};

struct tlv320dac33_priv {
	struct mutex mutex;
	struct workqueue_struct *dac33_wq;
	struct work_struct work;
	struct snd_soc_codec codec;
	struct regulator_bulk_data supplies[DAC33_NUM_SUPPLIES];
	int power_gpio;
	int chip_power;
	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);
}

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;
	int ret;

	mutex_lock(&dac33->mutex);
	if (power) {
		if (dac33->power_gpio >= 0) {
		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 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);
	} else {
		dac33_soft_power(codec, 0);
		if (dac33->power_gpio >= 0) {
		if (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,
@@ -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,
				enum snd_soc_bias_level level)
{
	int ret;

	switch (level) {
	case SND_SOC_BIAS_ON:
		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:
		break;
	case SND_SOC_BIAS_STANDBY:
		if (codec->bias_level == SND_SOC_BIAS_OFF)
			dac33_hard_power(codec, 1);
		if (codec->bias_level == SND_SOC_BIAS_OFF) {
			ret = dac33_hard_power(codec, 1);
			if (ret != 0)
				return ret;
		}

		dac33_soft_power(codec, 0);
		break;
	case SND_SOC_BIAS_OFF:
		dac33_hard_power(codec, 0);
		ret = dac33_hard_power(codec, 0);
		if (ret != 0)
			return ret;

		break;
	}
	codec->bias_level = level;
@@ -959,6 +998,9 @@ static int dac33_soc_probe(struct platform_device *pdev)
	/* power on device */
	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;

pcm_err:
@@ -1039,7 +1081,7 @@ static int dac33_i2c_probe(struct i2c_client *client,
	struct tlv320dac33_platform_data *pdata;
	struct tlv320dac33_priv *dac33;
	struct snd_soc_codec *codec;
	int ret = 0;
	int ret, i;

	if (client->dev.platform_data == NULL) {
		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);
	if (ret != 0) {
		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;

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) {
		free_irq(dac33->irq, &dac33->codec);
		destroy_workqueue(dac33->dac33_wq);
@@ -1177,6 +1241,8 @@ static int dac33_i2c_remove(struct i2c_client *client)
	if (dac33->irq >= 0)
		free_irq(dac33->irq, &dac33->codec);

	regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies);

	destroy_workqueue(dac33->dac33_wq);
	snd_soc_unregister_dai(&dac33_dai);
	snd_soc_unregister_codec(&dac33->codec);