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

Commit 30578764 authored by Mark Brown's avatar Mark Brown
Browse files

Merge branch 'topic/asoc' of...

Merge branch 'topic/asoc' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6 into for-2.6.35
parents c4806174 aeb29a82
Loading
Loading
Loading
Loading
+17 −0
Original line number Original line Diff line number Diff line
/*
 * Platform data for Texas Instruments TLV320AIC3x codec
 *
 * Author: Jarkko Nikula <jhnikula@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
#ifndef __TLV320AIC3x_H__
#define __TLV320AIC3x_H__

struct aic3x_pdata {
	int gpio_reset; /* < 0 if not used */
};

#endif
 No newline at end of file
+1 −0
Original line number Original line Diff line number Diff line
@@ -31,6 +31,7 @@ enum tpa_model {
struct tpa6130a2_platform_data {
struct tpa6130a2_platform_data {
	enum tpa_model id;
	enum tpa_model id;
	int power_gpio;
	int power_gpio;
	int limit_gain;
};
};


#endif
#endif
+25 −0
Original line number Original line Diff line number Diff line
@@ -38,6 +38,7 @@
#include <linux/delay.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/platform_device.h>
#include <linux/platform_device.h>
#include <sound/core.h>
#include <sound/core.h>
@@ -47,6 +48,7 @@
#include <sound/soc-dapm.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include <sound/tlv.h>
#include <sound/tlv320aic3x.h>


#include "tlv320aic3x.h"
#include "tlv320aic3x.h"


@@ -64,6 +66,7 @@ struct aic3x_priv {
	struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES];
	struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES];
	unsigned int sysclk;
	unsigned int sysclk;
	int master;
	int master;
	int gpio_reset;
};
};


