Merge remote-tracking branches 'asoc/topic/ab8500', 'asoc/topic/adau17x1', 'asoc...
authorMark Brown <broonie@kernel.org>
Sun, 13 Mar 2016 08:16:41 +0000 (15:16 +0700)
committerMark Brown <broonie@kernel.org>
Sun, 13 Mar 2016 08:16:41 +0000 (15:16 +0700)
1  2  3  4  5  6 
sound/soc/codecs/ab8500-codec.c
sound/soc/codecs/arizona.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm_adsp.c

Simple merge
index 91785318b2834f325b2ebfb55476ce591b5e377b,38a73e3da508f8cb408878d09f8002bdd89913c0,33143fe1de0bdeaa0c6b04bc9bfd159b49bf658b,33143fe1de0bdeaa0c6b04bc9bfd159b49bf658b,33143fe1de0bdeaa0c6b04bc9bfd159b49bf658b,dd926f4da409684e8da63c08f445238e0e973b24..92d22a018d68bf13bf57def12d6c2c82e1e9d933
@@@@@@@ -1491,12 -1491,9 -1491,12 -1491,12 -1491,12 -1462,11 +1462,11 @@@@@@@ static int arizona_startup(struct snd_p
        struct snd_soc_codec *codec = dai->codec;
        struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
        struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
-----   const struct snd_pcm_hw_constraint_list *constraint;
        unsigned int base_rate;
      
 +      if (!substream->runtime)
 +              return 0;
 +    
        switch (dai_priv->clk) {
        case ARIZONA_CLK_SYSCLK:
                base_rate = priv->sysclk;
index 97c0f1e2388637dcdc686da1f1a5cf06037a6944,c3640960183589eac7856e0edcbc77647c5e78f7,6088d30962a953cab19ee561ee288cca142dfccf,6088d30962a953cab19ee561ee288cca142dfccf,6088d30962a953cab19ee561ee288cca142dfccf,aa47955b68af373321b6050e6344f1b001f5ac91..83ba70fe16e69488a473a68bcc97d4cc2408874f
@@@@@@@ -2173,18 -2177,6 -2173,18 -2173,18 -2173,18 -2218,27 +2218,27 @@@@@@@ static int wm5110_open(struct snd_compr
        return wm_adsp_compr_open(&priv->core.adsp[n_adsp], stream);
      }
      
- ---   struct wm5110_priv *florida = data;
- ---   int ret;
 +    static irqreturn_t wm5110_adsp2_irq(int irq, void *data)
 +    {
- ---   ret = wm_adsp_compr_handle_irq(&florida->core.adsp[2]);
- ---   if (ret == -ENODEV)
+++++   struct wm5110_priv *priv = data;
+++++   struct arizona *arizona = priv->core.arizona;
+++++   int serviced = 0;
+++++   int i, ret;
 +    
+++++   for (i = 0; i < WM5110_NUM_ADSP; ++i) {
+++++           ret = wm_adsp_compr_handle_irq(&priv->core.adsp[i]);
+++++           if (ret != -ENODEV)
+++++                   serviced++;
+++++   }
+++++ 
+++++   if (!serviced) {
+++++           dev_err(arizona->dev, "Spurious compressed data IRQ\n");
 +              return IRQ_NONE;
+++++   }
 +    
 +      return IRQ_HANDLED;
 +    }
 +    
      static int wm5110_codec_probe(struct snd_soc_codec *codec)
      {
        struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
index b9195b9c2b05175278d4e779f7db87aad20d9f63,ac879d16c6a673b0250cbac7cfab57dfe77f7f09,33806d487b8ae00711dddd4ec400393dbff59b1f,33806d487b8ae00711dddd4ec400393dbff59b1f,ba9213c0ad5363110d1aeebc8318623083d0805f,28d3851c50639ef672c42b723e94d1b805757a18..d3b1cb15e7f0766111b6ced6fbe36d65571703aa
@@@@@@@ -292,9 -287,6 -292,9 -292,9 -292,11 -289,9 +289,11 @@@@@@@ struct wm_adsp_compr 
      
        struct snd_compr_stream *stream;
        struct snd_compressed_buffer size;
 +    
 +      u32 *raw_buf;
 +      unsigned int copied_total;
++++ +
++++ +  unsigned int sample_rate;
      };
      
      #define WM_ADSP_DATA_WORD_SIZE         3
@@@@@@@ -2466,11 -2451,6 -2466,11 -2466,11 -2462,13 -2479,11 +2475,13 @@@@@@@ int wm_adsp_compr_set_params(struct snd
        adsp_dbg(compr->dsp, "fragment_size=%d fragments=%d\n",
                 compr->size.fragment_size, compr->size.fragments);
      
 +      size = wm_adsp_compr_frag_words(compr) * sizeof(*compr->raw_buf);
 +      compr->raw_buf = kmalloc(size, GFP_DMA | GFP_KERNEL);
 +      if (!compr->raw_buf)
 +              return -ENOMEM;
 +    
++++ +  compr->sample_rate = params->codec.sample_rate;
++++ +
        return 0;
      }
      EXPORT_SYMBOL_GPL(wm_adsp_compr_set_params);
@@@@@@@ -2751,298 -2719,4 -2751,298 -2751,298 -2749,299 -2764,297 +2762,298 @@@@@@@ int wm_adsp_compr_trigger(struct snd_co
      }
      EXPORT_SYMBOL_GPL(wm_adsp_compr_trigger);
      
- ---           adsp_err(dsp, "Spurious buffer IRQ\n");
 +    static inline int wm_adsp_buffer_size(struct wm_adsp_compr_buf *buf)
 +    {
 +      int last_region = wm_adsp_fw[buf->dsp->fw].caps->num_regions - 1;
 +    
 +      return buf->regions[last_region].cumulative_size;
 +    }
 +    
 +    static int wm_adsp_buffer_update_avail(struct wm_adsp_compr_buf *buf)
 +    {
 +      u32 next_read_index, next_write_index;
 +      int write_index, read_index, avail;
 +      int ret;
 +    
 +      /* Only sync read index if we haven't already read a valid index */
 +      if (buf->read_index < 0) {
 +              ret = wm_adsp_buffer_read(buf,
 +                              HOST_BUFFER_FIELD(next_read_index),
 +                              &next_read_index);
 +              if (ret < 0)
 +                      return ret;
 +    
 +              read_index = sign_extend32(next_read_index, 23);
 +    
 +              if (read_index < 0) {
 +                      adsp_dbg(buf->dsp, "Avail check on unstarted stream\n");
 +                      return 0;
 +              }
 +    
 +              buf->read_index = read_index;
 +      }
 +    
 +      ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(next_write_index),
 +                      &next_write_index);
 +      if (ret < 0)
 +              return ret;
 +    
 +      write_index = sign_extend32(next_write_index, 23);
 +    
 +      avail = write_index - buf->read_index;
 +      if (avail < 0)
 +              avail += wm_adsp_buffer_size(buf);
 +    
 +      adsp_dbg(buf->dsp, "readindex=0x%x, writeindex=0x%x, avail=%d\n",
 +               buf->read_index, write_index, avail);
 +    
 +      buf->avail = avail;
 +    
 +      return 0;
 +    }
 +    
 +    int wm_adsp_compr_handle_irq(struct wm_adsp *dsp)
 +    {
 +      struct wm_adsp_compr_buf *buf = dsp->buffer;
 +      struct wm_adsp_compr *compr = dsp->compr;
 +      int ret = 0;
 +    
 +      mutex_lock(&dsp->pwr_lock);
 +    
 +      if (!buf) {
- -- -  if (compr->stream)
 +              ret = -ENODEV;
 +              goto out;
 +      }
 +    
 +      adsp_dbg(dsp, "Handling buffer IRQ\n");
 +    
 +      ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error);
 +      if (ret < 0) {
 +              adsp_err(dsp, "Failed to check buffer error: %d\n", ret);
 +              goto out;
 +      }
 +      if (buf->error != 0) {
 +              adsp_err(dsp, "Buffer error occurred: %d\n", buf->error);
 +              ret = -EIO;
 +              goto out;
 +      }
 +    
 +      ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count),
 +                                &buf->irq_count);
 +      if (ret < 0) {
 +              adsp_err(dsp, "Failed to get irq_count: %d\n", ret);
 +              goto out;
 +      }
 +    
 +      ret = wm_adsp_buffer_update_avail(buf);
 +      if (ret < 0) {
 +              adsp_err(dsp, "Error reading avail: %d\n", ret);
 +              goto out;
 +      }
 +    
