Merge remote-tracking branches 'asoc/fix/da7219-pops' and 'asoc/fix/qcom' into asoc...
authorMark Brown <broonie@kernel.org>
Mon, 12 Dec 2016 15:52:37 +0000 (15:52 +0000)
committerMark Brown <broonie@kernel.org>
Mon, 12 Dec 2016 15:52:37 +0000 (15:52 +0000)
1  2  3 
sound/soc/codecs/da7219.c
sound/soc/qcom/lpass-platform.c

index cf37936bfe3aaaf6b29cb1f78c9c54f80a2b40b7,2610fc5cff686e413ea9aac87519a02e6e97d5c4,1152aa5e7c394208d6e42f04a2c4d44c8b0ea906..99601627f83cf6fe0dc83249139058ce6b15611e
@@@@ -823,6 -823,85 -823,6 +823,85 @@@@ static int da7219_dai_event(struct snd_
        }
   }
   
+ +static int da7219_settling_event(struct snd_soc_dapm_widget *w,
+ +                              struct snd_kcontrol *kcontrol, int event)
+ +{
+ +     switch (event) {
+ +     case SND_SOC_DAPM_POST_PMU:
+ +     case SND_SOC_DAPM_POST_PMD:
+ +             msleep(DA7219_SETTLING_DELAY);
+ +             break;
+ +     default:
+ +             break;
+ +     }
+ +
+ +     return 0;
+ +}
+ +
+ +static int da7219_mixout_event(struct snd_soc_dapm_widget *w,
+ +                            struct snd_kcontrol *kcontrol, int event)
+ +{
+ +     struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ +     u8 hp_ctrl, min_gain_mask;
+ +
+ +     switch (w->reg) {
+ +     case DA7219_MIXOUT_L_CTRL:
+ +             hp_ctrl = DA7219_HP_L_CTRL;
+ +             min_gain_mask = DA7219_HP_L_AMP_MIN_GAIN_EN_MASK;
+ +             break;
+ +     case DA7219_MIXOUT_R_CTRL:
+ +             hp_ctrl = DA7219_HP_R_CTRL;
+ +             min_gain_mask = DA7219_HP_R_AMP_MIN_GAIN_EN_MASK;
+ +             break;
+ +     default:
+ +             return -EINVAL;
+ +     }
+ +
+ +     switch (event) {
+ +     case SND_SOC_DAPM_PRE_PMD:
+ +             /* Enable minimum gain on HP to avoid pops */
+ +             snd_soc_update_bits(codec, hp_ctrl, min_gain_mask,
+ +                                 min_gain_mask);
+ +
+ +             msleep(DA7219_MIN_GAIN_DELAY);
+ +
+ +             break;
+ +     case SND_SOC_DAPM_POST_PMU:
+ +             /* Remove minimum gain on HP */
+ +             snd_soc_update_bits(codec, hp_ctrl, min_gain_mask, 0);
+ +
+ +             break;
+ +     }
+ +
+ +     return 0;
+ +}
+ +
+ +static int da7219_gain_ramp_event(struct snd_soc_dapm_widget *w,
+ +                               struct snd_kcontrol *kcontrol, int event)
+ +{
+ +     struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ +     struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+ +
+ +     switch (event) {
+ +     case SND_SOC_DAPM_PRE_PMU:
+ +     case SND_SOC_DAPM_PRE_PMD:
+ +             /* Ensure nominal gain ramping for DAPM sequence */
+ +             da7219->gain_ramp_ctrl =
+ +                     snd_soc_read(codec, DA7219_GAIN_RAMP_CTRL);
+ +             snd_soc_write(codec, DA7219_GAIN_RAMP_CTRL,
+ +                           DA7219_GAIN_RAMP_RATE_NOMINAL);
+ +             break;
+ +     case SND_SOC_DAPM_POST_PMU:
+ +     case SND_SOC_DAPM_POST_PMD:
+ +             /* Restore previous gain ramp settings */
+ +             snd_soc_write(codec, DA7219_GAIN_RAMP_CTRL,
+ +                           da7219->gain_ramp_ctrl);
+ +             break;
+ +     }
+ +
+ +     return 0;
+ +}
+ +
   
   /*
    * DAPM Widgets
@@@@ -880,8 -959,7 -880,7 +959,8 @@@@ static const struct snd_soc_dapm_widge
                            SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
   
        /* DAI */
 --     SND_SOC_DAPM_AIF_OUT("DAIOUT", "Capture", 0, SND_SOC_NOPM, 0, 0),
 ++     SND_SOC_DAPM_AIF_OUT("DAIOUT", "Capture", 0, DA7219_DAI_TDM_CTRL,
 ++                          DA7219_DAI_OE_SHIFT, DA7219_NO_INVERT),
        SND_SOC_DAPM_AIF_IN("DAIIN", "Playback", 0, SND_SOC_NOPM, 0, 0),
   
        /* Output Muxes */
                           ARRAY_SIZE(da7219_st_out_filtr_mix_controls)),
   
        /* DACs */