/*
/*
@@ -1278,6 +1281,10 @@ static int aic3x_unregister(struct aic3x_priv *aic3x)
	snd_soc_unregister_dai(&aic3x_dai);
	snd_soc_unregister_dai(&aic3x_dai);
	snd_soc_unregister_codec(&aic3x->codec);
	snd_soc_unregister_codec(&aic3x->codec);


	if (aic3x->gpio_reset >= 0) {
		gpio_set_value(aic3x->gpio_reset, 0);
		gpio_free(aic3x->gpio_reset);
	}
	regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
	regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
	regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
	regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);


@@ -1302,6 +1309,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
{
{
	struct snd_soc_codec *codec;
	struct snd_soc_codec *codec;
	struct aic3x_priv *aic3x;
	struct aic3x_priv *aic3x;
	struct aic3x_pdata *pdata = i2c->dev.platform_data;
	int ret, i;
	int ret, i;


	aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL);
	aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL);
@@ -1318,6 +1326,15 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,


	i2c_set_clientdata(i2c, aic3x);
	i2c_set_clientdata(i2c, aic3x);


	aic3x->gpio_reset = -1;
	if (pdata && pdata->gpio_reset >= 0) {
		ret = gpio_request(pdata->gpio_reset, "tlv320aic3x reset");
		if (ret != 0)
			goto err_gpio;
		aic3x->gpio_reset = pdata->gpio_reset;
		gpio_direction_output(aic3x->gpio_reset, 0);
	}

	for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
	for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
		aic3x->supplies[i].supply = aic3x_supply_names[i];
		aic3x->supplies[i].supply = aic3x_supply_names[i];


@@ -1335,11 +1352,19 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
		goto err_enable;
		goto err_enable;
	}
	}


	if (aic3x->gpio_reset >= 0) {
		udelay(1);
		gpio_set_value(aic3x->gpio_reset, 1);
	}

	return aic3x_register(codec);
	return aic3x_register(codec);


err_enable:
err_enable:
	regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
	regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
err_get:
err_get:
	if (aic3x->gpio_reset >= 0)
		gpio_free(aic3x->gpio_reset);
err_gpio:
	kfree(aic3x);
	kfree(aic3x);
	return ret;
	return ret;
}
}
+118 −105
Original line number Original line Diff line number Diff line
@@ -61,6 +61,8 @@
#define US_TO_SAMPLES(rate, us) \
#define US_TO_SAMPLES(rate, us) \
	(rate / (1000000 / us))
	(rate / (1000000 / us))


static void dac33_calculate_times(struct snd_pcm_substream *substream);
static int dac33_prepare_chip(struct snd_pcm_substream *substream);


static struct snd_soc_codec *tlv320dac33_codec;
static struct snd_soc_codec *tlv320dac33_codec;


@@ -91,6 +93,7 @@ struct tlv320dac33_priv {
	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];
	struct regulator_bulk_data supplies[DAC33_NUM_SUPPLIES];
	struct snd_pcm_substream *substream;
	int power_gpio;
	int power_gpio;
	int chip_power;
	int chip_power;
	int irq;
	int irq;
@@ -284,45 +287,47 @@ static int dac33_write16(struct snd_soc_codec *codec, unsigned int reg,
	return ret;
	return ret;
}
}


static void dac33_restore_regs(struct snd_soc_codec *codec)
static void dac33_init_chip(struct snd_soc_codec *codec)
{
{
	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
	u8 *cache = codec->reg_cache;
	u8 data[2];
	int i, ret;


	if (!dac33->chip_power)
	if (unlikely(!dac33->chip_power))
		return;
		return;


	for (i = DAC33_PWR_CTRL; i <= DAC33_INTP_CTRL_B; i++) {
	/* 44-46: DAC Control Registers */
		data[0] = i;
	/* A : DAC sample rate Fsref/1.5 */
		data[1] = cache[i];
	dac33_write(codec, DAC33_DAC_CTRL_A, DAC33_DACRATE(0));
		/* Skip the read only registers */
	/* B : DAC src=normal, not muted */
		if ((i >= DAC33_INT_OSC_STATUS &&
	dac33_write(codec, DAC33_DAC_CTRL_B, DAC33_DACSRCR_RIGHT |
				i <= DAC33_INT_OSC_FREQ_RAT_READ_B) ||
					     DAC33_DACSRCL_LEFT);
		    (i >= DAC33_FIFO_WPTR_MSB && i <= DAC33_FIFO_IRQ_FLAG) ||
	/* C : (defaults) */
		    i == DAC33_DAC_STATUS_FLAGS ||
	dac33_write(codec, DAC33_DAC_CTRL_C, 0x00);
		    i == DAC33_SRC_EST_REF_CLK_RATIO_A ||

		    i == DAC33_SRC_EST_REF_CLK_RATIO_B)
	/* 73 : volume soft stepping control,
			continue;
	 clock source = internal osc (?) */
		ret = codec->hw_write(codec->control_data, data, 2);
	dac33_write(codec, DAC33_ANA_VOL_SOFT_STEP_CTRL, DAC33_VOLCLKEN);
		if (ret != 2)

			dev_err(codec->dev, "Write failed (%d)\n", ret);
	dac33_write(codec, DAC33_PWR_CTRL, DAC33_PDNALLB);
	}

	for (i = DAC33_LDAC_PWR_CTRL; i <= DAC33_LINEL_TO_LLO_VOL; i++) {
	/* Restore only selected registers (gains mostly) */
		data[0] = i;
	dac33_write(codec, DAC33_LDAC_DIG_VOL_CTRL,
		data[1] = cache[i];
		    dac33_read_reg_cache(codec, DAC33_LDAC_DIG_VOL_CTRL));
		ret = codec->hw_write(codec->control_data, data, 2);
	dac33_write(codec, DAC33_RDAC_DIG_VOL_CTRL,
		if (ret != 2)
		    dac33_read_reg_cache(codec, DAC33_RDAC_DIG_VOL_CTRL));
			dev_err(codec->dev, "Write failed (%d)\n", ret);

	}
	dac33_write(codec, DAC33_LINEL_TO_LLO_VOL,
	for (i = DAC33_LINER_TO_RLO_VOL; i <= DAC33_OSC_TRIM; i++) {
		    dac33_read_reg_cache(codec, DAC33_LINEL_TO_LLO_VOL));
		data[0] = i;
	dac33_write(codec, DAC33_LINER_TO_RLO_VOL,
		data[1] = cache[i];
		    dac33_read_reg_cache(codec, DAC33_LINER_TO_RLO_VOL));
		ret = codec->hw_write(codec->control_data, data, 2);
		if (ret != 2)
			dev_err(codec->dev, "Write failed (%d)\n", ret);
}
}

