summary refs log tree commit diff
path: root/sound/soc/codecs/tlv320dac33.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2010-05-20 12:00:43 +0200
committerTakashi Iwai <tiwai@suse.de>2010-05-20 12:00:43 +0200
commitd71f4cece4bd97d05592836202fc04ff2e7817e3 (patch)
tree6c877c7a938758b1323d9c97d46b9c536e618c69 /sound/soc/codecs/tlv320dac33.c
parent19008bdacb9f7841166ebafe0aef361ee582ffbf (diff)
parentad8332c1302bcb4f80d593fd3eb477be9d7f5604 (diff)
downloadlinux-d71f4cece4bd97d05592836202fc04ff2e7817e3.tar.gz
Merge branch 'topic/asoc' into for-linus
Conflicts:
	sound/soc/codecs/ad1938.c
Diffstat (limited to 'sound/soc/codecs/tlv320dac33.c')
-rw-r--r--sound/soc/codecs/tlv320dac33.c543
1 files changed, 386 insertions, 157 deletions
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index d1e0e81ef30c..65adc77eada1 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -51,6 +51,20 @@
 
 #define LATENCY_TIME_MS		20
 
+#define MODE7_LTHR		10
+#define MODE7_UTHR		(DAC33_BUFFER_SIZE_SAMPLES - 10)
+
+#define BURST_BASEFREQ_HZ	49152000
+
+#define SAMPLES_TO_US(rate, samples) \
+	(1000000000 / ((rate * 1000) / samples))
+
+#define US_TO_SAMPLES(rate, 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;
 
 enum dac33_state {
@@ -80,6 +94,7 @@ struct tlv320dac33_priv {
 	struct work_struct work;
 	struct snd_soc_codec codec;
 	struct regulator_bulk_data supplies[DAC33_NUM_SUPPLIES];
+	struct snd_pcm_substream *substream;
 	int power_gpio;
 	int chip_power;
 	int irq;
@@ -93,6 +108,17 @@ struct tlv320dac33_priv {
 	enum dac33_fifo_modes fifo_mode;/* FIFO mode selection */
 	unsigned int nsample;		/* burst read amount from host */
 	u8 burst_bclkdiv;		/* BCLK divider value in burst mode */
+	unsigned int burst_rate;	/* Interface speed in Burst modes */
+
+	int keep_bclk;			/* Keep the BCLK continuously running
+					 * in FIFO modes */
+	spinlock_t lock;
+	unsigned long long t_stamp1;	/* Time stamp for FIFO modes to */
+	unsigned long long t_stamp2;	/* calculate the FIFO caused delay */
+
+	unsigned int mode1_us_burst;	/* Time to burst read n number of
+					 * samples */
+	unsigned int mode7_us_to_lthr;	/* Time to reach lthr from uthr */
 
 	enum dac33_state state;
 };
@@ -166,7 +192,7 @@ static inline void dac33_write_reg_cache(struct snd_soc_codec *codec,
 static int dac33_read(struct snd_soc_codec *codec, unsigned int reg,
 		      u8 *value)
 {
-	struct tlv320dac33_priv *dac33 = codec->private_data;
+	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 	int val;
 
 	*value = reg & 0xff;
@@ -191,7 +217,7 @@ static int dac33_read(struct snd_soc_codec *codec, unsigned int reg,
 static int dac33_write(struct snd_soc_codec *codec, unsigned int reg,
 		       unsigned int value)
 {
-	struct tlv320dac33_priv *dac33 = codec->private_data;
+	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 	u8 data[2];
 	int ret = 0;
 
@@ -218,7 +244,7 @@ static int dac33_write(struct snd_soc_codec *codec, unsigned int reg,
 static int dac33_write_locked(struct snd_soc_codec *codec, unsigned int reg,
 		       unsigned int value)
 {
-	struct tlv320dac33_priv *dac33 = codec->private_data;
+	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 	int ret;
 
 	mutex_lock(&dac33->mutex);
@@ -232,7 +258,7 @@ static int dac33_write_locked(struct snd_soc_codec *codec, unsigned int reg,
 static int dac33_write16(struct snd_soc_codec *codec, unsigned int reg,
 		       unsigned int value)
 {
-	struct tlv320dac33_priv *dac33 = codec->private_data;
+	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 	u8 data[3];
 	int ret = 0;
 
@@ -262,45 +288,47 @@ static int dac33_write16(struct snd_soc_codec *codec, unsigned int reg,
 	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 = codec->private_data;
-	u8 *cache = codec->reg_cache;
-	u8 data[2];
-	int i, ret;
+	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 
-	if (!dac33->chip_power)
+	if (unlikely(!dac33->chip_power))
 		return;
 
-	for (i = DAC33_PWR_CTRL; i <= DAC33_INTP_CTRL_B; i++) {
-		data[0] = i;
-		data[1] = cache[i];
-		/* Skip the read only registers */
-		if ((i >= DAC33_INT_OSC_STATUS &&
-				i <= DAC33_INT_OSC_FREQ_RAT_READ_B) ||
-		    (i >= DAC33_FIFO_WPTR_MSB && i <= DAC33_FIFO_IRQ_FLAG) ||
-		    i == DAC33_DAC_STATUS_FLAGS ||
-		    i == DAC33_SRC_EST_REF_CLK_RATIO_A ||
-		    i == DAC33_SRC_EST_REF_CLK_RATIO_B)
-			continue;
-		ret = codec->hw_write(codec->control_data, data, 2);
-		if (ret != 2)
-			dev_err(codec->dev, "Write failed (%d)\n", ret);
-	}
-	for (i = DAC33_LDAC_PWR_CTRL; i <= DAC33_LINEL_TO_LLO_VOL; i++) {
-		data[0] = i;
-		data[1] = cache[i];
-		ret = codec->hw_write(codec->control_data, data, 2);
-		if (ret != 2)
-			dev_err(codec->dev, "Write failed (%d)\n", ret);
-	}
-	for (i = DAC33_LINER_TO_RLO_VOL; i <= DAC33_OSC_TRIM; i++) {
-		data[0] = i;
-		data[1] = cache[i];
-		ret = codec->hw_write(codec->control_data, data, 2);
-		if (ret != 2)
-			dev_err(codec->dev, "Write failed (%d)\n", ret);
-	}
+	/* 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);
+
+	/* 73 : volume soft stepping control,
+	 clock source = internal osc (?) */
+	dac33_write(codec, DAC33_ANA_VOL_SOFT_STEP_CTRL, DAC33_VOLCLKEN);
+
+	dac33_write(codec, DAC33_PWR_CTRL, DAC33_PDNALLB);
+
+	/* Restore only selected registers (gains mostly) */
+	dac33_write(codec, DAC33_LDAC_DIG_VOL_CTRL,
+		    dac33_read_reg_cache(codec, DAC33_LDAC_DIG_VOL_CTRL));
+	dac33_write(codec, DAC33_RDAC_DIG_VOL_CTRL,
+		    dac33_read_reg_cache(codec, DAC33_RDAC_DIG_VOL_CTRL));
+
+	dac33_write(codec, DAC33_LINEL_TO_LLO_VOL,
+		    dac33_read_reg_cache(codec, DAC33_LINEL_TO_LLO_VOL));
+	dac33_write(codec, DAC33_LINER_TO_RLO_VOL,
+		    dac33_read_reg_cache(codec, DAC33_LINER_TO_RLO_VOL));
+}
+
+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)
@@ -311,16 +339,25 @@ static inline void dac33_soft_power(struct snd_soc_codec *codec, int power)
 	if (power)
 		reg |= DAC33_PDNALLB;
 	else
-		reg &= ~DAC33_PDNALLB;
+		reg &= ~(DAC33_PDNALLB | DAC33_OSCPDNB |
+			 DAC33_DACRPDNB | DAC33_DACLPDNB);
 	dac33_write(codec, DAC33_PWR_CTRL, reg);
 }
 
 static int dac33_hard_power(struct snd_soc_codec *codec, int power)
 {
-	struct tlv320dac33_priv *dac33 = codec->private_data;
-	int ret;
+	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
 
 	mutex_lock(&dac33->mutex);
+
+	/* Safety check */
+	if (unlikely(power == dac33->chip_power)) {
+		dev_dbg(codec->dev, "Trying to set the same power state: %s\n",
+			power ? "ON" : "OFF");
+		goto exit;
+	}
+
 	if (power) {
 		ret = regulator_bulk_enable(ARRAY_SIZE(dac33->supplies),
 					  dac33->supplies);
@@ -334,11 +371,6 @@ static int dac33_hard_power(struct snd_soc_codec *codec, int power)
 			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)
@@ -360,11 +392,27 @@ exit:
 	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,
 			 struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct tlv320dac33_priv *dac33 = codec->private_data;
+	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 
 	ucontrol->value.integer.value[0] = dac33->nsample;
 
@@ -375,17 +423,21 @@ static int dac33_set_nsample(struct snd_kcontrol *kcontrol,
 			 struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct tlv320dac33_priv *dac33 = codec->private_data;
+	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 	int ret = 0;
 
 	if (dac33->nsample == ucontrol->value.integer.value[0])
 		return 0;
 
 	if (ucontrol->value.integer.value[0] < dac33->nsample_min ||
-	    ucontrol->value.integer.value[0] > dac33->nsample_max)
+	    ucontrol->value.integer.value[0] > dac33->nsample_max) {
 		ret = -EINVAL;
-	else
+	} else {
 		dac33->nsample = ucontrol->value.integer.value[0];
+		/* Re calculate the burst time */
+		dac33->mode1_us_burst = SAMPLES_TO_US(dac33->burst_rate,
+						      dac33->nsample);
+	}
 
 	return ret;
 }
@@ -394,7 +446,7 @@ static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol,
 			 struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct tlv320dac33_priv *dac33 = codec->private_data;
+	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 
 	ucontrol->value.integer.value[0] = dac33->fifo_mode;
 
@@ -405,7 +457,7 @@ static int dac33_set_fifo_mode(struct snd_kcontrol *kcontrol,
 			 struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct tlv320dac33_priv *dac33 = codec->private_data;
+	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 	int ret = 0;
 
 	if (dac33->fifo_mode == ucontrol->value.integer.value[0])
@@ -485,6 +537,8 @@ static const struct snd_soc_dapm_widget dac33_dapm_widgets[] = {
 			 DAC33_OUT_AMP_PWR_CTRL, 6, 3, 3, 0),
 	SND_SOC_DAPM_REG(snd_soc_dapm_mixer, "Output Right Amp Power",
 			 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[] = {
@@ -527,18 +581,21 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec,
 		break;
 	case SND_SOC_BIAS_STANDBY:
 		if (codec->bias_level == SND_SOC_BIAS_OFF) {
+			/* Coming from OFF, switch on the codec */
 			ret = dac33_hard_power(codec, 1);
 			if (ret != 0)
 				return ret;
-		}
 
-		dac33_soft_power(codec, 0);
+			dac33_init_chip(codec);
+		}
 		break;
 	case SND_SOC_BIAS_OFF:
+		/* Do not power off, when the codec is already off */
+		if (codec->bias_level == SND_SOC_BIAS_OFF)
+			return 0;
 		ret = dac33_hard_power(codec, 0);
 		if (ret != 0)
 			return ret;
-
 		break;
 	}
 	codec->bias_level = level;
@@ -555,13 +612,34 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
 	switch (dac33->fifo_mode) {
 	case DAC33_FIFO_MODE1:
 		dac33_write16(codec, DAC33_NSAMPLE_MSB,
-				DAC33_THRREG(dac33->nsample));
+			DAC33_THRREG(dac33->nsample + dac33->alarm_threshold));
+
+		/* Take the timestamps */
+		spin_lock_irq(&dac33->lock);
+		dac33->t_stamp2 = ktime_to_us(ktime_get());
+		dac33->t_stamp1 = dac33->t_stamp2;
+		spin_unlock_irq(&dac33->lock);
+
 		dac33_write16(codec, DAC33_PREFILL_MSB,
 				DAC33_THRREG(dac33->alarm_threshold));
+		/* Enable Alarm Threshold IRQ with a delay */
+		udelay(SAMPLES_TO_US(dac33->burst_rate,
+				     dac33->alarm_threshold));
+		dac33_write(codec, DAC33_FIFO_IRQ_MASK, DAC33_MAT);
 		break;
 	case DAC33_FIFO_MODE7:
+		/* Take the timestamp */
+		spin_lock_irq(&dac33->lock);
+		dac33->t_stamp1 = ktime_to_us(ktime_get());
+		/* Move back the timestamp with drain time */
+		dac33->t_stamp1 -= dac33->mode7_us_to_lthr;
+		spin_unlock_irq(&dac33->lock);
+
 		dac33_write16(codec, DAC33_PREFILL_MSB,
-				DAC33_THRREG(10));
+				DAC33_THRREG(MODE7_LTHR));
+
+		/* Enable Upper Threshold IRQ */
+		dac33_write(codec, DAC33_FIFO_IRQ_MASK, DAC33_MUT);
 		break;
 	default:
 		dev_warn(codec->dev, "Unhandled FIFO mode: %d\n",
@@ -578,6 +656,11 @@ static inline void dac33_playback_handler(struct tlv320dac33_priv *dac33)
 
 	switch (dac33->fifo_mode) {
 	case DAC33_FIFO_MODE1:
+		/* Take the timestamp */
+		spin_lock_irq(&dac33->lock);
+		dac33->t_stamp2 = ktime_to_us(ktime_get());
+		spin_unlock_irq(&dac33->lock);
+
 		dac33_write16(codec, DAC33_NSAMPLE_MSB,
 				DAC33_THRREG(dac33->nsample));
 		break;
@@ -628,31 +711,17 @@ static void dac33_work(struct work_struct *work)
 static irqreturn_t dac33_interrupt_handler(int irq, void *dev)
 {
 	struct snd_soc_codec *codec = dev;
-	struct tlv320dac33_priv *dac33 = codec->private_data;
-
-	queue_work(dac33->dac33_wq, &dac33->work);
+	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 
-	return IRQ_HANDLED;
-}
+	spin_lock(&dac33->lock);
+	dac33->t_stamp1 = ktime_to_us(ktime_get());
+	spin_unlock(&dac33->lock);
 
-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 = codec->private_data;
-	unsigned int pwr_ctrl;
+	/* Do not schedule the workqueue in Mode7 */
+	if (dac33->fifo_mode != DAC33_FIFO_MODE7)
+		queue_work(dac33->dac33_wq, &dac33->work);
 
-	/* Stop pending workqueue */
-	if (dac33->fifo_mode)
-		cancel_work_sync(&dac33->work);
-
-	mutex_lock(&dac33->mutex);
-	pwr_ctrl = dac33_read_reg_cache(codec, DAC33_PWR_CTRL);
-	pwr_ctrl &= ~(DAC33_OSCPDNB | DAC33_DACRPDNB | DAC33_DACLPDNB);
-	dac33_write(codec, DAC33_PWR_CTRL, pwr_ctrl);
-	mutex_unlock(&dac33->mutex);
+	return IRQ_HANDLED;
 }
 
 static void dac33_oscwait(struct snd_soc_codec *codec)
@@ -669,6 +738,31 @@ static void dac33_oscwait(struct snd_soc_codec *codec)
 			"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,
 			   struct snd_pcm_hw_params *params,
 			   struct snd_soc_dai *dai)
@@ -715,7 +809,7 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
 	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 = codec->private_data;
+	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 	unsigned int oscset, ratioset, pwr_ctrl, reg_tmp;
 	u8 aictrl_a, aictrl_b, fifoctrl_a;
 
@@ -752,6 +846,17 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
 	}
 
 	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, 1);
 
 	reg_tmp = dac33_read_reg_cache(codec, DAC33_INT_OSC_CTRL);
@@ -799,11 +904,10 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
 	case DAC33_FIFO_MODE1:
 		dac33_write(codec, DAC33_FIFO_IRQ_MODE_B,
 			    DAC33_ATM(DAC33_FIFO_IRQ_MODE_LEVEL));
-		dac33_write(codec, DAC33_FIFO_IRQ_MASK, DAC33_MAT);
 		break;
 	case DAC33_FIFO_MODE7:
-		/* Disable all interrupts */
-		dac33_write(codec, DAC33_FIFO_IRQ_MASK, 0);
+		dac33_write(codec, DAC33_FIFO_IRQ_MODE_A,
+			DAC33_UTM(DAC33_FIFO_IRQ_MODE_LEVEL));
 		break;
 	default:
 		/* in FIFO bypass mode, the interrupts are not used */
@@ -822,7 +926,10 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
 		 */
 		fifoctrl_a &= ~DAC33_FBYPAS;
 		fifoctrl_a &= ~DAC33_FAUTO;
-		aictrl_b &= ~DAC33_BCLKON;
+		if (dac33->keep_bclk)
+			aictrl_b |= DAC33_BCLKON;
+		else
+			aictrl_b &= ~DAC33_BCLKON;
 		break;
 	case DAC33_FIFO_MODE7:
 		/*
@@ -833,7 +940,10 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
 		 */
 		fifoctrl_a &= ~DAC33_FBYPAS;
 		fifoctrl_a |= DAC33_FAUTO;
-		aictrl_b &= ~DAC33_BCLKON;
+		if (dac33->keep_bclk)
+			aictrl_b |= DAC33_BCLKON;
+		else
+			aictrl_b &= ~DAC33_BCLKON;
 		break;
 	default:
 		/*
@@ -875,10 +985,8 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
 		 * Configure the threshold levels, and leave 10 sample space
 		 * at the bottom, and also at the top of the FIFO
 		 */
-		dac33_write16(codec, DAC33_UTHR_MSB,
-			DAC33_THRREG(DAC33_BUFFER_SIZE_SAMPLES - 10));
-		dac33_write16(codec, DAC33_LTHR_MSB,
-			DAC33_THRREG(10));
+		dac33_write16(codec, DAC33_UTHR_MSB, DAC33_THRREG(MODE7_UTHR));
+		dac33_write16(codec, DAC33_LTHR_MSB, DAC33_THRREG(MODE7_LTHR));
 		break;
 	default:
 		break;
@@ -894,9 +1002,13 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream)
 	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 = codec->private_data;
+	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 	unsigned int nsample_limit;
 
+	/* In bypass mode we don't need to calculate */
+	if (!dac33->fifo_mode)
+		return;
+
 	/* Number of samples (16bit, stereo) in one period */
 	dac33->nsample_min = snd_pcm_lib_period_bytes(substream) / 4;
 
@@ -930,15 +1042,24 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream)
 
 	if (dac33->nsample > dac33->nsample_max)
 		dac33->nsample = dac33->nsample_max;
-}
 
-static int dac33_pcm_prepare(struct snd_pcm_substream *substream,
-			     struct snd_soc_dai *dai)
-{
-	dac33_calculate_times(substream);
-	dac33_prepare_chip(substream);
+	switch (dac33->fifo_mode) {
+	case DAC33_FIFO_MODE1:
+		dac33->mode1_us_burst = SAMPLES_TO_US(dac33->burst_rate,
+						      dac33->nsample);
+		dac33->t_stamp1 = 0;
+		dac33->t_stamp2 = 0;
+		break;
+	case DAC33_FIFO_MODE7:
+		dac33->mode7_us_to_lthr =
+					SAMPLES_TO_US(substream->runtime->rate,
+						MODE7_UTHR - MODE7_LTHR + 1);
+		dac33->t_stamp1 = 0;
+		break;
+	default:
+		break;
+	}
 
-	return 0;
 }
 
 static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
@@ -947,7 +1068,7 @@ static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
 	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 = codec->private_data;
+	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 	int ret = 0;
 
 	switch (cmd) {
@@ -974,11 +1095,156 @@ static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
 	return ret;
 }
 
+static snd_pcm_sframes_t dac33_dai_delay(
+			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);
+	unsigned long long t0, t1, t_now;
+	unsigned int time_delta;
+	int samples_out, samples_in, samples;
+	snd_pcm_sframes_t delay = 0;
+
+	switch (dac33->fifo_mode) {
+	case DAC33_FIFO_BYPASS:
+		break;
+	case DAC33_FIFO_MODE1:
+		spin_lock(&dac33->lock);
+		t0 = dac33->t_stamp1;
+		t1 = dac33->t_stamp2;
+		spin_unlock(&dac33->lock);
+		t_now = ktime_to_us(ktime_get());
+
+		/* We have not started to fill the FIFO yet, delay is 0 */
+		if (!t1)
+			goto out;
+
+		if (t0 > t1) {
+			/*
+			 * Phase 1:
+			 * After Alarm threshold, and before nSample write
+			 */
+			time_delta = t_now - t0;
+			samples_out = time_delta ? US_TO_SAMPLES(
+						substream->runtime->rate,
+						time_delta) : 0;
+
+			if (likely(dac33->alarm_threshold > samples_out))
+				delay = dac33->alarm_threshold - samples_out;
+			else
+				delay = 0;
+		} else if ((t_now - t1) <= dac33->mode1_us_burst) {
+			/*
+			 * Phase 2:
+			 * After nSample write (during burst operation)
+			 */
+			time_delta = t_now - t0;
+			samples_out = time_delta ? US_TO_SAMPLES(
+						substream->runtime->rate,
+						time_delta) : 0;
+
+			time_delta = t_now - t1;
+			samples_in = time_delta ? US_TO_SAMPLES(
+						dac33->burst_rate,
+						time_delta) : 0;
+
+			samples = dac33->alarm_threshold;
+			samples += (samples_in - samples_out);
+
+			if (likely(samples > 0))
+				delay = samples;
+			else
+				delay = 0;
+		} else {
+			/*
+			 * Phase 3:
+			 * After burst operation, before next alarm threshold
+			 */
+			time_delta = t_now - t0;
+			samples_out = time_delta ? US_TO_SAMPLES(
+						substream->runtime->rate,
+						time_delta) : 0;
+
+			samples_in = dac33->nsample;
+			samples = dac33->alarm_threshold;
+			samples += (samples_in - samples_out);
+
+			if (likely(samples > 0))
+				delay = samples > DAC33_BUFFER_SIZE_SAMPLES ?
+					DAC33_BUFFER_SIZE_SAMPLES : samples;
+			else
+				delay = 0;
+		}
+		break;
+	case DAC33_FIFO_MODE7:
+		spin_lock(&dac33->lock);
+		t0 = dac33->t_stamp1;
+		spin_unlock(&dac33->lock);
+		t_now = ktime_to_us(ktime_get());
+
+		/* We have not started to fill the FIFO yet, delay is 0 */
+		if (!t0)
+			goto out;
+
+		if (t_now <= t0) {
+			/*
+			 * Either the timestamps are messed or equal. Report
+			 * maximum delay
+			 */
+			delay = MODE7_UTHR;
+			goto out;
+		}
+
+		time_delta = t_now - t0;
+		if (time_delta <= dac33->mode7_us_to_lthr) {
+			/*
+			* Phase 1:
+			* After burst (draining phase)
+			*/
+			samples_out = US_TO_SAMPLES(
+					substream->runtime->rate,
+					time_delta);
+
+			if (likely(MODE7_UTHR > samples_out))
+				delay = MODE7_UTHR - samples_out;
+			else
+				delay = 0;
+		} else {
+			/*
+			* Phase 2:
+			* During burst operation
+			*/
+			time_delta = time_delta - dac33->mode7_us_to_lthr;
+
+			samples_out = US_TO_SAMPLES(
+					substream->runtime->rate,
+					time_delta);
+			samples_in = US_TO_SAMPLES(
+					dac33->burst_rate,
+					time_delta);
+			delay = MODE7_LTHR + samples_in - samples_out;
+
+			if (unlikely(delay > MODE7_UTHR))
+				delay = MODE7_UTHR;
+		}
+		break;
+	default:
+		dev_warn(codec->dev, "Unhandled FIFO mode: %d\n",
+							dac33->fifo_mode);
+		break;
+	}
+out:
+	return delay;
+}
+
 static int dac33_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 		int clk_id, unsigned int freq, int dir)
 {
 	struct snd_soc_codec *codec = codec_dai->codec;
-	struct tlv320dac33_priv *dac33 = codec->private_data;
+	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 	u8 ioc_reg, asrcb_reg;
 
 	ioc_reg = dac33_read_reg_cache(codec, DAC33_INT_OSC_CTRL);
@@ -1008,7 +1274,7 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai,
 			     unsigned int fmt)
 {
 	struct snd_soc_codec *codec = codec_dai->codec;
-	struct tlv320dac33_priv *dac33 = codec->private_data;
+	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 	u8 aictrl_a, aictrl_b;
 
 	aictrl_a = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_A);
@@ -1059,35 +1325,6 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai,
 	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)
 {
 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
@@ -1099,12 +1336,7 @@ static int dac33_soc_probe(struct platform_device *pdev)
 
 	codec = tlv320dac33_codec;
 	socdev->card->codec = codec;
-	dac33 = codec->private_data;
-
-	/* Power up the codec */
-	dac33_hard_power(codec, 1);
-	/* Set default configuration */
-	dac33_init_chip(codec);
+	dac33 = snd_soc_codec_get_drvdata(codec);
 
 	/* register pcms */
 	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
@@ -1122,12 +1354,6 @@ static int dac33_soc_probe(struct platform_device *pdev)
 
 	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;
 
 pcm_err:
@@ -1164,7 +1390,6 @@ static int dac33_soc_resume(struct platform_device *pdev)
 	struct snd_soc_codec *codec = socdev->card->codec;
 
 	dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-	dac33_set_bias_level(codec, codec->suspend_bias_level);
 
 	return 0;
 }
