Merge branch 'topic/asoc' into for-linus
[safe/jmp/linux-2.6] / sound / soc / codecs / tlv320dac33.c
index d1e0e81..65adc77 100644 (file)
 
 #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);