static inline void dac33_read_id(struct snd_soc_codec *codec)
{
	u8 reg;

	dac33_read(codec, DAC33_DEVICE_ID_MSB, &reg);
	dac33_read(codec, DAC33_DEVICE_ID_LSB, &reg);
	dac33_read(codec, DAC33_DEVICE_REV_ID, &reg);
}
}


static inline void dac33_soft_power(struct snd_soc_codec *codec, int power)
static inline void dac33_soft_power(struct snd_soc_codec *codec, int power)
@@ -341,9 +346,17 @@ static inline void dac33_soft_power(struct snd_soc_codec *codec, int power)
static int 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 = snd_soc_codec_get_drvdata(codec);
	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
	int ret;
	int ret = 0;


	mutex_lock(&dac33->mutex);
	mutex_lock(&dac33->mutex);

	/* Safety check */
	if (unlikely(power == dac33->chip_power)) {
		dev_warn(codec->dev, "Trying to set the same power state: %s\n",
			power ? "ON" : "OFF");
		goto exit;
	}

	if (power) {
	if (power) {
		ret = regulator_bulk_enable(ARRAY_SIZE(dac33->supplies),
		ret = regulator_bulk_enable(ARRAY_SIZE(dac33->supplies),
					  dac33->supplies);
					  dac33->supplies);
@@ -357,11 +370,6 @@ static int dac33_hard_power(struct snd_soc_codec *codec, int power)
			gpio_set_value(dac33->power_gpio, 1);
			gpio_set_value(dac33->power_gpio, 1);


		dac33->chip_power = 1;
		dac33->chip_power = 1;

		/* Restore registers */
		dac33_restore_regs(codec);

		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)
@@ -383,6 +391,22 @@ static int dac33_hard_power(struct snd_soc_codec *codec, int power)
	return ret;
	return ret;
}
}


static int playback_event(struct snd_soc_dapm_widget *w,
		struct snd_kcontrol *kcontrol, int event)
{
	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(w->codec);

	switch (event) {
	case SND_SOC_DAPM_PRE_PMU:
		if (likely(dac33->substream)) {
			dac33_calculate_times(dac33->substream);
			dac33_prepare_chip(dac33->substream);
		}
		break;
	}
	return 0;
}

static int dac33_get_nsample(struct snd_kcontrol *kcontrol,
static int dac33_get_nsample(struct snd_kcontrol *kcontrol,
			 struct snd_ctl_elem_value *ucontrol)
			 struct snd_ctl_elem_value *ucontrol)
{
{
@@ -512,6 +536,8 @@ static const struct snd_soc_dapm_widget dac33_dapm_widgets[] = {
			 DAC33_OUT_AMP_PWR_CTRL, 6, 3, 3, 0),
			 DAC33_OUT_AMP_PWR_CTRL, 6, 3, 3, 0),
	SND_SOC_DAPM_REG(snd_soc_dapm_mixer, "Output Right Amp Power",
	SND_SOC_DAPM_REG(snd_soc_dapm_mixer, "Output Right Amp Power",
			 DAC33_OUT_AMP_PWR_CTRL, 4, 3, 3, 0),
			 DAC33_OUT_AMP_PWR_CTRL, 4, 3, 3, 0),

	SND_SOC_DAPM_PRE("Prepare Playback", playback_event),
};
};


static const struct snd_soc_dapm_route audio_map[] = {
static const struct snd_soc_dapm_route audio_map[] = {
@@ -554,18 +580,18 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec,
		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) {
			/* Coming from OFF, switch on the codec */
			ret = dac33_hard_power(codec, 1);
			ret = dac33_hard_power(codec, 1);
			if (ret != 0)
			if (ret != 0)
				return ret;
				return ret;
		}


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

		break;
		break;
	}
	}
	codec->bias_level = level;
	codec->bias_level = level;
@@ -708,6 +734,31 @@ static void dac33_oscwait(struct snd_soc_codec *codec)
			"internal oscillator calibration failed\n");
			"internal oscillator calibration failed\n");
}
}


static int dac33_startup(struct snd_pcm_substream *substream,
			   struct snd_soc_dai *dai)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_device *socdev = rtd->socdev;
	struct snd_soc_codec *codec = socdev->card->codec;
	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);

	/* Stream started, save the substream pointer */
	dac33->substream = substream;

	return 0;
}

