All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/5] ASoC: tlv320dac33: FIFO caused delay reporting and fixes
@ 2010-04-22 13:57 Peter Ujfalusi
  2010-04-22 13:57 ` [PATCH 1/5] ASoC: tlv320dac33: Fix for early interrupt in FIFO Mode1 Peter Ujfalusi
                   ` (4 more replies)
  0 siblings, 5 replies; 10+ messages in thread
From: Peter Ujfalusi @ 2010-04-22 13:57 UTC (permalink / raw)
  To: alsa-devel; +Cc: broonie, lrg

Hello,

The main feature of this series is the FIFO caused delay reporting on the DAC33
codec.
The main patch is quite big, but I don't think it can be divided further.

Short details of the actual implementation is in the commit message(s), and
I will not copy it here.

The values reported by the delay call has been verified by using one GPIO as a
signal, and printout from the kernel at the same time with the delay, than
based on the time scale on the scope several (>100) cases has been hand
calculated and the results were compared to the kernel reported values.
The difference were around (or less) the 10 samples, but during the bursts it
is much harder to count, but the reported value was reasonable accurate there
as well.

---
Peter Ujfalusi (5):
  ASoC: tlv320dac33: Fix for early interrupt in FIFO Mode1
  ASoC: tlv320dac33: Skip calculations in FIFO Bypass mode
  ASoC: tlv320dac33: Change magic numbers used in Mode7
  ASoC: tlv320dac33: Calculate the interface speed during bursts
  ASoC: tlv320dac33: FIFO caused delay reporting

 sound/soc/codecs/tlv320dac33.c |  249 ++++++++++++++++++++++++++++++++++++++--
 1 files changed, 237 insertions(+), 12 deletions(-)

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/5] ASoC: tlv320dac33: Fix for early interrupt in FIFO Mode1
  2010-04-22 13:57 [PATCH 0/5] ASoC: tlv320dac33: FIFO caused delay reporting and fixes Peter Ujfalusi
@ 2010-04-22 13:57 ` Peter Ujfalusi
  2010-04-22 16:26   ` Liam Girdwood
  2010-04-22 13:57 ` [PATCH 2/5] ASoC: tlv320dac33: Skip calculations in FIFO Bypass mode Peter Ujfalusi
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 10+ messages in thread
From: Peter Ujfalusi @ 2010-04-22 13:57 UTC (permalink / raw)
  To: alsa-devel; +Cc: broonie, lrg

Alarm threshold interrupt is triggered right after the
playback start.
This interrupt is recieved during the first burst period,
and caused the state machine to write additional nSample
command, which has to be avoided.
To fix this issue move the DAC33 interrupt unmasking
after we configured the PREFILL register with a small
delay.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com>
---
 sound/soc/codecs/tlv320dac33.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 824bb35..8a7265f 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -557,9 +557,12 @@ 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));
 		dac33_write16(codec, DAC33_PREFILL_MSB,
 				DAC33_THRREG(dac33->alarm_threshold));
+		/* Enable Alarm Threshold IRQ */
+		msleep(2);
+		dac33_write(codec, DAC33_FIFO_IRQ_MASK, DAC33_MAT);
 		break;
 	case DAC33_FIFO_MODE7:
 		dac33_write16(codec, DAC33_PREFILL_MSB,
@@ -782,7 +785,6 @@ 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 */
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/5] ASoC: tlv320dac33: Skip calculations in FIFO Bypass mode
  2010-04-22 13:57 [PATCH 0/5] ASoC: tlv320dac33: FIFO caused delay reporting and fixes Peter Ujfalusi
  2010-04-22 13:57 ` [PATCH 1/5] ASoC: tlv320dac33: Fix for early interrupt in FIFO Mode1 Peter Ujfalusi
@ 2010-04-22 13:57 ` Peter Ujfalusi
  2010-04-22 13:57 ` [PATCH 3/5] ASoC: tlv320dac33: Change magic numbers used in Mode7 Peter Ujfalusi
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 10+ messages in thread
From: Peter Ujfalusi @ 2010-04-22 13:57 UTC (permalink / raw)
  To: alsa-devel; +Cc: broonie, lrg