@@ -1182,10 +1407,11 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320dac33);
 #define DAC33_FORMATS	SNDRV_PCM_FMTBIT_S16_LE
 
 static struct snd_soc_dai_ops dac33_dai_ops = {
+	.startup	= dac33_startup,
 	.shutdown	= dac33_shutdown,
 	.hw_params	= dac33_hw_params,
-	.prepare	= dac33_pcm_prepare,
 	.trigger	= dac33_pcm_trigger,
+	.delay		= dac33_dai_delay,
 	.set_sysclk	= dac33_set_dai_sysclk,
 	.set_fmt	= dac33_set_dai_fmt,
 };
@@ -1221,11 +1447,12 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
 		return -ENOMEM;
 
 	codec = &dac33->codec;
-	codec->private_data = dac33;
+	snd_soc_codec_set_drvdata(codec, dac33);
 	codec->control_data = client;
 
 	mutex_init(&codec->mutex);
 	mutex_init(&dac33->mutex);
+	spin_lock_init(&dac33->lock);
 	INIT_LIST_HEAD(&codec->dapm_widgets);
 	INIT_LIST_HEAD(&codec->dapm_paths);
 
@@ -1236,6 +1463,7 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
 	codec->hw_write = (hw_write_t) i2c_master_send;
 	codec->bias_level = SND_SOC_BIAS_OFF;
 	codec->set_bias_level = dac33_set_bias_level;