static void dac33_shutdown(struct snd_pcm_substream *substream,
			     struct snd_soc_dai *dai)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_device *socdev = rtd->socdev;
	struct snd_soc_codec *codec = socdev->card->codec;
	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);

	dac33->substream = NULL;
}

static int dac33_hw_params(struct snd_pcm_substream *substream,
static int dac33_hw_params(struct snd_pcm_substream *substream,
			   struct snd_pcm_hw_params *params,
			   struct snd_pcm_hw_params *params,
			   struct snd_soc_dai *dai)
			   struct snd_soc_dai *dai)
@@ -791,6 +842,16 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
	}
	}


	mutex_lock(&dac33->mutex);
	mutex_lock(&dac33->mutex);

	if (!dac33->chip_power) {
		/*
		 * Chip is not powered yet.
		 * Do the init in the dac33_set_bias_level later.
		 */
		mutex_unlock(&dac33->mutex);
		return 0;
	}

	dac33_soft_power(codec, 0);
	dac33_soft_power(codec, 0);
	dac33_soft_power(codec, 1);
	dac33_soft_power(codec, 1);


@@ -997,15 +1058,6 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream)


}
}


static int dac33_pcm_prepare(struct snd_pcm_substream *substream,
			     struct snd_soc_dai *dai)
{
	dac33_calculate_times(substream);
	dac33_prepare_chip(substream);

	return 0;
}

static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
			     struct snd_soc_dai *dai)
			     struct snd_soc_dai *dai)
{
{
@@ -1269,35 +1321,6 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai,
	return 0;
	return 0;
}
}


static void dac33_init_chip(struct snd_soc_codec *codec)
{
	/* 44-46: DAC Control Registers */
	/* A : DAC sample rate Fsref/1.5 */
	dac33_write(codec, DAC33_DAC_CTRL_A, DAC33_DACRATE(0));
	/* B : DAC src=normal, not muted */
	dac33_write(codec, DAC33_DAC_CTRL_B, DAC33_DACSRCR_RIGHT |
					     DAC33_DACSRCL_LEFT);
	/* C : (defaults) */
	dac33_write(codec, DAC33_DAC_CTRL_C, 0x00);

	/* 64-65 : L&R DAC power control
	 Line In -> OUT 1V/V Gain, DAC -> OUT 4V/V Gain*/
	dac33_write(codec, DAC33_LDAC_PWR_CTRL, DAC33_LROUT_GAIN(2));
	dac33_write(codec, DAC33_RDAC_PWR_CTRL, DAC33_LROUT_GAIN(2));

	/* 73 : volume soft stepping control,
	 clock source = internal osc (?) */
	dac33_write(codec, DAC33_ANA_VOL_SOFT_STEP_CTRL, DAC33_VOLCLKEN);

	/* 66 : LOP/LOM Modes */
	dac33_write(codec, DAC33_OUT_AMP_CM_CTRL, 0xff);

	/* 68 : LOM inverted from LOP */
	dac33_write(codec, DAC33_OUT_AMP_CTRL, (3<<2));

	dac33_write(codec, DAC33_PWR_CTRL, DAC33_PDNALLB);
}