There is no need for calculations for FIFO bypass mode.
Just in case set the nsample maximum limit, which
has been done in the calculation phase.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com>
---
 sound/soc/codecs/tlv320dac33.c |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 8a7265f..d3ea0db 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -888,6 +888,10 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream)
 	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;
 
@@ -1243,6 +1247,7 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
 	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;
 
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/5] ASoC: tlv320dac33: Change magic numbers used in Mode7
  2010-04-22 13:57 [PATCH 0/5] ASoC: tlv320dac33: FIFO caused delay reporting and fixes Peter Ujfalusi
  2010-04-22 13:57 ` [PATCH 1/5] ASoC: tlv320dac33: Fix for early interrupt in FIFO Mode1 Peter Ujfalusi
  2010-04-22 13:57 ` [PATCH 2/5] ASoC: tlv320dac33: Skip calculations in FIFO Bypass mode Peter Ujfalusi
@ 2010-04-22 13:57 ` Peter Ujfalusi
  2010-04-22 13:57 ` [PATCH 4/5] ASoC: tlv320dac33: Calculate the interface speed during bursts Peter Ujfalusi
  2010-04-22 13:57 ` [PATCH 5/5] ASoC: tlv320dac33: FIFO caused delay reporting Peter Ujfalusi
  4 siblings, 0 replies; 10+ messages in thread
From: Peter Ujfalusi @ 2010-04-22 13:57 UTC (permalink / raw)
  To: alsa-devel; +Cc: broonie, lrg

Upper and Lower threshold values are used as magic
numbers. Replace them with defines for later use.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com>
---
 sound/soc/codecs/tlv320dac33.c |   11 ++++++-----
 1 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index d3ea0db..725be4c 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -50,6 +50,9 @@
 
 #define LATENCY_TIME_MS		20
 
+#define MODE7_LTHR		10
+#define MODE7_UTHR		(DAC33_BUFFER_SIZE_SAMPLES - 10)
+
 static struct snd_soc_codec *tlv320dac33_codec;
 
 enum dac33_state {
@@ -566,7 +569,7 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
 		break;
 	case DAC33_FIFO_MODE7:
 		dac33_write16(codec, DAC33_PREFILL_MSB,
-				DAC33_THRREG(10));
+				DAC33_THRREG(MODE7_LTHR));
 		break;
 	default:
 		dev_warn(codec->dev, "Unhandled FIFO mode: %d\n",
@@ -866,10 +869,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;
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 4/5] ASoC: tlv320dac33: Calculate the interface speed during bursts
  2010-04-22 13:57 [PATCH 0/5] ASoC: tlv320dac33: FIFO caused delay reporting and fixes Peter Ujfalusi
                   ` (2 preceding siblings ...)
  2010-04-22 13:57 ` [PATCH 3/5] ASoC: tlv320dac33: Change magic numbers used in Mode7 Peter Ujfalusi
@ 2010-04-22 13:57 ` Peter Ujfalusi
  2010-04-22 13:57 ` [PATCH 5/5] ASoC: tlv320dac33: FIFO caused delay reporting Peter Ujfalusi
  4 siblings, 0 replies; 10+ messages in thread
From: Peter Ujfalusi @ 2010-04-22 13:57 UTC (permalink / raw)
  To: alsa-devel; +Cc: broonie, lrg

When the DAC33 FIFO is in use the dai interface is running in
much higher speed than the sampling frequency.
Calculate the rate based on the internal base frequency and
the bclk divider.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com>
---
 sound/soc/codecs/tlv320dac33.c |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 725be4c..7a3dea6 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -53,6 +53,8 @@
 #define MODE7_LTHR		10
 #define MODE7_UTHR		(DAC33_BUFFER_SIZE_SAMPLES - 10)
 
+#define BURST_BASEFREQ_HZ	49152000
+
 static struct snd_soc_codec *tlv320dac33_codec;
 
 enum dac33_state {
@@ -95,6 +97,7 @@ 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 */
@@ -1245,6 +1248,8 @@ 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;
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 5/5] ASoC: tlv320dac33: FIFO caused delay reporting
  2010-04-22 13:57 [PATCH 0/5] ASoC: tlv320dac33: FIFO caused delay reporting and fixes Peter Ujfalusi
                   ` (3 preceding siblings ...)
  2010-04-22 13:57 ` [PATCH 4/5] ASoC: tlv320dac33: Calculate the interface speed during bursts Peter Ujfalusi
@ 2010-04-22 13:57 ` Peter Ujfalusi
  2010-04-22 17:57   ` Liam Girdwood
  4 siblings, 1 reply; 10+ messages in thread
From: Peter Ujfalusi @ 2010-04-22 13:57 UTC (permalink / raw)
  To: alsa-devel; +Cc: broonie, lrg

Delay reporting for the three implemented DAC33 FIFO modes.
DAC33 has FIFO depth status register(s), but it can not be used, since
inside of pcm_pointer we can not send I2C commands.
Timestamp based estimation need to be used. The method of calculating
the delay depends on the active FIFO mode.

Bypass mode: FIFO is bypassed, report 0 as delay

Mode1: nSample fill mode. In this mode I need to use two timestamp
ts1: taken when the interrupt has been received
ts2: taken before writing to nSample register.

Interrupts are coming when DAC33 FIFO depth goes under alarm threshold.

Phase1: when we received the alarm threshold, but our workqueue has
        not been executed (safeguard phase). Just count the played out
        samples since ts1 and subtract it from the alarm threshold
        value.
Phase2: During nSample burst (after writing to nSample register), count
        the played out samples since ts1, count the samples received
        since ts2 (in a burst). Estimate the FIFO depth using these and
        alarm threshold value.
Phase3: Draining phase (after the burst read), count the played out
        samples since ts1. Estimate the FIFO depth using the nSample
        configuration and the alarm threshold value.

Mode7: Threshold based fill mode. In this mode one timestamp is enough.
ts1: taken when the interrupt has been received

Interrupts are coming when DAC33 FIFO depth reaches upper threshold.

Phase1: Draining phase (after the burst), counting the played out
        samples since ts1, and subtract it from the upper threshold
        value.
Phase2: During burst operation. Using the pre calculated time needed to
        play out samples from the buffer during the drain period (from
        upper to lower threshold), move the time window to cover the
        estimated time from the burst start to the current time.
        Calculate the samples played out since lower threshold and also
        the samples received during the same time.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com>
---
 sound/soc/codecs/tlv320dac33.c |  222 +++++++++++++++++++++++++++++++++++++++-
 1 files changed, 217 insertions(+), 5 deletions(-)

diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 7a3dea6..e937d32 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -55,6 +55,13 @@
 
 #define BURST_BASEFREQ_HZ	49152000
 
+#define SAMPLES_TO_US(rate, samples) \
+	(1000000000 / ((rate * 1000) / samples))
+
+#define US_TO_SAMPLES(rate, ns) \
+	(rate / (1000000 / ns))
+
+
 static struct snd_soc_codec *tlv320dac33_codec;
 
 enum dac33_state {
@@ -101,6 +108,14 @@ struct tlv320dac33_priv {
 
 	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;
 };
 
@@ -390,10 +405,14 @@ static int dac33_set_nsample(struct snd_kcontrol *kcontrol,
 		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;
 }
@@ -564,6 +583,13 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
 	case DAC33_FIFO_MODE1:
 		dac33_write16(codec, DAC33_NSAMPLE_MSB,
 			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 */
@@ -571,8 +597,18 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
 		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(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",
@@ -589,6 +625,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;
@@ -641,7 +682,13 @@ static irqreturn_t dac33_interrupt_handler(int irq, void *dev)
 	struct snd_soc_codec *codec = dev;
 	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 
-	queue_work(dac33->dac33_wq, &dac33->work);
+	spin_lock(&dac33->lock);
+	dac33->t_stamp1 = ktime_to_us(ktime_get());
+	spin_unlock(&dac33->lock);
+
+	/* Do not schedule the workqueue in Mode7 */
+	if (dac33->fifo_mode != DAC33_FIFO_MODE7)
+		queue_work(dac33->dac33_wq, &dac33->work);
 
 	return IRQ_HANDLED;
 }
@@ -793,8 +840,8 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
 			    DAC33_ATM(DAC33_FIFO_IRQ_MODE_LEVEL));
 		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 */
@@ -929,6 +976,24 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream)
 
 	if (dac33->nsample > dac33->nsample_max)
 		dac33->nsample = dac33->nsample_max;
+
+	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;
+	}
+
 }
 
 static int dac33_pcm_prepare(struct snd_pcm_substream *substream,
@@ -973,6 +1038,151 @@ 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)
 {
@@ -1184,6 +1394,7 @@ static struct snd_soc_dai_ops dac33_dai_ops = {
 	.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,
 };
@@ -1224,6 +1435,7 @@ static int __devinit dac33_i2c_probe(struct i2c_client *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);
 
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/5] ASoC: tlv320dac33: Fix for early interrupt in FIFO Mode1
  2010-04-22 13:57 ` [PATCH 1/5] ASoC: tlv320dac33: Fix for early interrupt in FIFO Mode1 Peter Ujfalusi