+	codec->idle_bias_off = 1;
 	codec->dai = &dac33_dai;
 	codec->num_dai = 1;
 	codec->reg_cache_size = ARRAY_SIZE(dac33_reg);
@@ -1250,8 +1478,12 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
 
 	dac33->power_gpio = pdata->power_gpio;
 	dac33->burst_bclkdiv = pdata->burst_bclkdiv;
+	/* Pre calculate the burst rate */
+	dac33->burst_rate = BURST_BASEFREQ_HZ / dac33->burst_bclkdiv / 32;
+	dac33->keep_bclk = pdata->keep_bclk;
 	dac33->irq = client->irq;
 	dac33->nsample = NSAMPLE_MAX;
+	dac33->nsample_max = NSAMPLE_MAX;
 	/* Disable FIFO use by default */
 	dac33->fifo_mode = DAC33_FIFO_BYPASS;
 
@@ -1272,8 +1504,6 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
 			goto error_gpio;
 		}
 		gpio_direction_output(dac33->power_gpio, 0);
-	} else {
-		dac33->chip_power = 1;
 	}
 
 	/* Check if the IRQ number is valid and request it */
@@ -1311,12 +1541,14 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
 		goto err_get;
 	}
 
-	ret = regulator_bulk_enable(ARRAY_SIZE(dac33->supplies),
-				    dac33->supplies);
+	/* Read the tlv320dac33 ID registers */
+	ret = dac33_hard_power(codec, 1);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
-		goto err_enable;
+		dev_err(codec->dev, "Failed to power up codec: %d\n", ret);
+		goto error_codec;
 	}
+	dac33_read_id(codec);
+	dac33_hard_power(codec, 0);
 
 	ret = snd_soc_register_codec(codec);
 	if (ret != 0) {
@@ -1331,14 +1563,9 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
 		goto error_codec;
 	}
 
-	/* Shut down the codec for now */
-	dac33_hard_power(codec, 0);
-
 	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) {
@@ -1362,7 +1589,9 @@ static int __devexit dac33_i2c_remove(struct i2c_client *client)
 	struct tlv320dac33_priv *dac33;
 
 	dac33 = i2c_get_clientdata(client);
-	dac33_hard_power(&dac33->codec, 0);
+
+	if (unlikely(dac33->chip_power))
+		dac33_hard_power(&dac33->codec, 0);
 
 	if (dac33->power_gpio >= 0)
 		gpio_free(dac33->power_gpio);