++++ +  if (compr && compr->stream)
 +              snd_compr_fragment_elapsed(compr->stream);
 +    
 +    out:
 +      mutex_unlock(&dsp->pwr_lock);
 +    
 +      return ret;
 +    }
 +    EXPORT_SYMBOL_GPL(wm_adsp_compr_handle_irq);
 +    
 +    static int wm_adsp_buffer_reenable_irq(struct wm_adsp_compr_buf *buf)
 +    {
 +      if (buf->irq_count & 0x01)
 +              return 0;
 +    
 +      adsp_dbg(buf->dsp, "Enable IRQ(0x%x) for next fragment\n",
 +               buf->irq_count);
 +    
 +      buf->irq_count |= 0x01;
 +    
 +      return wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(irq_ack),
 +                                  buf->irq_count);
 +    }
 +    
 +    int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
 +                        struct snd_compr_tstamp *tstamp)
 +    {
 +      struct wm_adsp_compr *compr = stream->runtime->private_data;
 +      struct wm_adsp_compr_buf *buf = compr->buf;
 +      struct wm_adsp *dsp = compr->dsp;
 +      int ret = 0;
 +    
 +      adsp_dbg(dsp, "Pointer request\n");
 +    
 +      mutex_lock(&dsp->pwr_lock);
 +    
 +      if (!compr->buf) {
 +              ret = -ENXIO;
 +              goto out;
 +      }
 +    
 +      if (compr->buf->error) {
 +              ret = -EIO;
 +              goto out;
 +      }
 +    
 +      if (buf->avail < wm_adsp_compr_frag_words(compr)) {
 +              ret = wm_adsp_buffer_update_avail(buf);
 +              if (ret < 0) {
 +                      adsp_err(dsp, "Error reading avail: %d\n", ret);
 +                      goto out;
 +              }
 +    
 +              /*
 +               * If we really have less than 1 fragment available tell the
 +               * DSP to inform us once a whole fragment is available.
 +               */
 +              if (buf->avail < wm_adsp_compr_frag_words(compr)) {
 +                      ret = wm_adsp_buffer_reenable_irq(buf);
 +                      if (ret < 0) {
 +                              adsp_err(dsp,
 +                                       "Failed to re-enable buffer IRQ: %d\n",
 +                                       ret);
 +                              goto out;
 +                      }
 +              }
 +      }
 +    
 +      tstamp->copied_total = compr->copied_total;
 +      tstamp->copied_total += buf->avail * WM_ADSP_DATA_WORD_SIZE;
++++ +  tstamp->sampling_rate = compr->sample_rate;
 +    
 +    out:
 +      mutex_unlock(&dsp->pwr_lock);
 +    
 +      return ret;
 +    }
 +    EXPORT_SYMBOL_GPL(wm_adsp_compr_pointer);
 +    
 +    static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target)
 +    {
 +      struct wm_adsp_compr_buf *buf = compr->buf;
 +      u8 *pack_in = (u8 *)compr->raw_buf;
 +      u8 *pack_out = (u8 *)compr->raw_buf;
 +      unsigned int adsp_addr;
 +      int mem_type, nwords, max_read;
 +      int i, j, ret;
 +    
 +      /* Calculate read parameters */
 +      for (i = 0; i < wm_adsp_fw[buf->dsp->fw].caps->num_regions; ++i)
 +              if (buf->read_index < buf->regions[i].cumulative_size)
 +                      break;
 +    
 +      if (i == wm_adsp_fw[buf->dsp->fw].caps->num_regions)
 +              return -EINVAL;
 +    
 +      mem_type = buf->regions[i].mem_type;
 +      adsp_addr = buf->regions[i].base_addr +
 +                  (buf->read_index - buf->regions[i].offset);
 +    
 +      max_read = wm_adsp_compr_frag_words(compr);
 +      nwords = buf->regions[i].cumulative_size - buf->read_index;
 +    
 +      if (nwords > target)
 +              nwords = target;
 +      if (nwords > buf->avail)
 +              nwords = buf->avail;
 +      if (nwords > max_read)
 +              nwords = max_read;
 +      if (!nwords)
 +              return 0;
 +    
 +      /* Read data from DSP */
 +      ret = wm_adsp_read_data_block(buf->dsp, mem_type, adsp_addr,
 +                                    nwords, compr->raw_buf);
 +      if (ret < 0)
 +              return ret;
 +    
 +      /* Remove the padding bytes from the data read from the DSP */
 +      for (i = 0; i < nwords; i++) {
 +              for (j = 0; j < WM_ADSP_DATA_WORD_SIZE; j++)
 +                      *pack_out++ = *pack_in++;
 +    
 +              pack_in += sizeof(*(compr->raw_buf)) - WM_ADSP_DATA_WORD_SIZE;
 +      }
 +    
 +      /* update read index to account for words read */
 +      buf->read_index += nwords;
 +      if (buf->read_index == wm_adsp_buffer_size(buf))
 +              buf->read_index = 0;
 +    
 +      ret = wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(next_read_index),
 +                                 buf->read_index);
 +      if (ret < 0)
 +              return ret;
 +    
 +      /* update avail to account for words read */
 +      buf->avail -= nwords;
 +    
 +      return nwords;
 +    }
 +    
 +    static int wm_adsp_compr_read(struct wm_adsp_compr *compr,
 +                            char __user *buf, size_t count)
 +    {
 +      struct wm_adsp *dsp = compr->dsp;
 +      int ntotal = 0;
 +      int nwords, nbytes;
 +    
 +      adsp_dbg(dsp, "Requested read of %zu bytes\n", count);
 +    
 +      if (!compr->buf)
 +              return -ENXIO;
 +    
 +      if (compr->buf->error)
 +              return -EIO;
 +    
 +      count /= WM_ADSP_DATA_WORD_SIZE;
 +    
 +      do {
 +              nwords = wm_adsp_buffer_capture_block(compr, count);
 +              if (nwords < 0) {
 +                      adsp_err(dsp, "Failed to capture block: %d\n", nwords);
 +                      return nwords;
 +              }
 +    
 +              nbytes = nwords * WM_ADSP_DATA_WORD_SIZE;
 +    
 +              adsp_dbg(dsp, "Read %d bytes\n", nbytes);
 +    
 +              if (copy_to_user(buf + ntotal, compr->raw_buf, nbytes)) {
 +                      adsp_err(dsp, "Failed to copy data to user: %d, %d\n",
 +                               ntotal, nbytes);
 +                      return -EFAULT;
 +              }
 +    
 +              count -= nwords;
 +              ntotal += nbytes;
 +      } while (nwords > 0 && count > 0);
 +    
 +      compr->copied_total += ntotal;
 +    
 +      return ntotal;
 +    }
 +    
 +    int wm_adsp_compr_copy(struct snd_compr_stream *stream, char __user *buf,
 +                     size_t count)
 +    {
 +      struct wm_adsp_compr *compr = stream->runtime->private_data;
 +      struct wm_adsp *dsp = compr->dsp;
 +      int ret;
 +    
 +      mutex_lock(&dsp->pwr_lock);
 +    
 +      if (stream->direction == SND_COMPRESS_CAPTURE)
 +              ret = wm_adsp_compr_read(compr, buf, count);
 +      else
 +              ret = -ENOTSUPP;
 +    
 +      mutex_unlock(&dsp->pwr_lock);
 +    
 +      return ret;
 +    }
 +    EXPORT_SYMBOL_GPL(wm_adsp_compr_copy);
 +    
      MODULE_LICENSE("GPL v2");