- -     SND_SOC_DAPM_DAC("DACL", NULL, DA7219_DAC_L_CTRL, DA7219_DAC_L_EN_SHIFT,
- -                      DA7219_NO_INVERT),
- -     SND_SOC_DAPM_DAC("DACR", NULL, DA7219_DAC_R_CTRL, DA7219_DAC_R_EN_SHIFT,
- -                      DA7219_NO_INVERT),
+ +     SND_SOC_DAPM_DAC_E("DACL", NULL, DA7219_DAC_L_CTRL,
+ +                        DA7219_DAC_L_EN_SHIFT, DA7219_NO_INVERT,
+ +                        da7219_settling_event,
+ +                        SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ +     SND_SOC_DAPM_DAC_E("DACR", NULL, DA7219_DAC_R_CTRL,
+ +                        DA7219_DAC_R_EN_SHIFT, DA7219_NO_INVERT,
+ +                        da7219_settling_event,
+ +                        SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
   
        /* Output PGAs */
- -     SND_SOC_DAPM_PGA("Mixout Left PGA", DA7219_MIXOUT_L_CTRL,
- -                      DA7219_MIXOUT_L_AMP_EN_SHIFT, DA7219_NO_INVERT,
- -                      NULL, 0),
- -     SND_SOC_DAPM_PGA("Mixout Right PGA", DA7219_MIXOUT_R_CTRL,
- -                      DA7219_MIXOUT_R_AMP_EN_SHIFT, DA7219_NO_INVERT,
- -                      NULL, 0),
- -     SND_SOC_DAPM_PGA("Headphone Left PGA", DA7219_HP_L_CTRL,
- -                      DA7219_HP_L_AMP_EN_SHIFT, DA7219_NO_INVERT, NULL, 0),
- -     SND_SOC_DAPM_PGA("Headphone Right PGA", DA7219_HP_R_CTRL,
- -                      DA7219_HP_R_AMP_EN_SHIFT, DA7219_NO_INVERT, NULL, 0),
+ +     SND_SOC_DAPM_PGA_E("Mixout Left PGA", DA7219_MIXOUT_L_CTRL,
+ +                        DA7219_MIXOUT_L_AMP_EN_SHIFT, DA7219_NO_INVERT,
+ +                        NULL, 0, da7219_mixout_event,
+ +                        SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ +     SND_SOC_DAPM_PGA_E("Mixout Right PGA", DA7219_MIXOUT_R_CTRL,
+ +                        DA7219_MIXOUT_R_AMP_EN_SHIFT, DA7219_NO_INVERT,
+ +                        NULL, 0, da7219_mixout_event,
+ +                        SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ +     SND_SOC_DAPM_SUPPLY_S("Headphone Left PGA", 1, DA7219_HP_L_CTRL,
+ +                           DA7219_HP_L_AMP_EN_SHIFT, DA7219_NO_INVERT,
+ +                           da7219_settling_event,
+ +                           SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ +     SND_SOC_DAPM_SUPPLY_S("Headphone Right PGA", 1, DA7219_HP_R_CTRL,
+ +                           DA7219_HP_R_AMP_EN_SHIFT, DA7219_NO_INVERT,
+ +                           da7219_settling_event,
+ +                           SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
   
        /* Output Supplies */
- -     SND_SOC_DAPM_SUPPLY("Charge Pump", DA7219_CP_CTRL, DA7219_CP_EN_SHIFT,
- -                         DA7219_NO_INVERT, NULL, 0),
+ +     SND_SOC_DAPM_SUPPLY_S("Charge Pump", 0, DA7219_CP_CTRL,
+ +                           DA7219_CP_EN_SHIFT, DA7219_NO_INVERT,
+ +                           da7219_settling_event,
+ +                           SND_SOC_DAPM_POST_PMU),
   
        /* Outputs */
        SND_SOC_DAPM_OUTPUT("HPL"),
        SND_SOC_DAPM_OUTPUT("HPR"),
+ +
+ +     /* Pre/Post Power */
+ +     SND_SOC_DAPM_PRE("Pre Power Gain Ramp", da7219_gain_ramp_event),
+ +     SND_SOC_DAPM_POST("Post Power Gain Ramp", da7219_gain_ramp_event),
   };
   
   
@@@@ -1003,8 -1097,8 -1002,8 +1098,8 @@@@ static const struct snd_soc_dapm_route 
        {"Mixout Left PGA", NULL, "DACL"},
        {"Mixout Right PGA", NULL, "DACR"},
   
- -     {"Headphone Left PGA", NULL, "Mixout Left PGA"},
- -     {"Headphone Right PGA", NULL, "Mixout Right PGA"},
+ +     {"HPL", NULL, "Mixout Left PGA"},
+ +     {"HPR", NULL, "Mixout Right PGA"},
   
        {"HPL", NULL, "Headphone Left PGA"},
        {"HPR", NULL, "Headphone Right PGA"},
@@@@ -1712,6 -1806,14 -1711,6 +1807,14 @@@@ static int da7219_probe(struct snd_soc_
                            DA7219_HP_R_AMP_RAMP_EN_MASK,
                            DA7219_HP_R_AMP_RAMP_EN_MASK);
   
+ +     /* Default minimum gain on HP to avoid pops during DAPM sequencing */
+ +     snd_soc_update_bits(codec, DA7219_HP_L_CTRL,
+ +                         DA7219_HP_L_AMP_MIN_GAIN_EN_MASK,
+ +                         DA7219_HP_L_AMP_MIN_GAIN_EN_MASK);
+ +     snd_soc_update_bits(codec, DA7219_HP_R_CTRL,
+ +                         DA7219_HP_R_AMP_MIN_GAIN_EN_MASK,
+ +                         DA7219_HP_R_AMP_MIN_GAIN_EN_MASK);
+ +
        /* Default infinite tone gen, start/stop by Kcontrol */
        snd_soc_write(codec, DA7219_TONE_GEN_CYCLES, DA7219_BEEP_CYCLES_MASK);
   
index b392e51de94d173a20b130ad663b6af7c1e25f19,e2ff538a8aa5b63c4117f35365c39057b1f5360a,e223bc90b2ef7fed9df0c07c823c104e32e97dba..420d200f9a0533bd335224784c2e7933a0c8c3b1
@@@@ -61,41 -61,7 -61,43 +61,44 @@@@ static int lpass_platform_pcmops_open(s
   {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
 -      int ret;
 +      struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
 +      struct lpass_data *drvdata =
 +              snd_soc_platform_get_drvdata(soc_runtime->platform);
 +      struct lpass_variant *v = drvdata->variant;
 +      int ret, dma_ch, dir = substream->stream;
 +      struct lpass_pcm_data *data;
 + 
 +      data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL);
 +      if (!data)
 +              return -ENOMEM;
 + 
 +      data->i2s_port = cpu_dai->driver->id;
 +      runtime->private_data = data;
 + 
 ++     dma_ch = 0;
 +      if (v->alloc_dma_channel)
 +              dma_ch = v->alloc_dma_channel(drvdata, dir);
++      else
++              dma_ch = 0;
++ 
 +      if (dma_ch < 0)
 +              return dma_ch;
 + 
 +      drvdata->substream[dma_ch] = substream;
 + 
 +      ret = regmap_write(drvdata->lpaif_map,
 +                      LPAIF_DMACTL_REG(v, dma_ch, dir), 0);
 +      if (ret) {
 +              dev_err(soc_runtime->dev,
 +                      "%s() error writing to rdmactl reg: %d\n",
 +                      __func__, ret);
 +                      return ret;
 +      }
 + 
 +      if (dir == SNDRV_PCM_STREAM_PLAYBACK)
 +              data->rdma_ch = dma_ch;
 +      else
 +              data->wrdma_ch = dma_ch;
   
        snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware);
   
        return 0;
   }
   
 + static int lpass_platform_pcmops_close(struct snd_pcm_substream *substream)
 + {
 +      struct snd_pcm_runtime *runtime = substream->runtime;
 +      struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
 +      struct lpass_data *drvdata =
 +              snd_soc_platform_get_drvdata(soc_runtime->platform);
 +      struct lpass_variant *v = drvdata->variant;
 +      struct lpass_pcm_data *data;
 +      int dma_ch, dir = substream->stream;
 + 
 +      data = runtime->private_data;
 +      v = drvdata->variant;
 + 
 +      if (dir == SNDRV_PCM_STREAM_PLAYBACK)
 +              dma_ch = data->rdma_ch;
 +      else
 +              dma_ch = data->wrdma_ch;
 + 
 +      drvdata->substream[dma_ch] = NULL;
 + 
 +      if (v->free_dma_channel)
 +              v->free_dma_channel(drvdata, dma_ch);
 + 
 +      return 0;
 + }
 + 
   static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
                struct snd_pcm_hw_params *params)
   {
        struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
        struct lpass_data *drvdata =
                snd_soc_platform_get_drvdata(soc_runtime->platform);
 -      struct lpass_pcm_data *pcm_data = drvdata->private_data;
 +      struct snd_pcm_runtime *rt = substream->runtime;
 +      struct lpass_pcm_data *pcm_data = rt->private_data;
        struct lpass_variant *v = drvdata->variant;
        snd_pcm_format_t format = params_format(params);
        unsigned int channels = params_channels(params);
@@@@ -240,8 -179,7 -242,8 +243,8 @@@@ static int lpass_platform_pcmops_hw_fre
        struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
        struct lpass_data *drvdata =
                snd_soc_platform_get_drvdata(soc_runtime->platform);
 -      struct lpass_pcm_data *pcm_data = drvdata->private_data;
 +      struct snd_pcm_runtime *rt = substream->runtime;
 +      struct lpass_pcm_data *pcm_data = rt->private_data;
        struct lpass_variant *v = drvdata->variant;
        unsigned int reg;
        int ret;
@@@@ -265,8 -203,7 -267,8 +268,8 @@@@ static int lpass_platform_pcmops_prepar
        struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
        struct lpass_data *drvdata =
                snd_soc_platform_get_drvdata(soc_runtime->platform);
 -      struct lpass_pcm_data *pcm_data = drvdata->private_data;
 +      struct snd_pcm_runtime *rt = substream->runtime;
 +      struct lpass_pcm_data *pcm_data = rt->private_data;
        struct lpass_variant *v = drvdata->variant;
        int ret, ch, dir = substream->stream;
   
@@@@ -320,8 -257,7 -322,8 +323,8 @@@@ static int lpass_platform_pcmops_trigge
        struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
        struct lpass_data *drvdata =
                snd_soc_platform_get_drvdata(soc_runtime->platform);
 -      struct lpass_pcm_data *pcm_data = drvdata->private_data;
 +      struct snd_pcm_runtime *rt = substream->runtime;
 +      struct lpass_pcm_data *pcm_data = rt->private_data;
        struct lpass_variant *v = drvdata->variant;
        int ret, ch, dir = substream->stream;
   
@@@@ -397,8 -333,7 -399,8 +400,8 @@@@ static snd_pcm_uframes_t lpass_platform
        struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
        struct lpass_data *drvdata =
                        snd_soc_platform_get_drvdata(soc_runtime->platform);
 -      struct lpass_pcm_data *pcm_data = drvdata->private_data;
 +      struct snd_pcm_runtime *rt = substream->runtime;
 +      struct lpass_pcm_data *pcm_data = rt->private_data;
        struct lpass_variant *v = drvdata->variant;
        unsigned int base_addr, curr_addr;
        int ret, ch, dir = substream->stream;
@@@@ -439,7 -374,6 -441,7 +442,7 @@@@ static int lpass_platform_pcmops_mmap(s
   
   static const struct snd_pcm_ops lpass_platform_pcm_ops = {
        .open           = lpass_platform_pcmops_open,
 +      .close          = lpass_platform_pcmops_close,
        .ioctl          = snd_pcm_lib_ioctl,
        .hw_params      = lpass_platform_pcmops_hw_params,
        .hw_free        = lpass_platform_pcmops_hw_free,
@@@@ -536,45 -470,117 -538,45 +539,45 @@@@ static int lpass_platform_pcm_new(struc
   {
        struct snd_pcm *pcm = soc_runtime->pcm;
        struct snd_pcm_substream *psubstream, *csubstream;
 -      struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
 -      struct lpass_data *drvdata =
 -              snd_soc_platform_get_drvdata(soc_runtime->platform);
 -      struct lpass_variant *v = drvdata->variant;
        int ret = -EINVAL;
 -      struct lpass_pcm_data *data;
        size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
   
 -      data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL);
 -      if (!data)
 -              return -ENOMEM;
 - 
 -      data->i2s_port = cpu_dai->driver->id;
 -      drvdata->private_data = data;
 - 
        psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
        if (psubstream) {
 -              if (v->alloc_dma_channel)
 -                      data->rdma_ch = v->alloc_dma_channel(drvdata,
 -                                              SNDRV_PCM_STREAM_PLAYBACK);
 - 
 -              if (data->rdma_ch < 0)
 -                      return data->rdma_ch;
 - 
 -              drvdata->substream[data->rdma_ch] = psubstream;
 - 
                ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
                                        soc_runtime->platform->dev,
                                        size, &psubstream->dma_buffer);
 -              if (ret)
 -                      goto playback_alloc_err;
 - 
 -              ret = regmap_write(drvdata->lpaif_map,
 -                      LPAIF_RDMACTL_REG(v, data->rdma_ch), 0);
                if (ret) {
 -                      dev_err(soc_runtime->dev,
 -                              "%s() error writing to rdmactl reg: %d\n",
 -                              __func__, ret);
 -                      goto capture_alloc_err;
 +                      dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
 +                      return ret;
                }
        }
   
        csubstream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
        if (csubstream) {
 -              if (v->alloc_dma_channel)
 -                      data->wrdma_ch = v->alloc_dma_channel(drvdata,
 -                                              SNDRV_PCM_STREAM_CAPTURE);
 - 
 -              if (data->wrdma_ch < 0) {
 -                      ret = data->wrdma_ch;
 -                      goto capture_alloc_err;
 -              }
 - 
 -              drvdata->substream[data->wrdma_ch] = csubstream;
 - 
                ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
                                        soc_runtime->platform->dev,
                                        size, &csubstream->dma_buffer);
 -              if (ret)
 -                      goto capture_alloc_err;
 - 
 -              ret = regmap_write(drvdata->lpaif_map,
 -                      LPAIF_WRDMACTL_REG(v, data->wrdma_ch), 0);
                if (ret) {
 -                      dev_err(soc_runtime->dev,
 -                              "%s() error writing to wrdmactl reg: %d\n",
 -                              __func__, ret);
 -                      goto capture_reg_err;
 +                      dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
 +                      if (psubstream)
 +                              snd_dma_free_pages(&psubstream->dma_buffer);
 +                      return ret;
                }
 + 
        }
   
        return 0;
 - 
 - capture_reg_err:
 -      if (csubstream)
 -              snd_dma_free_pages(&csubstream->dma_buffer);
 - 
 - capture_alloc_err:
 -      if (psubstream)
 -              snd_dma_free_pages(&psubstream->dma_buffer);
 - 
 -  playback_alloc_err:
 -      dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
 - 
 -      return ret;
   }
   
   static void lpass_platform_pcm_free(struct snd_pcm *pcm)
   {
 -      struct snd_soc_pcm_runtime *rt;
 -      struct lpass_data *drvdata;
 -      struct lpass_pcm_data *data;
 -      struct lpass_variant *v;
        struct snd_pcm_substream *substream;
 -      int ch, i;
 +      int i;
   
        for (i = 0; i < ARRAY_SIZE(pcm->streams); i++) {
                substream = pcm->streams[i].substream;
                if (substream) {
 -                      rt = substream->private_data;
 -                      drvdata = snd_soc_platform_get_drvdata(rt->platform);
 -                      data = drvdata->private_data;
 - 
 -                      ch = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 -                              ? data->rdma_ch
 -                              : data->wrdma_ch;
 -                      v = drvdata->variant;
 -                      drvdata->substream[ch] = NULL;
 -                      if (v->free_dma_channel)
 -                              v->free_dma_channel(drvdata, ch);
 - 
                        snd_dma_free_pages(&substream->dma_buffer);
                        substream->dma_buffer.area = NULL;
                        substream->dma_buffer.addr = 0;