summaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/tlv320dac33.c
diff options
context:
space:
mode:
authorGrant Likely <grant.likely@secretlab.ca>2010-05-22 08:36:56 +0200
committerGrant Likely <grant.likely@secretlab.ca>2010-05-22 08:36:56 +0200
commitcf9b59e9d3e008591d1f54830f570982bb307a0d (patch)
tree113478ce8fd8c832ba726ffdf59b82cb46356476 /sound/soc/codecs/tlv320dac33.c
parentof: change of_match_device to work with struct device (diff)
parentfbmem: avoid printk format warning with 32-bit resources (diff)
downloadlinux-cf9b59e9d3e008591d1f54830f570982bb307a0d.tar.xz
linux-cf9b59e9d3e008591d1f54830f570982bb307a0d.zip
Merge remote branch 'origin' into secretlab/next-devicetree
Merging in current state of Linus' tree to deal with merge conflicts and build failures in vio.c after merge. Conflicts: drivers/i2c/busses/i2c-cpm.c drivers/i2c/busses/i2c-mpc.c drivers/net/gianfar.c Also fixed up one line in arch/powerpc/kernel/vio.c to use the correct node pointer. Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
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);