@ 2010-04-22 16:26   ` Liam Girdwood
  2010-04-23  5:33     ` Peter Ujfalusi
  0 siblings, 1 reply; 10+ messages in thread
From: Liam Girdwood @ 2010-04-22 16:26 UTC (permalink / raw)
  To: Peter Ujfalusi; +Cc: alsa-devel, broonie

On Thu, 2010-04-22 at 16:57 +0300, Peter Ujfalusi wrote:
> Alarm threshold interrupt is triggered right after the
> playback start.
> This interrupt is recieved during the first burst period,
> and caused the state machine to write additional nSample
> command, which has to be avoided.
> To fix this issue move the DAC33 interrupt unmasking
> after we configured the PREFILL register with a small
> delay.
> 
> Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com>
> ---
>  sound/soc/codecs/tlv320dac33.c |    6 ++++--
>  1 files changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
> index 824bb35..8a7265f 100644
> --- a/sound/soc/codecs/tlv320dac33.c
> +++ b/sound/soc/codecs/tlv320dac33.c
> @@ -557,9 +557,12 @@ 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));
>  		dac33_write16(codec, DAC33_PREFILL_MSB,
>  				DAC33_THRREG(dac33->alarm_threshold));
> +		/* Enable Alarm Threshold IRQ */
> +		msleep(2);