static int dac33_soc_probe(struct platform_device *pdev)
static int dac33_soc_probe(struct platform_device *pdev)
{
{
	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
@@ -1311,11 +1334,6 @@ static int dac33_soc_probe(struct platform_device *pdev)
	socdev->card->codec = codec;
	socdev->card->codec = codec;
	dac33 = snd_soc_codec_get_drvdata(codec);
	dac33 = snd_soc_codec_get_drvdata(codec);


	/* Power up the codec */
	dac33_hard_power(codec, 1);
	/* Set default configuration */
	dac33_init_chip(codec);

	/* register pcms */
	/* register pcms */
	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
	if (ret < 0) {
	if (ret < 0) {
@@ -1332,12 +1350,6 @@ static int dac33_soc_probe(struct platform_device *pdev)


	dac33_add_widgets(codec);
	dac33_add_widgets(codec);


	/* 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;
	return 0;


pcm_err:
pcm_err:
@@ -1374,6 +1386,8 @@ static int dac33_soc_resume(struct platform_device *pdev)
	struct snd_soc_codec *codec = socdev->card->codec;
	struct snd_soc_codec *codec = socdev->card->codec;


	dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
	dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
	if (codec->suspend_bias_level == SND_SOC_BIAS_ON)
		dac33_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
	dac33_set_bias_level(codec, codec->suspend_bias_level);
	dac33_set_bias_level(codec, codec->suspend_bias_level);


	return 0;
	return 0;
@@ -1392,8 +1406,9 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320dac33);
#define DAC33_FORMATS	SNDRV_PCM_FMTBIT_S16_LE
#define DAC33_FORMATS	SNDRV_PCM_FMTBIT_S16_LE


static struct snd_soc_dai_ops dac33_dai_ops = {
static struct snd_soc_dai_ops dac33_dai_ops = {
	.startup	= dac33_startup,
	.shutdown	= dac33_shutdown,
	.hw_params	= dac33_hw_params,
	.hw_params	= dac33_hw_params,
	.prepare	= dac33_pcm_prepare,
	.trigger	= dac33_pcm_trigger,
	.trigger	= dac33_pcm_trigger,
	.delay		= dac33_dai_delay,
	.delay		= dac33_dai_delay,
	.set_sysclk	= dac33_set_dai_sysclk,
	.set_sysclk	= dac33_set_dai_sysclk,
@@ -1447,6 +1462,7 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
	codec->hw_write = (hw_write_t) i2c_master_send;
	codec->hw_write = (hw_write_t) i2c_master_send;
	codec->bias_level = SND_SOC_BIAS_OFF;
	codec->bias_level = SND_SOC_BIAS_OFF;
	codec->set_bias_level = dac33_set_bias_level;
	codec->set_bias_level = dac33_set_bias_level;
	codec->idle_bias_off = 1;
	codec->dai = &dac33_dai;
	codec->dai = &dac33_dai;
	codec->num_dai = 1;
	codec->num_dai = 1;
	codec->reg_cache_size = ARRAY_SIZE(dac33_reg);
	codec->reg_cache_size = ARRAY_SIZE(dac33_reg);
@@ -1487,8 +1503,6 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
			goto error_gpio;
			goto error_gpio;
		}
		}
		gpio_direction_output(dac33->power_gpio, 0);
		gpio_direction_output(dac33->power_gpio, 0);
	} else {
		dac33->chip_power = 1;
	}
	}


	/* Check if the IRQ number is valid and request it */
	/* Check if the IRQ number is valid and request it */
@@ -1526,12 +1540,14 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
		goto err_get;
		goto err_get;
	}
	}


	ret = regulator_bulk_enable(ARRAY_SIZE(dac33->supplies),
	/* Read the tlv320dac33 ID registers */
				    dac33->supplies);
	ret = dac33_hard_power(codec, 1);
	if (ret != 0) {
	if (ret != 0) {
		dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
		dev_err(codec->dev, "Failed to power up codec: %d\n", ret);
		goto err_enable;
		goto error_codec;
	}
	}
	dac33_read_id(codec);
	dac33_hard_power(codec, 0);


	ret = snd_soc_register_codec(codec);
	ret = snd_soc_register_codec(codec);
	if (ret != 0) {
	if (ret != 0) {
@@ -1546,14 +1562,9 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
		goto error_codec;
		goto error_codec;
	}
	}


	/* Shut down the codec for now */
	dac33_hard_power(codec, 0);

	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);
	regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies);