Does this sleep depend on rate/frame_size in any way ?

Liam

-- 
Freelance Developer, SlimLogic Ltd
ASoC and Voltage Regulator Maintainer.
http://www.slimlogic.co.uk

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 5/5] ASoC: tlv320dac33: FIFO caused delay reporting
  2010-04-22 13:57 ` [PATCH 5/5] ASoC: tlv320dac33: FIFO caused delay reporting Peter Ujfalusi
@ 2010-04-22 17:57   ` Liam Girdwood
  2010-04-23  5:52     ` Peter Ujfalusi
  0 siblings, 1 reply; 10+ messages in thread
From: Liam Girdwood @ 2010-04-22 17:57 UTC (permalink / raw)
  To: Peter Ujfalusi; +Cc: alsa-devel, broonie

On Thu, 2010-04-22 at 16:57 +0300, Peter Ujfalusi wrote:
> Delay reporting for the three implemented DAC33 FIFO modes.
> DAC33 has FIFO depth status register(s), but it can not be used, since
> inside of pcm_pointer we can not send I2C commands.
> Timestamp based estimation need to be used. The method of calculating
> the delay depends on the active FIFO mode.
> 
> Bypass mode: FIFO is bypassed, report 0 as delay
> 
> Mode1: nSample fill mode. In this mode I need to use two timestamp
> ts1: taken when the interrupt has been received
> ts2: taken before writing to nSample register.
> 
> Interrupts are coming when DAC33 FIFO depth goes under alarm threshold.
> 
> Phase1: when we received the alarm threshold, but our workqueue has
>         not been executed (safeguard phase). Just count the played out
>         samples since ts1 and subtract it from the alarm threshold
>         value.
> Phase2: During nSample burst (after writing to nSample register), count
>         the played out samples since ts1, count the samples received
>         since ts2 (in a burst). Estimate the FIFO depth using these and
>         alarm threshold value.
> Phase3: Draining phase (after the burst read), count the played out
>         samples since ts1. Estimate the FIFO depth using the nSample
>         configuration and the alarm threshold value.
> 
> Mode7: Threshold based fill mode. In this mode one timestamp is enough.
> ts1: taken when the interrupt has been received
> 
> Interrupts are coming when DAC33 FIFO depth reaches upper threshold.
> 
> Phase1: Draining phase (after the burst), counting the played out
>         samples since ts1, and subtract it from the upper threshold
>         value.
> Phase2: During burst operation. Using the pre calculated time needed to
>         play out samples from the buffer during the drain period (from
>         upper to lower threshold), move the time window to cover the
>         estimated time from the burst start to the current time.
>         Calculate the samples played out since lower threshold and also
>         the samples received during the same time.
> 
> Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com>
> ---
>  sound/soc/codecs/tlv320dac33.c |  222 +++++++++++++++++++++++++++++++++++++++-
>  1 files changed, 217 insertions(+), 5 deletions(-)
> 
> diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
> index 7a3dea6..e937d32 100644
> --- a/sound/soc/codecs/tlv320dac33.c
> +++ b/sound/soc/codecs/tlv320dac33.c
> @@ -55,6 +55,13 @@
>  
>  #define BURST_BASEFREQ_HZ	49152000
>  
> +#define SAMPLES_TO_US(rate, samples) \
> +	(1000000000 / ((rate * 1000) / samples))
> +
> +#define US_TO_SAMPLES(rate, ns) \
> +	(rate / (1000000 / ns))
> +
> +

Is it microseconds or nanoseconds here (us or ns) ? 

>  static struct snd_soc_codec *tlv320dac33_codec;
>  
>  enum dac33_state {
> @@ -101,6 +108,14 @@ struct tlv320dac33_priv {
>  
>  	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;
>  };
>  
> @@ -390,10 +405,14 @@ static int dac33_set_nsample(struct snd_kcontrol *kcontrol,
>  		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;
>  }
> @@ -564,6 +583,13 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
>  	case DAC33_FIFO_MODE1:
>  		dac33_write16(codec, DAC33_NSAMPLE_MSB,
>  			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 */
> @@ -571,8 +597,18 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
>  		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(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",
> @@ -589,6 +625,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;
> @@ -641,7 +682,13 @@ static irqreturn_t dac33_interrupt_handler(int irq, void *dev)
>  	struct snd_soc_codec *codec = dev;
>  	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
>  
> -	queue_work(dac33->dac33_wq, &dac33->work);
> +	spin_lock(&dac33->lock);
> +	dac33->t_stamp1 = ktime_to_us(ktime_get());
> +	spin_unlock(&dac33->lock);
> +
> +	/* Do not schedule the workqueue in Mode7 */
> +	if (dac33->fifo_mode != DAC33_FIFO_MODE7)
> +		queue_work(dac33->dac33_wq, &dac33->work);
>  
>  	return IRQ_HANDLED;
>  }
> @@ -793,8 +840,8 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
>  			    DAC33_ATM(DAC33_FIFO_IRQ_MODE_LEVEL));
>  		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 */
> @@ -929,6 +976,24 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream)
>  
>  	if (dac33->nsample > dac33->nsample_max)
>  		dac33->nsample = dac33->nsample_max;
> +
> +	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;
> +	}
> +
>  }
>  
>  static int dac33_pcm_prepare(struct snd_pcm_substream *substream,
> @@ -973,6 +1038,151 @@ 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;
> +

We may need some logic here to handle any underruns (e.g. recalc our
delay based on underrun), as ALSA will re-call prepare() and there may
still be data playing through the DAC33 FIFO.

Have you tried forcing underruns to see how it behaves ?

Liam


-- 
Freelance Developer, SlimLogic Ltd
ASoC and Voltage Regulator Maintainer.
http://www.slimlogic.co.uk

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/5] ASoC: tlv320dac33: Fix for early interrupt in FIFO Mode1
  2010-04-22 16:26   ` Liam Girdwood
@ 2010-04-23  5:33     ` Peter Ujfalusi
  0 siblings, 0 replies; 10+ messages in thread
From: Peter Ujfalusi @ 2010-04-23  5:33 UTC (permalink / raw)
  To: ext Liam Girdwood; +Cc: alsa-devel, broonie

On Thursday 22 April 2010 19:26:51 ext Liam Girdwood wrote:
> > +		/* Enable Alarm Threshold IRQ */
> > +		msleep(2);
> 
> Does this sleep depend on rate/frame_size in any way ?

It is actually depends on the alarm_threshold and the burst rate.
We only want to enable the interrupt, when the FIFO depth is higher than the 
alarm threshold, thus we will not receive the extra interrupt.
I have now the corrected version.

Thanks,
Péter
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 5/5] ASoC: tlv320dac33: FIFO caused delay reporting
  2010-04-22 17:57   ` Liam Girdwood
@ 2010-04-23  5:52     ` Peter Ujfalusi
  0 siblings, 0 replies; 10+ messages in thread
From: Peter Ujfalusi @ 2010-04-23  5:52 UTC (permalink / raw)
  To: ext Liam Girdwood; +Cc: alsa-devel, broonie

On Thursday 22 April 2010 20:57:54 ext Liam Girdwood wrote:
> > +#define SAMPLES_TO_US(rate, samples) \
> > +	(1000000000 / ((rate * 1000) / samples))
> > +
> > +#define US_TO_SAMPLES(rate, ns) \
> > +	(rate / (1000000 / ns))
> > +
> > +
> 
> Is it microseconds or nanoseconds here (us or ns) ?

It is microseconds (us). I have initially used nanoseconds, but it was a bit 
overkill, and using usec gives close enough resolution.
I'll change the ns to us in the macro.

> > +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;
> > +
> 
> We may need some logic here to handle any underruns (e.g. recalc our
> delay based on underrun), as ALSA will re-call prepare() and there may
> still be data playing through the DAC33 FIFO.

I guess we anyway have the problem with the stopping. Trigger:stop can come 
anytime, and we supposed to stop even if the FIFO is almost full.
What happens now, is that I only set the codec to FLUSH mode, which will allow 
us to play the remaining samples out, but the codec will not ask for new 
samples. The codec than will be stopped at set_bias:STANDBY, so we will 
eventually play out everything.

What this timestamping will allow us to do is to detect the underrun situation 
inside of the codec, and try to recover from it. If underrun happens, than the 
codec will not ask for new data (the alarm interrupt will not re-trigger). This 
breaks the playback. In this case we have to go back to prefill state, and that 
should solve the problem, but I have not analyzed the pattern, which leads to 
deadlock (but I have seen it several times).

> 
> Have you tried forcing underruns to see how it behaves ?

No I have not forced it, but it happened few times, especially when there were 
heavy traffic on the I2C bus.
What happens is that I actually reset the codec in pcm_prepare, so we do loose 
some samples for sure.

When the codec is in mode1, the interrupts (and the nSample writes) are not in a 
constant distance, over time the delays are compensated by this movement of the 
burst starts.
Overnight playback tests resulted no underruns so far.


> 
> Liam

-- 
Péter
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2010-04-23  5:52 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-04-22 13:57 [PATCH 0/5] ASoC: tlv320dac33: FIFO caused delay reporting and fixes Peter Ujfalusi
2010-04-22 13:57 ` [PATCH 1/5] ASoC: tlv320dac33: Fix for early interrupt in FIFO Mode1 Peter Ujfalusi
2010-04-22 16:26   ` Liam Girdwood
2010-04-23  5:33     ` Peter Ujfalusi
2010-04-22 13:57 ` [PATCH 2/5] ASoC: tlv320dac33: Skip calculations in FIFO Bypass mode Peter Ujfalusi
2010-04-22 13:57 ` [PATCH 3/5] ASoC: tlv320dac33: Change magic numbers used in Mode7 Peter Ujfalusi
2010-04-22 13:57 ` [PATCH 4/5] ASoC: tlv320dac33: Calculate the interface speed during bursts Peter Ujfalusi
2010-04-22 13:57 ` [PATCH 5/5] ASoC: tlv320dac33: FIFO caused delay reporting Peter Ujfalusi
2010-04-22 17:57   ` Liam Girdwood
2010-04-23  5:52     ` Peter Ujfalusi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.