err_get:
err_get:
	if (dac33->irq >= 0) {
	if (dac33->irq >= 0) {
@@ -1577,6 +1588,8 @@ static int __devexit dac33_i2c_remove(struct i2c_client *client)
	struct tlv320dac33_priv *dac33;
	struct tlv320dac33_priv *dac33;


	dac33 = i2c_get_clientdata(client);
	dac33 = i2c_get_clientdata(client);

	if (unlikely(dac33->chip_power))
		dac33_hard_power(&dac33->codec, 0);
		dac33_hard_power(&dac33->codec, 0);


	if (dac33->power_gpio >= 0)
	if (dac33->power_gpio >= 0)
+92 −7
Original line number Original line Diff line number Diff line
@@ -46,6 +46,9 @@ static const char *tpa6140a2_supply_names[TPA6130A2_NUM_SUPPLIES] = {
	"AVdd",
	"AVdd",
};
};


#define TPA6130A2_GAIN_MAX	0x3f
#define TPA6140A2_GAIN_MAX	0x1f

/* This struct is used to save the context */
/* This struct is used to save the context */
struct tpa6130a2_data {
struct tpa6130a2_data {
	struct mutex mutex;
	struct mutex mutex;
@@ -53,6 +56,8 @@ struct tpa6130a2_data {
	struct regulator_bulk_data supplies[TPA6130A2_NUM_SUPPLIES];
	struct regulator_bulk_data supplies[TPA6130A2_NUM_SUPPLIES];
	int power_gpio;
	int power_gpio;
	unsigned char power_state;
	unsigned char power_state;
	enum tpa_model id;
	int gain_limit;
};
};


static int tpa6130a2_i2c_read(int reg)
static int tpa6130a2_i2c_read(int reg)
@@ -175,6 +180,40 @@ static int tpa6130a2_power(int power)
	return ret;
	return ret;
}
}


static int tpa6130a2_info_volsw(struct snd_kcontrol *kcontrol,
		struct snd_ctl_elem_info *uinfo)
{
	struct soc_mixer_control *mc =
		(struct soc_mixer_control *)kcontrol->private_value;
	struct tpa6130a2_data *data;

	BUG_ON(tpa6130a2_client == NULL);
	data = i2c_get_clientdata(tpa6130a2_client);

	mutex_lock(&data->mutex);
	switch (mc->reg) {
	case TPA6130A2_REG_VOL_MUTE:
		if (data->gain_limit != mc->max)
			mc->max = data->gain_limit;
		break;
	default:
		dev_err(&tpa6130a2_client->dev,
			"Invalid register: 0x02%x\n", mc->reg);
		goto out;
	}
	if (unlikely(mc->max == 1))
		uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
	else
		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;

	uinfo->count = 1;
	uinfo->value.integer.min = 0;
	uinfo->value.integer.max = mc->max;
out:
	mutex_unlock(&data->mutex);
	return 0;
}

static int tpa6130a2_get_reg(struct snd_kcontrol *kcontrol,
static int tpa6130a2_get_reg(struct snd_kcontrol *kcontrol,
		struct snd_ctl_elem_value *ucontrol)
		struct snd_ctl_elem_value *ucontrol)
{
{
@@ -238,6 +277,15 @@ static int tpa6130a2_set_reg(struct snd_kcontrol *kcontrol,
	return 1;
	return 1;
}
}


#define SOC_SINGLE_EXT_TLV_TPA(xname, xreg, xshift, xmax, xinvert, tlv_array) \
{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
		 SNDRV_CTL_ELEM_ACCESS_READWRITE,\
	.tlv.p = (tlv_array), \
	.info = tpa6130a2_info_volsw, \
	.get = tpa6130a2_get_reg, .put = tpa6130a2_set_reg, \
	.private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) }

/*
/*
 * TPA6130 volume. From -59.5 to 4 dB with increasing step size when going
 * TPA6130 volume. From -59.5 to 4 dB with increasing step size when going
 * down in gain.
 * down in gain.
@@ -257,12 +305,24 @@ static const unsigned int tpa6130_tlv[] = {
};
};


static const struct snd_kcontrol_new tpa6130a2_controls[] = {
static const struct snd_kcontrol_new tpa6130a2_controls[] = {
	SOC_SINGLE_EXT_TLV("TPA6130A2 Headphone Playback Volume",
	SOC_SINGLE_EXT_TLV_TPA("TPA6130A2 Headphone Playback Volume",
		       TPA6130A2_REG_VOL_MUTE, 0, 0x3f, 0,
			TPA6130A2_REG_VOL_MUTE, 0, TPA6130A2_GAIN_MAX, 0,
		       tpa6130a2_get_reg, tpa6130a2_set_reg,
			tpa6130_tlv),
			tpa6130_tlv),
};
};


static const unsigned int tpa6140_tlv[] = {
	TLV_DB_RANGE_HEAD(3),
	0, 8, TLV_DB_SCALE_ITEM(-5900, 400, 0),
	9, 16, TLV_DB_SCALE_ITEM(-2500, 200, 0),
	17, 31, TLV_DB_SCALE_ITEM(-1000, 100, 0),
};

static const struct snd_kcontrol_new tpa6140a2_controls[] = {
	SOC_SINGLE_EXT_TLV_TPA("TPA6140A2 Headphone Playback Volume",
			TPA6130A2_REG_VOL_MUTE, 1, TPA6140A2_GAIN_MAX, 0,
			tpa6140_tlv),
};

/*
/*
 * Enable or disable channel (left or right)
 * Enable or disable channel (left or right)
 * The bit number for mute and amplifier are the same per channel:
 * The bit number for mute and amplifier are the same per channel:
@@ -368,11 +428,20 @@ static const struct snd_soc_dapm_route audio_map[] = {


int tpa6130a2_add_controls(struct snd_soc_codec *codec)
int tpa6130a2_add_controls(struct snd_soc_codec *codec)
{
{
	struct	tpa6130a2_data *data;

	BUG_ON(tpa6130a2_client == NULL);
	data = i2c_get_clientdata(tpa6130a2_client);

	snd_soc_dapm_new_controls(codec, tpa6130a2_dapm_widgets,
	snd_soc_dapm_new_controls(codec, tpa6130a2_dapm_widgets,
				ARRAY_SIZE(tpa6130a2_dapm_widgets));
				ARRAY_SIZE(tpa6130a2_dapm_widgets));


	snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
	snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));


	if (data->id == TPA6140A2)
		return snd_soc_add_controls(codec, tpa6140a2_controls,
						ARRAY_SIZE(tpa6140a2_controls));
	else
		return snd_soc_add_controls(codec, tpa6130a2_controls,
		return snd_soc_add_controls(codec, tpa6130a2_controls,
						ARRAY_SIZE(tpa6130a2_controls));
						ARRAY_SIZE(tpa6130a2_controls));


@@ -407,6 +476,7 @@ static int __devinit tpa6130a2_probe(struct i2c_client *client,


	pdata = client->dev.platform_data;
	pdata = client->dev.platform_data;
	data->power_gpio = pdata->power_gpio;
	data->power_gpio = pdata->power_gpio;
	data->id = pdata->id;


	mutex_init(&data->mutex);
	mutex_init(&data->mutex);


@@ -425,20 +495,35 @@ static int __devinit tpa6130a2_probe(struct i2c_client *client,
		gpio_direction_output(data->power_gpio, 0);
		gpio_direction_output(data->power_gpio, 0);
	}
	}


	switch (pdata->id) {
	switch (data->id) {
	case TPA6130A2:
	case TPA6130A2:
		for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
		for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
			data->supplies[i].supply = tpa6130a2_supply_names[i];
			data->supplies[i].supply = tpa6130a2_supply_names[i];
		if (pdata->limit_gain > 0 &&
		    pdata->limit_gain < TPA6130A2_GAIN_MAX)
			data->gain_limit = pdata->limit_gain;
		else
			data->gain_limit = TPA6130A2_GAIN_MAX;
		break;
		break;
	case TPA6140A2:
	case TPA6140A2:
		for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
		for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
			data->supplies[i].supply = tpa6140a2_supply_names[i];;
			data->supplies[i].supply = tpa6140a2_supply_names[i];;
		if (pdata->limit_gain > 0 &&
		    pdata->limit_gain < TPA6140A2_GAIN_MAX)
			data->gain_limit = pdata->limit_gain;
		else
			data->gain_limit = TPA6140A2_GAIN_MAX;
		break;
		break;
	default:
	default:
		dev_warn(dev, "Unknown TPA model (%d). Assuming 6130A2\n",
		dev_warn(dev, "Unknown TPA model (%d). Assuming 6130A2\n",
			 pdata->id);
			 pdata->id);
		for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
		for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
			data->supplies[i].supply = tpa6130a2_supply_names[i];
			data->supplies[i].supply = tpa6130a2_supply_names[i];
		if (pdata->limit_gain > 0 &&
		    pdata->limit_gain < TPA6130A2_GAIN_MAX)
			data->gain_limit = pdata->limit_gain;
		else
			data->gain_limit = TPA6130A2_GAIN_MAX;
	}
	}


	ret = regulator_bulk_get(dev, ARRAY_SIZE(data->supplies),
	ret = regulator_bulk_get(dev, ARRAY_SIZE(data->supplies),
Loading