Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 // Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
0003 // Copyright (c) 2018, Linaro Limited
0004 
0005 #include <linux/init.h>
0006 #include <linux/err.h>
0007 #include <linux/module.h>
0008 #include <linux/platform_device.h>
0009 #include <linux/slab.h>
0010 #include <sound/soc.h>
0011 #include <sound/soc-dapm.h>
0012 #include <sound/pcm.h>
0013 #include <linux/spinlock.h>
0014 #include <sound/compress_driver.h>
0015 #include <asm/dma.h>
0016 #include <linux/dma-mapping.h>
0017 #include <linux/of_device.h>
0018 #include <sound/pcm_params.h>
0019 #include "q6asm.h"
0020 #include "q6routing.h"
0021 #include "q6dsp-errno.h"
0022 
0023 #define DRV_NAME    "q6asm-fe-dai"
0024 
0025 #define PLAYBACK_MIN_NUM_PERIODS    2
0026 #define PLAYBACK_MAX_NUM_PERIODS   8
0027 #define PLAYBACK_MAX_PERIOD_SIZE    65536
0028 #define PLAYBACK_MIN_PERIOD_SIZE    128
0029 #define CAPTURE_MIN_NUM_PERIODS     2
0030 #define CAPTURE_MAX_NUM_PERIODS     8
0031 #define CAPTURE_MAX_PERIOD_SIZE     4096
0032 #define CAPTURE_MIN_PERIOD_SIZE     320
0033 #define SID_MASK_DEFAULT    0xF
0034 
0035 /* Default values used if user space does not set */
0036 #define COMPR_PLAYBACK_MIN_FRAGMENT_SIZE (8 * 1024)
0037 #define COMPR_PLAYBACK_MAX_FRAGMENT_SIZE (128 * 1024)
0038 #define COMPR_PLAYBACK_MIN_NUM_FRAGMENTS (4)
0039 #define COMPR_PLAYBACK_MAX_NUM_FRAGMENTS (16 * 4)
0040 
0041 #define ALAC_CH_LAYOUT_MONO   ((101 << 16) | 1)
0042 #define ALAC_CH_LAYOUT_STEREO ((101 << 16) | 2)
0043 
0044 enum stream_state {
0045     Q6ASM_STREAM_IDLE = 0,
0046     Q6ASM_STREAM_STOPPED,
0047     Q6ASM_STREAM_RUNNING,
0048 };
0049 
0050 struct q6asm_dai_rtd {
0051     struct snd_pcm_substream *substream;
0052     struct snd_compr_stream *cstream;
0053     struct snd_codec codec;
0054     struct snd_dma_buffer dma_buffer;
0055     spinlock_t lock;
0056     phys_addr_t phys;
0057     unsigned int pcm_size;
0058     unsigned int pcm_count;
0059     unsigned int pcm_irq_pos;       /* IRQ position */
0060     unsigned int periods;
0061     unsigned int bytes_sent;
0062     unsigned int bytes_received;
0063     unsigned int copied_total;
0064     uint16_t bits_per_sample;
0065     uint16_t source; /* Encoding source bit mask */
0066     struct audio_client *audio_client;
0067     uint32_t next_track_stream_id;
0068     bool next_track;
0069     uint32_t stream_id;
0070     uint16_t session_id;
0071     enum stream_state state;
0072     uint32_t initial_samples_drop;
0073     uint32_t trailing_samples_drop;
0074     bool notify_on_drain;
0075 };
0076 
0077 struct q6asm_dai_data {
0078     struct snd_soc_dai_driver *dais;
0079     int num_dais;
0080     long long int sid;
0081 };
0082 
0083 static const struct snd_pcm_hardware q6asm_dai_hardware_capture = {
0084     .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BATCH |
0085                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
0086                 SNDRV_PCM_INFO_MMAP_VALID |
0087                 SNDRV_PCM_INFO_INTERLEAVED |
0088                 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
0089     .formats =              (SNDRV_PCM_FMTBIT_S16_LE |
0090                 SNDRV_PCM_FMTBIT_S24_LE),
0091     .rates =                SNDRV_PCM_RATE_8000_48000,
0092     .rate_min =             8000,
0093     .rate_max =             48000,
0094     .channels_min =         1,
0095     .channels_max =         4,
0096     .buffer_bytes_max =     CAPTURE_MAX_NUM_PERIODS *
0097                 CAPTURE_MAX_PERIOD_SIZE,
0098     .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE,
0099     .period_bytes_max =     CAPTURE_MAX_PERIOD_SIZE,
0100     .periods_min =          CAPTURE_MIN_NUM_PERIODS,
0101     .periods_max =          CAPTURE_MAX_NUM_PERIODS,
0102     .fifo_size =            0,
0103 };
0104 
0105 static struct snd_pcm_hardware q6asm_dai_hardware_playback = {
0106     .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BATCH |
0107                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
0108                 SNDRV_PCM_INFO_MMAP_VALID |
0109                 SNDRV_PCM_INFO_INTERLEAVED |
0110                 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
0111     .formats =              (SNDRV_PCM_FMTBIT_S16_LE |
0112                 SNDRV_PCM_FMTBIT_S24_LE),
0113     .rates =                SNDRV_PCM_RATE_8000_192000,
0114     .rate_min =             8000,
0115     .rate_max =             192000,
0116     .channels_min =         1,
0117     .channels_max =         8,
0118     .buffer_bytes_max =     (PLAYBACK_MAX_NUM_PERIODS *
0119                 PLAYBACK_MAX_PERIOD_SIZE),
0120     .period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE,
0121     .period_bytes_max =     PLAYBACK_MAX_PERIOD_SIZE,
0122     .periods_min =          PLAYBACK_MIN_NUM_PERIODS,
0123     .periods_max =          PLAYBACK_MAX_NUM_PERIODS,
0124     .fifo_size =            0,
0125 };
0126 
0127 #define Q6ASM_FEDAI_DRIVER(num) { \
0128         .playback = {                       \
0129             .stream_name = "MultiMedia"#num" Playback", \
0130             .rates = (SNDRV_PCM_RATE_8000_192000|       \
0131                     SNDRV_PCM_RATE_KNOT),       \
0132             .formats = (SNDRV_PCM_FMTBIT_S16_LE |       \
0133                     SNDRV_PCM_FMTBIT_S24_LE),   \
0134             .channels_min = 1,              \
0135             .channels_max = 8,              \
0136             .rate_min =     8000,               \
0137             .rate_max = 192000,             \
0138         },                          \
0139         .capture = {                        \
0140             .stream_name = "MultiMedia"#num" Capture",  \
0141             .rates = (SNDRV_PCM_RATE_8000_48000|        \
0142                     SNDRV_PCM_RATE_KNOT),       \
0143             .formats = (SNDRV_PCM_FMTBIT_S16_LE |       \
0144                     SNDRV_PCM_FMTBIT_S24_LE),       \
0145             .channels_min = 1,              \
0146             .channels_max = 4,              \
0147             .rate_min =     8000,               \
0148             .rate_max = 48000,              \
0149         },                          \
0150         .name = "MultiMedia"#num,               \
0151         .id = MSM_FRONTEND_DAI_MULTIMEDIA##num,         \
0152     }
0153 
0154 /* Conventional and unconventional sample rate supported */
0155 static unsigned int supported_sample_rates[] = {
0156     8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
0157     88200, 96000, 176400, 192000
0158 };
0159 
0160 static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
0161     .count = ARRAY_SIZE(supported_sample_rates),
0162     .list = supported_sample_rates,
0163     .mask = 0,
0164 };
0165 
0166 static const struct snd_compr_codec_caps q6asm_compr_caps = {
0167     .num_descriptors = 1,
0168     .descriptor[0].max_ch = 2,
0169     .descriptor[0].sample_rates = { 8000, 11025, 12000, 16000, 22050,
0170                     24000, 32000, 44100, 48000, 88200,
0171                     96000, 176400, 192000 },
0172     .descriptor[0].num_sample_rates = 13,
0173     .descriptor[0].bit_rate[0] = 320,
0174     .descriptor[0].bit_rate[1] = 128,
0175     .descriptor[0].num_bitrates = 2,
0176     .descriptor[0].profiles = 0,
0177     .descriptor[0].modes = SND_AUDIOCHANMODE_MP3_STEREO,
0178     .descriptor[0].formats = 0,
0179 };
0180 
0181 static void event_handler(uint32_t opcode, uint32_t token,
0182               void *payload, void *priv)
0183 {
0184     struct q6asm_dai_rtd *prtd = priv;
0185     struct snd_pcm_substream *substream = prtd->substream;
0186 
0187     switch (opcode) {
0188     case ASM_CLIENT_EVENT_CMD_RUN_DONE:
0189         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0190             q6asm_write_async(prtd->audio_client, prtd->stream_id,
0191                    prtd->pcm_count, 0, 0, 0);
0192         break;
0193     case ASM_CLIENT_EVENT_CMD_EOS_DONE:
0194         prtd->state = Q6ASM_STREAM_STOPPED;
0195         break;
0196     case ASM_CLIENT_EVENT_DATA_WRITE_DONE: {
0197         prtd->pcm_irq_pos += prtd->pcm_count;
0198         snd_pcm_period_elapsed(substream);
0199         if (prtd->state == Q6ASM_STREAM_RUNNING)
0200             q6asm_write_async(prtd->audio_client, prtd->stream_id,
0201                        prtd->pcm_count, 0, 0, 0);
0202 
0203         break;
0204         }
0205     case ASM_CLIENT_EVENT_DATA_READ_DONE:
0206         prtd->pcm_irq_pos += prtd->pcm_count;
0207         snd_pcm_period_elapsed(substream);
0208         if (prtd->state == Q6ASM_STREAM_RUNNING)
0209             q6asm_read(prtd->audio_client, prtd->stream_id);
0210 
0211         break;
0212     default:
0213         break;
0214     }
0215 }
0216 
0217 static int q6asm_dai_prepare(struct snd_soc_component *component,
0218                  struct snd_pcm_substream *substream)
0219 {
0220     struct snd_pcm_runtime *runtime = substream->runtime;
0221     struct snd_soc_pcm_runtime *soc_prtd = asoc_substream_to_rtd(substream);
0222     struct q6asm_dai_rtd *prtd = runtime->private_data;
0223     struct q6asm_dai_data *pdata;
0224     struct device *dev = component->dev;
0225     int ret, i;
0226 
0227     pdata = snd_soc_component_get_drvdata(component);
0228     if (!pdata)
0229         return -EINVAL;
0230 
0231     if (!prtd || !prtd->audio_client) {
0232         dev_err(dev, "%s: private data null or audio client freed\n",
0233             __func__);
0234         return -EINVAL;
0235     }
0236 
0237     prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
0238     prtd->pcm_irq_pos = 0;
0239     /* rate and channels are sent to audio driver */
0240     if (prtd->state) {
0241         /* clear the previous setup if any  */
0242         q6asm_cmd(prtd->audio_client, prtd->stream_id, CMD_CLOSE);
0243         q6asm_unmap_memory_regions(substream->stream,
0244                        prtd->audio_client);
0245         q6routing_stream_close(soc_prtd->dai_link->id,
0246                      substream->stream);
0247     }
0248 
0249     ret = q6asm_map_memory_regions(substream->stream, prtd->audio_client,
0250                        prtd->phys,
0251                        (prtd->pcm_size / prtd->periods),
0252                        prtd->periods);
0253 
0254     if (ret < 0) {
0255         dev_err(dev, "Audio Start: Buffer Allocation failed rc = %d\n",
0256                             ret);
0257         return -ENOMEM;
0258     }
0259 
0260     if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0261         ret = q6asm_open_write(prtd->audio_client, prtd->stream_id,
0262                        FORMAT_LINEAR_PCM,
0263                        0, prtd->bits_per_sample, false);
0264     } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
0265         ret = q6asm_open_read(prtd->audio_client, prtd->stream_id,
0266                       FORMAT_LINEAR_PCM,
0267                       prtd->bits_per_sample);
0268     }
0269 
0270     if (ret < 0) {
0271         dev_err(dev, "%s: q6asm_open_write failed\n", __func__);
0272         goto open_err;
0273     }
0274 
0275     prtd->session_id = q6asm_get_session_id(prtd->audio_client);
0276     ret = q6routing_stream_open(soc_prtd->dai_link->id, LEGACY_PCM_MODE,
0277                   prtd->session_id, substream->stream);
0278     if (ret) {
0279         dev_err(dev, "%s: stream reg failed ret:%d\n", __func__, ret);
0280         goto routing_err;
0281     }
0282 
0283     if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0284         ret = q6asm_media_format_block_multi_ch_pcm(
0285                 prtd->audio_client, prtd->stream_id,
0286                 runtime->rate, runtime->channels, NULL,
0287                 prtd->bits_per_sample);
0288     } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
0289         ret = q6asm_enc_cfg_blk_pcm_format_support(prtd->audio_client,
0290                                prtd->stream_id,
0291                                runtime->rate,
0292                                runtime->channels,
0293                                prtd->bits_per_sample);
0294 
0295         /* Queue the buffers */
0296         for (i = 0; i < runtime->periods; i++)
0297             q6asm_read(prtd->audio_client, prtd->stream_id);
0298 
0299     }
0300     if (ret < 0)
0301         dev_info(dev, "%s: CMD Format block failed\n", __func__);
0302     else
0303         prtd->state = Q6ASM_STREAM_RUNNING;
0304 
0305     return ret;
0306 
0307 routing_err:
0308     q6asm_cmd(prtd->audio_client, prtd->stream_id,  CMD_CLOSE);
0309 open_err:
0310     q6asm_unmap_memory_regions(substream->stream, prtd->audio_client);
0311     q6asm_audio_client_free(prtd->audio_client);
0312     prtd->audio_client = NULL;
0313 
0314     return ret;
0315 }
0316 
0317 static int q6asm_dai_trigger(struct snd_soc_component *component,
0318                  struct snd_pcm_substream *substream, int cmd)
0319 {
0320     int ret = 0;
0321     struct snd_pcm_runtime *runtime = substream->runtime;
0322     struct q6asm_dai_rtd *prtd = runtime->private_data;
0323 
0324     switch (cmd) {
0325     case SNDRV_PCM_TRIGGER_START:
0326     case SNDRV_PCM_TRIGGER_RESUME:
0327     case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
0328         ret = q6asm_run_nowait(prtd->audio_client, prtd->stream_id,
0329                        0, 0, 0);
0330         break;
0331     case SNDRV_PCM_TRIGGER_STOP:
0332         prtd->state = Q6ASM_STREAM_STOPPED;
0333         ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
0334                        CMD_EOS);
0335         break;
0336     case SNDRV_PCM_TRIGGER_SUSPEND:
0337     case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
0338         ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
0339                        CMD_PAUSE);
0340         break;
0341     default:
0342         ret = -EINVAL;
0343         break;
0344     }
0345 
0346     return ret;
0347 }
0348 
0349 static int q6asm_dai_open(struct snd_soc_component *component,
0350               struct snd_pcm_substream *substream)
0351 {
0352     struct snd_pcm_runtime *runtime = substream->runtime;
0353     struct snd_soc_pcm_runtime *soc_prtd = asoc_substream_to_rtd(substream);
0354     struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_prtd, 0);
0355     struct q6asm_dai_rtd *prtd;
0356     struct q6asm_dai_data *pdata;
0357     struct device *dev = component->dev;
0358     int ret = 0;
0359     int stream_id;
0360 
0361     stream_id = cpu_dai->driver->id;
0362 
0363     pdata = snd_soc_component_get_drvdata(component);
0364     if (!pdata) {
0365         dev_err(dev, "Drv data not found ..\n");
0366         return -EINVAL;
0367     }
0368 
0369     prtd = kzalloc(sizeof(struct q6asm_dai_rtd), GFP_KERNEL);
0370     if (prtd == NULL)
0371         return -ENOMEM;
0372 
0373     prtd->substream = substream;
0374     prtd->audio_client = q6asm_audio_client_alloc(dev,
0375                 (q6asm_cb)event_handler, prtd, stream_id,
0376                 LEGACY_PCM_MODE);
0377     if (IS_ERR(prtd->audio_client)) {
0378         dev_info(dev, "%s: Could not allocate memory\n", __func__);
0379         ret = PTR_ERR(prtd->audio_client);
0380         kfree(prtd);
0381         return ret;
0382     }
0383 
0384     /* DSP expects stream id from 1 */
0385     prtd->stream_id = 1;
0386 
0387     if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0388         runtime->hw = q6asm_dai_hardware_playback;
0389     else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
0390         runtime->hw = q6asm_dai_hardware_capture;
0391 
0392     ret = snd_pcm_hw_constraint_list(runtime, 0,
0393                 SNDRV_PCM_HW_PARAM_RATE,
0394                 &constraints_sample_rates);
0395     if (ret < 0)
0396         dev_info(dev, "snd_pcm_hw_constraint_list failed\n");
0397     /* Ensure that buffer size is a multiple of period size */
0398     ret = snd_pcm_hw_constraint_integer(runtime,
0399                         SNDRV_PCM_HW_PARAM_PERIODS);
0400     if (ret < 0)
0401         dev_info(dev, "snd_pcm_hw_constraint_integer failed\n");
0402 
0403     if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0404         ret = snd_pcm_hw_constraint_minmax(runtime,
0405             SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
0406             PLAYBACK_MIN_NUM_PERIODS * PLAYBACK_MIN_PERIOD_SIZE,
0407             PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE);
0408         if (ret < 0) {
0409             dev_err(dev, "constraint for buffer bytes min max ret = %d\n",
0410                 ret);
0411         }
0412     }
0413 
0414     ret = snd_pcm_hw_constraint_step(runtime, 0,
0415         SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
0416     if (ret < 0) {
0417         dev_err(dev, "constraint for period bytes step ret = %d\n",
0418                                 ret);
0419     }
0420     ret = snd_pcm_hw_constraint_step(runtime, 0,
0421         SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
0422     if (ret < 0) {
0423         dev_err(dev, "constraint for buffer bytes step ret = %d\n",
0424                                 ret);
0425     }
0426 
0427     runtime->private_data = prtd;
0428 
0429     snd_soc_set_runtime_hwparams(substream, &q6asm_dai_hardware_playback);
0430 
0431     runtime->dma_bytes = q6asm_dai_hardware_playback.buffer_bytes_max;
0432 
0433 
0434     if (pdata->sid < 0)
0435         prtd->phys = substream->dma_buffer.addr;
0436     else
0437         prtd->phys = substream->dma_buffer.addr | (pdata->sid << 32);
0438 
0439     return 0;
0440 }
0441 
0442 static int q6asm_dai_close(struct snd_soc_component *component,
0443                struct snd_pcm_substream *substream)
0444 {
0445     struct snd_pcm_runtime *runtime = substream->runtime;
0446     struct snd_soc_pcm_runtime *soc_prtd = asoc_substream_to_rtd(substream);
0447     struct q6asm_dai_rtd *prtd = runtime->private_data;
0448 
0449     if (prtd->audio_client) {
0450         if (prtd->state)
0451             q6asm_cmd(prtd->audio_client, prtd->stream_id,
0452                   CMD_CLOSE);
0453 
0454         q6asm_unmap_memory_regions(substream->stream,
0455                        prtd->audio_client);
0456         q6asm_audio_client_free(prtd->audio_client);
0457         prtd->audio_client = NULL;
0458     }
0459     q6routing_stream_close(soc_prtd->dai_link->id,
0460                         substream->stream);
0461     kfree(prtd);
0462     return 0;
0463 }
0464 
0465 static snd_pcm_uframes_t q6asm_dai_pointer(struct snd_soc_component *component,
0466                        struct snd_pcm_substream *substream)
0467 {
0468 
0469     struct snd_pcm_runtime *runtime = substream->runtime;
0470     struct q6asm_dai_rtd *prtd = runtime->private_data;
0471 
0472     if (prtd->pcm_irq_pos >= prtd->pcm_size)
0473         prtd->pcm_irq_pos = 0;
0474 
0475     return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
0476 }
0477 
0478 static int q6asm_dai_hw_params(struct snd_soc_component *component,
0479                    struct snd_pcm_substream *substream,
0480                    struct snd_pcm_hw_params *params)
0481 {
0482     struct snd_pcm_runtime *runtime = substream->runtime;
0483     struct q6asm_dai_rtd *prtd = runtime->private_data;
0484 
0485     prtd->pcm_size = params_buffer_bytes(params);
0486     prtd->periods = params_periods(params);
0487 
0488     switch (params_format(params)) {
0489     case SNDRV_PCM_FORMAT_S16_LE:
0490         prtd->bits_per_sample = 16;
0491         break;
0492     case SNDRV_PCM_FORMAT_S24_LE:
0493         prtd->bits_per_sample = 24;
0494         break;
0495     }
0496 
0497     return 0;
0498 }
0499 
0500 static void compress_event_handler(uint32_t opcode, uint32_t token,
0501                    void *payload, void *priv)
0502 {
0503     struct q6asm_dai_rtd *prtd = priv;
0504     struct snd_compr_stream *substream = prtd->cstream;
0505     unsigned long flags;
0506     u32 wflags = 0;
0507     uint64_t avail;
0508     uint32_t bytes_written, bytes_to_write;
0509     bool is_last_buffer = false;
0510 
0511     switch (opcode) {
0512     case ASM_CLIENT_EVENT_CMD_RUN_DONE:
0513         spin_lock_irqsave(&prtd->lock, flags);
0514         if (!prtd->bytes_sent) {
0515             q6asm_stream_remove_initial_silence(prtd->audio_client,
0516                             prtd->stream_id,
0517                             prtd->initial_samples_drop);
0518 
0519             q6asm_write_async(prtd->audio_client, prtd->stream_id,
0520                       prtd->pcm_count, 0, 0, 0);
0521             prtd->bytes_sent += prtd->pcm_count;
0522         }
0523 
0524         spin_unlock_irqrestore(&prtd->lock, flags);
0525         break;
0526 
0527     case ASM_CLIENT_EVENT_CMD_EOS_DONE:
0528         spin_lock_irqsave(&prtd->lock, flags);
0529         if (prtd->notify_on_drain) {
0530             if (substream->partial_drain) {
0531                 /*
0532                  * Close old stream and make it stale, switch
0533                  * the active stream now!
0534                  */
0535                 q6asm_cmd_nowait(prtd->audio_client,
0536                          prtd->stream_id,
0537                          CMD_CLOSE);
0538                 /*
0539                  * vaild stream ids start from 1, So we are
0540                  * toggling this between 1 and 2.
0541                  */
0542                 prtd->stream_id = (prtd->stream_id == 1 ? 2 : 1);
0543             }
0544 
0545             snd_compr_drain_notify(prtd->cstream);
0546             prtd->notify_on_drain = false;
0547 
0548         } else {
0549             prtd->state = Q6ASM_STREAM_STOPPED;
0550         }
0551         spin_unlock_irqrestore(&prtd->lock, flags);
0552         break;
0553 
0554     case ASM_CLIENT_EVENT_DATA_WRITE_DONE:
0555         spin_lock_irqsave(&prtd->lock, flags);
0556 
0557         bytes_written = token >> ASM_WRITE_TOKEN_LEN_SHIFT;
0558         prtd->copied_total += bytes_written;
0559         snd_compr_fragment_elapsed(substream);
0560 
0561         if (prtd->state != Q6ASM_STREAM_RUNNING) {
0562             spin_unlock_irqrestore(&prtd->lock, flags);
0563             break;
0564         }
0565 
0566         avail = prtd->bytes_received - prtd->bytes_sent;
0567         if (avail > prtd->pcm_count) {
0568             bytes_to_write = prtd->pcm_count;
0569         } else {
0570             if (substream->partial_drain || prtd->notify_on_drain)
0571                 is_last_buffer = true;
0572             bytes_to_write = avail;
0573         }
0574 
0575         if (bytes_to_write) {
0576             if (substream->partial_drain && is_last_buffer) {
0577                 wflags |= ASM_LAST_BUFFER_FLAG;
0578                 q6asm_stream_remove_trailing_silence(prtd->audio_client,
0579                              prtd->stream_id,
0580                              prtd->trailing_samples_drop);
0581             }
0582 
0583             q6asm_write_async(prtd->audio_client, prtd->stream_id,
0584                       bytes_to_write, 0, 0, wflags);
0585 
0586             prtd->bytes_sent += bytes_to_write;
0587         }
0588 
0589         if (prtd->notify_on_drain && is_last_buffer)
0590             q6asm_cmd_nowait(prtd->audio_client,
0591                      prtd->stream_id, CMD_EOS);
0592 
0593         spin_unlock_irqrestore(&prtd->lock, flags);
0594         break;
0595 
0596     default:
0597         break;
0598     }
0599 }
0600 
0601 static int q6asm_dai_compr_open(struct snd_soc_component *component,
0602                 struct snd_compr_stream *stream)
0603 {
0604     struct snd_soc_pcm_runtime *rtd = stream->private_data;
0605     struct snd_compr_runtime *runtime = stream->runtime;
0606     struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
0607     struct q6asm_dai_data *pdata;
0608     struct device *dev = component->dev;
0609     struct q6asm_dai_rtd *prtd;
0610     int stream_id, size, ret;
0611 
0612     stream_id = cpu_dai->driver->id;
0613     pdata = snd_soc_component_get_drvdata(component);
0614     if (!pdata) {
0615         dev_err(dev, "Drv data not found ..\n");
0616         return -EINVAL;
0617     }
0618 
0619     prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
0620     if (!prtd)
0621         return -ENOMEM;
0622 
0623     /* DSP expects stream id from 1 */
0624     prtd->stream_id = 1;
0625 
0626     prtd->cstream = stream;
0627     prtd->audio_client = q6asm_audio_client_alloc(dev,
0628                     (q6asm_cb)compress_event_handler,
0629                     prtd, stream_id, LEGACY_PCM_MODE);
0630     if (IS_ERR(prtd->audio_client)) {
0631         dev_err(dev, "Could not allocate memory\n");
0632         ret = PTR_ERR(prtd->audio_client);
0633         goto free_prtd;
0634     }
0635 
0636     size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE *
0637             COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
0638     ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size,
0639                   &prtd->dma_buffer);
0640     if (ret) {
0641         dev_err(dev, "Cannot allocate buffer(s)\n");
0642         goto free_client;
0643     }
0644 
0645     if (pdata->sid < 0)
0646         prtd->phys = prtd->dma_buffer.addr;
0647     else
0648         prtd->phys = prtd->dma_buffer.addr | (pdata->sid << 32);
0649 
0650     snd_compr_set_runtime_buffer(stream, &prtd->dma_buffer);
0651     spin_lock_init(&prtd->lock);
0652     runtime->private_data = prtd;
0653 
0654     return 0;
0655 
0656 free_client:
0657     q6asm_audio_client_free(prtd->audio_client);
0658 free_prtd:
0659     kfree(prtd);
0660 
0661     return ret;
0662 }
0663 
0664 static int q6asm_dai_compr_free(struct snd_soc_component *component,
0665                 struct snd_compr_stream *stream)
0666 {
0667     struct snd_compr_runtime *runtime = stream->runtime;
0668     struct q6asm_dai_rtd *prtd = runtime->private_data;
0669     struct snd_soc_pcm_runtime *rtd = stream->private_data;
0670 
0671     if (prtd->audio_client) {
0672         if (prtd->state) {
0673             q6asm_cmd(prtd->audio_client, prtd->stream_id,
0674                   CMD_CLOSE);
0675             if (prtd->next_track_stream_id) {
0676                 q6asm_cmd(prtd->audio_client,
0677                       prtd->next_track_stream_id,
0678                       CMD_CLOSE);
0679             }
0680         }
0681 
0682         snd_dma_free_pages(&prtd->dma_buffer);
0683         q6asm_unmap_memory_regions(stream->direction,
0684                        prtd->audio_client);
0685         q6asm_audio_client_free(prtd->audio_client);
0686         prtd->audio_client = NULL;
0687     }
0688     q6routing_stream_close(rtd->dai_link->id, stream->direction);
0689     kfree(prtd);
0690 
0691     return 0;
0692 }
0693 
0694 static int __q6asm_dai_compr_set_codec_params(struct snd_soc_component *component,
0695                           struct snd_compr_stream *stream,
0696                           struct snd_codec *codec,
0697                           int stream_id)
0698 {
0699     struct snd_compr_runtime *runtime = stream->runtime;
0700     struct q6asm_dai_rtd *prtd = runtime->private_data;
0701     struct q6asm_flac_cfg flac_cfg;
0702     struct q6asm_wma_cfg wma_cfg;
0703     struct q6asm_alac_cfg alac_cfg;
0704     struct q6asm_ape_cfg ape_cfg;
0705     unsigned int wma_v9 = 0;
0706     struct device *dev = component->dev;
0707     int ret;
0708     union snd_codec_options *codec_options;
0709     struct snd_dec_flac *flac;
0710     struct snd_dec_wma *wma;
0711     struct snd_dec_alac *alac;
0712     struct snd_dec_ape *ape;
0713 
0714     codec_options = &(prtd->codec.options);
0715 
0716     memcpy(&prtd->codec, codec, sizeof(*codec));
0717 
0718     switch (codec->id) {
0719     case SND_AUDIOCODEC_FLAC:
0720 
0721         memset(&flac_cfg, 0x0, sizeof(struct q6asm_flac_cfg));
0722         flac = &codec_options->flac_d;
0723 
0724         flac_cfg.ch_cfg = codec->ch_in;
0725         flac_cfg.sample_rate = codec->sample_rate;
0726         flac_cfg.stream_info_present = 1;
0727         flac_cfg.sample_size = flac->sample_size;
0728         flac_cfg.min_blk_size = flac->min_blk_size;
0729         flac_cfg.max_blk_size = flac->max_blk_size;
0730         flac_cfg.max_frame_size = flac->max_frame_size;
0731         flac_cfg.min_frame_size = flac->min_frame_size;
0732 
0733         ret = q6asm_stream_media_format_block_flac(prtd->audio_client,
0734                                stream_id,
0735                                &flac_cfg);
0736         if (ret < 0) {
0737             dev_err(dev, "FLAC CMD Format block failed:%d\n", ret);
0738             return -EIO;
0739         }
0740         break;
0741 
0742     case SND_AUDIOCODEC_WMA:
0743         wma = &codec_options->wma_d;
0744 
0745         memset(&wma_cfg, 0x0, sizeof(struct q6asm_wma_cfg));
0746 
0747         wma_cfg.sample_rate =  codec->sample_rate;
0748         wma_cfg.num_channels = codec->ch_in;
0749         wma_cfg.bytes_per_sec = codec->bit_rate / 8;
0750         wma_cfg.block_align = codec->align;
0751         wma_cfg.bits_per_sample = prtd->bits_per_sample;
0752         wma_cfg.enc_options = wma->encoder_option;
0753         wma_cfg.adv_enc_options = wma->adv_encoder_option;
0754         wma_cfg.adv_enc_options2 = wma->adv_encoder_option2;
0755 
0756         if (wma_cfg.num_channels == 1)
0757             wma_cfg.channel_mask = 4; /* Mono Center */
0758         else if (wma_cfg.num_channels == 2)
0759             wma_cfg.channel_mask = 3; /* Stereo FL/FR */
0760         else
0761             return -EINVAL;
0762 
0763         /* check the codec profile */
0764         switch (codec->profile) {
0765         case SND_AUDIOPROFILE_WMA9:
0766             wma_cfg.fmtag = 0x161;
0767             wma_v9 = 1;
0768             break;
0769 
0770         case SND_AUDIOPROFILE_WMA10:
0771             wma_cfg.fmtag = 0x166;
0772             break;
0773 
0774         case SND_AUDIOPROFILE_WMA9_PRO:
0775             wma_cfg.fmtag = 0x162;
0776             break;
0777 
0778         case SND_AUDIOPROFILE_WMA9_LOSSLESS:
0779             wma_cfg.fmtag = 0x163;
0780             break;
0781 
0782         case SND_AUDIOPROFILE_WMA10_LOSSLESS:
0783             wma_cfg.fmtag = 0x167;
0784             break;
0785 
0786         default:
0787             dev_err(dev, "Unknown WMA profile:%x\n",
0788                 codec->profile);
0789             return -EIO;
0790         }
0791 
0792         if (wma_v9)
0793             ret = q6asm_stream_media_format_block_wma_v9(
0794                     prtd->audio_client, stream_id,
0795                     &wma_cfg);
0796         else
0797             ret = q6asm_stream_media_format_block_wma_v10(
0798                     prtd->audio_client, stream_id,
0799                     &wma_cfg);
0800         if (ret < 0) {
0801             dev_err(dev, "WMA9 CMD failed:%d\n", ret);
0802             return -EIO;
0803         }
0804         break;
0805 
0806     case SND_AUDIOCODEC_ALAC:
0807         memset(&alac_cfg, 0x0, sizeof(alac_cfg));
0808         alac = &codec_options->alac_d;
0809 
0810         alac_cfg.sample_rate = codec->sample_rate;
0811         alac_cfg.avg_bit_rate = codec->bit_rate;
0812         alac_cfg.bit_depth = prtd->bits_per_sample;
0813         alac_cfg.num_channels = codec->ch_in;
0814 
0815         alac_cfg.frame_length = alac->frame_length;
0816         alac_cfg.pb = alac->pb;
0817         alac_cfg.mb = alac->mb;
0818         alac_cfg.kb = alac->kb;
0819         alac_cfg.max_run = alac->max_run;
0820         alac_cfg.compatible_version = alac->compatible_version;
0821         alac_cfg.max_frame_bytes = alac->max_frame_bytes;
0822 
0823         switch (codec->ch_in) {
0824         case 1:
0825             alac_cfg.channel_layout_tag = ALAC_CH_LAYOUT_MONO;
0826             break;
0827         case 2:
0828             alac_cfg.channel_layout_tag = ALAC_CH_LAYOUT_STEREO;
0829             break;
0830         }
0831         ret = q6asm_stream_media_format_block_alac(prtd->audio_client,
0832                                stream_id,
0833                                &alac_cfg);
0834         if (ret < 0) {
0835             dev_err(dev, "ALAC CMD Format block failed:%d\n", ret);
0836             return -EIO;
0837         }
0838         break;
0839 
0840     case SND_AUDIOCODEC_APE:
0841         memset(&ape_cfg, 0x0, sizeof(ape_cfg));
0842         ape = &codec_options->ape_d;
0843 
0844         ape_cfg.sample_rate = codec->sample_rate;
0845         ape_cfg.num_channels = codec->ch_in;
0846         ape_cfg.bits_per_sample = prtd->bits_per_sample;
0847 
0848         ape_cfg.compatible_version = ape->compatible_version;
0849         ape_cfg.compression_level = ape->compression_level;
0850         ape_cfg.format_flags = ape->format_flags;
0851         ape_cfg.blocks_per_frame = ape->blocks_per_frame;
0852         ape_cfg.final_frame_blocks = ape->final_frame_blocks;
0853         ape_cfg.total_frames = ape->total_frames;
0854         ape_cfg.seek_table_present = ape->seek_table_present;
0855 
0856         ret = q6asm_stream_media_format_block_ape(prtd->audio_client,
0857                               stream_id,
0858                               &ape_cfg);
0859         if (ret < 0) {
0860             dev_err(dev, "APE CMD Format block failed:%d\n", ret);
0861             return -EIO;
0862         }
0863         break;
0864 
0865     default:
0866         break;
0867     }
0868 
0869     return 0;
0870 }
0871 
0872 static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
0873                       struct snd_compr_stream *stream,
0874                       struct snd_compr_params *params)
0875 {
0876     struct snd_compr_runtime *runtime = stream->runtime;
0877     struct q6asm_dai_rtd *prtd = runtime->private_data;
0878     struct snd_soc_pcm_runtime *rtd = stream->private_data;
0879     int dir = stream->direction;
0880     struct q6asm_dai_data *pdata;
0881     struct device *dev = component->dev;
0882     int ret;
0883 
0884     pdata = snd_soc_component_get_drvdata(component);
0885     if (!pdata)
0886         return -EINVAL;
0887 
0888     if (!prtd || !prtd->audio_client) {
0889         dev_err(dev, "private data null or audio client freed\n");
0890         return -EINVAL;
0891     }
0892 
0893     prtd->periods = runtime->fragments;
0894     prtd->pcm_count = runtime->fragment_size;
0895     prtd->pcm_size = runtime->fragments * runtime->fragment_size;
0896     prtd->bits_per_sample = 16;
0897 
0898     if (dir == SND_COMPRESS_PLAYBACK) {
0899         ret = q6asm_open_write(prtd->audio_client, prtd->stream_id, params->codec.id,
0900                 params->codec.profile, prtd->bits_per_sample,
0901                 true);
0902 
0903         if (ret < 0) {
0904             dev_err(dev, "q6asm_open_write failed\n");
0905             q6asm_audio_client_free(prtd->audio_client);
0906             prtd->audio_client = NULL;
0907             return ret;
0908         }
0909     }
0910 
0911     prtd->session_id = q6asm_get_session_id(prtd->audio_client);
0912     ret = q6routing_stream_open(rtd->dai_link->id, LEGACY_PCM_MODE,
0913                   prtd->session_id, dir);
0914     if (ret) {
0915         dev_err(dev, "Stream reg failed ret:%d\n", ret);
0916         return ret;
0917     }
0918 
0919     ret = __q6asm_dai_compr_set_codec_params(component, stream,
0920                          &params->codec,
0921                          prtd->stream_id);
0922     if (ret) {
0923         dev_err(dev, "codec param setup failed ret:%d\n", ret);
0924         return ret;
0925     }
0926 
0927     ret = q6asm_map_memory_regions(dir, prtd->audio_client, prtd->phys,
0928                        (prtd->pcm_size / prtd->periods),
0929                        prtd->periods);
0930 
0931     if (ret < 0) {
0932         dev_err(dev, "Buffer Mapping failed ret:%d\n", ret);
0933         return -ENOMEM;
0934     }
0935 
0936     prtd->state = Q6ASM_STREAM_RUNNING;
0937 
0938     return 0;
0939 }
0940 
0941 static int q6asm_dai_compr_set_metadata(struct snd_soc_component *component,
0942                     struct snd_compr_stream *stream,
0943                     struct snd_compr_metadata *metadata)
0944 {
0945     struct snd_compr_runtime *runtime = stream->runtime;
0946     struct q6asm_dai_rtd *prtd = runtime->private_data;
0947     int ret = 0;
0948 
0949     switch (metadata->key) {
0950     case SNDRV_COMPRESS_ENCODER_PADDING:
0951         prtd->trailing_samples_drop = metadata->value[0];
0952         break;
0953     case SNDRV_COMPRESS_ENCODER_DELAY:
0954         prtd->initial_samples_drop = metadata->value[0];
0955         if (prtd->next_track_stream_id) {
0956             ret = q6asm_open_write(prtd->audio_client,
0957                            prtd->next_track_stream_id,
0958                            prtd->codec.id,
0959                            prtd->codec.profile,
0960                            prtd->bits_per_sample,
0961                        true);
0962             if (ret < 0) {
0963                 dev_err(component->dev, "q6asm_open_write failed\n");
0964                 return ret;
0965             }
0966             ret = __q6asm_dai_compr_set_codec_params(component, stream,
0967                                  &prtd->codec,
0968                                  prtd->next_track_stream_id);
0969             if (ret < 0) {
0970                 dev_err(component->dev, "q6asm_open_write failed\n");
0971                 return ret;
0972             }
0973 
0974             ret = q6asm_stream_remove_initial_silence(prtd->audio_client,
0975                             prtd->next_track_stream_id,
0976                             prtd->initial_samples_drop);
0977             prtd->next_track_stream_id = 0;
0978 
0979         }
0980 
0981         break;
0982     default:
0983         ret = -EINVAL;
0984         break;
0985     }
0986 
0987     return ret;
0988 }
0989 
0990 static int q6asm_dai_compr_trigger(struct snd_soc_component *component,
0991                    struct snd_compr_stream *stream, int cmd)
0992 {
0993     struct snd_compr_runtime *runtime = stream->runtime;
0994     struct q6asm_dai_rtd *prtd = runtime->private_data;
0995     int ret = 0;
0996 
0997     switch (cmd) {
0998     case SNDRV_PCM_TRIGGER_START:
0999     case SNDRV_PCM_TRIGGER_RESUME:
1000     case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
1001         ret = q6asm_run_nowait(prtd->audio_client, prtd->stream_id,
1002                        0, 0, 0);
1003         break;
1004     case SNDRV_PCM_TRIGGER_STOP:
1005         prtd->state = Q6ASM_STREAM_STOPPED;
1006         ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
1007                        CMD_EOS);
1008         break;
1009     case SNDRV_PCM_TRIGGER_SUSPEND:
1010     case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
1011         ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
1012                        CMD_PAUSE);
1013         break;
1014     case SND_COMPR_TRIGGER_NEXT_TRACK:
1015         prtd->next_track = true;
1016         prtd->next_track_stream_id = (prtd->stream_id == 1 ? 2 : 1);
1017         break;
1018     case SND_COMPR_TRIGGER_DRAIN:
1019     case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
1020         prtd->notify_on_drain = true;
1021         break;
1022     default:
1023         ret = -EINVAL;
1024         break;
1025     }
1026 
1027     return ret;
1028 }
1029 
1030 static int q6asm_dai_compr_pointer(struct snd_soc_component *component,
1031                    struct snd_compr_stream *stream,
1032                    struct snd_compr_tstamp *tstamp)
1033 {
1034     struct snd_compr_runtime *runtime = stream->runtime;
1035     struct q6asm_dai_rtd *prtd = runtime->private_data;
1036     unsigned long flags;
1037 
1038     spin_lock_irqsave(&prtd->lock, flags);
1039 
1040     tstamp->copied_total = prtd->copied_total;
1041     tstamp->byte_offset = prtd->copied_total % prtd->pcm_size;
1042 
1043     spin_unlock_irqrestore(&prtd->lock, flags);
1044 
1045     return 0;
1046 }
1047 
1048 static int q6asm_compr_copy(struct snd_soc_component *component,
1049                 struct snd_compr_stream *stream, char __user *buf,
1050                 size_t count)
1051 {
1052     struct snd_compr_runtime *runtime = stream->runtime;
1053     struct q6asm_dai_rtd *prtd = runtime->private_data;
1054     unsigned long flags;
1055     u32 wflags = 0;
1056     int avail, bytes_in_flight = 0;
1057     void *dstn;
1058     size_t copy;
1059     u32 app_pointer;
1060     u32 bytes_received;
1061 
1062     bytes_received = prtd->bytes_received;
1063 
1064     /**
1065      * Make sure that next track data pointer is aligned at 32 bit boundary
1066      * This is a Mandatory requirement from DSP data buffers alignment
1067      */
1068     if (prtd->next_track)
1069         bytes_received = ALIGN(prtd->bytes_received, prtd->pcm_count);
1070 
1071     app_pointer = bytes_received/prtd->pcm_size;
1072     app_pointer = bytes_received -  (app_pointer * prtd->pcm_size);
1073     dstn = prtd->dma_buffer.area + app_pointer;
1074 
1075     if (count < prtd->pcm_size - app_pointer) {
1076         if (copy_from_user(dstn, buf, count))
1077             return -EFAULT;
1078     } else {
1079         copy = prtd->pcm_size - app_pointer;
1080         if (copy_from_user(dstn, buf, copy))
1081             return -EFAULT;
1082         if (copy_from_user(prtd->dma_buffer.area, buf + copy,
1083                    count - copy))
1084             return -EFAULT;
1085     }
1086 
1087     spin_lock_irqsave(&prtd->lock, flags);
1088 
1089     bytes_in_flight = prtd->bytes_received - prtd->copied_total;
1090 
1091     if (prtd->next_track) {
1092         prtd->next_track = false;
1093         prtd->copied_total = ALIGN(prtd->copied_total, prtd->pcm_count);
1094         prtd->bytes_sent = ALIGN(prtd->bytes_sent, prtd->pcm_count);
1095     }
1096 
1097     prtd->bytes_received = bytes_received + count;
1098 
1099     /* Kick off the data to dsp if its starving!! */
1100     if (prtd->state == Q6ASM_STREAM_RUNNING && (bytes_in_flight == 0)) {
1101         uint32_t bytes_to_write = prtd->pcm_count;
1102 
1103         avail = prtd->bytes_received - prtd->bytes_sent;
1104 
1105         if (avail < prtd->pcm_count)
1106             bytes_to_write = avail;
1107 
1108         q6asm_write_async(prtd->audio_client, prtd->stream_id,
1109                   bytes_to_write, 0, 0, wflags);
1110         prtd->bytes_sent += bytes_to_write;
1111     }
1112 
1113     spin_unlock_irqrestore(&prtd->lock, flags);
1114 
1115     return count;
1116 }
1117 
1118 static int q6asm_dai_compr_mmap(struct snd_soc_component *component,
1119                 struct snd_compr_stream *stream,
1120                 struct vm_area_struct *vma)
1121 {
1122     struct snd_compr_runtime *runtime = stream->runtime;
1123     struct q6asm_dai_rtd *prtd = runtime->private_data;
1124     struct device *dev = component->dev;
1125 
1126     return dma_mmap_coherent(dev, vma,
1127             prtd->dma_buffer.area, prtd->dma_buffer.addr,
1128             prtd->dma_buffer.bytes);
1129 }
1130 
1131 static int q6asm_dai_compr_get_caps(struct snd_soc_component *component,
1132                     struct snd_compr_stream *stream,
1133                     struct snd_compr_caps *caps)
1134 {
1135     caps->direction = SND_COMPRESS_PLAYBACK;
1136     caps->min_fragment_size = COMPR_PLAYBACK_MIN_FRAGMENT_SIZE;
1137     caps->max_fragment_size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE;
1138     caps->min_fragments = COMPR_PLAYBACK_MIN_NUM_FRAGMENTS;
1139     caps->max_fragments = COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
1140     caps->num_codecs = 5;
1141     caps->codecs[0] = SND_AUDIOCODEC_MP3;
1142     caps->codecs[1] = SND_AUDIOCODEC_FLAC;
1143     caps->codecs[2] = SND_AUDIOCODEC_WMA;
1144     caps->codecs[3] = SND_AUDIOCODEC_ALAC;
1145     caps->codecs[4] = SND_AUDIOCODEC_APE;
1146 
1147     return 0;
1148 }
1149 
1150 static int q6asm_dai_compr_get_codec_caps(struct snd_soc_component *component,
1151                       struct snd_compr_stream *stream,
1152                       struct snd_compr_codec_caps *codec)
1153 {
1154     switch (codec->codec) {
1155     case SND_AUDIOCODEC_MP3:
1156         *codec = q6asm_compr_caps;
1157         break;
1158     default:
1159         break;
1160     }
1161 
1162     return 0;
1163 }
1164 
1165 static const struct snd_compress_ops q6asm_dai_compress_ops = {
1166     .open       = q6asm_dai_compr_open,
1167     .free       = q6asm_dai_compr_free,
1168     .set_params = q6asm_dai_compr_set_params,
1169     .set_metadata   = q6asm_dai_compr_set_metadata,
1170     .pointer    = q6asm_dai_compr_pointer,
1171     .trigger    = q6asm_dai_compr_trigger,
1172     .get_caps   = q6asm_dai_compr_get_caps,
1173     .get_codec_caps = q6asm_dai_compr_get_codec_caps,
1174     .mmap       = q6asm_dai_compr_mmap,
1175     .copy       = q6asm_compr_copy,
1176 };
1177 
1178 static int q6asm_dai_pcm_new(struct snd_soc_component *component,
1179                  struct snd_soc_pcm_runtime *rtd)
1180 {
1181     struct snd_pcm *pcm = rtd->pcm;
1182     size_t size = q6asm_dai_hardware_playback.buffer_bytes_max;
1183 
1184     return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
1185                         component->dev, size);
1186 }
1187 
1188 static const struct snd_soc_dapm_widget q6asm_dapm_widgets[] = {
1189     SND_SOC_DAPM_AIF_IN("MM_DL1", "MultiMedia1 Playback", 0, SND_SOC_NOPM, 0, 0),
1190     SND_SOC_DAPM_AIF_IN("MM_DL2", "MultiMedia2 Playback", 0, SND_SOC_NOPM, 0, 0),
1191     SND_SOC_DAPM_AIF_IN("MM_DL3", "MultiMedia3 Playback", 0, SND_SOC_NOPM, 0, 0),
1192     SND_SOC_DAPM_AIF_IN("MM_DL4", "MultiMedia4 Playback", 0, SND_SOC_NOPM, 0, 0),
1193     SND_SOC_DAPM_AIF_IN("MM_DL5", "MultiMedia5 Playback", 0, SND_SOC_NOPM, 0, 0),
1194     SND_SOC_DAPM_AIF_IN("MM_DL6", "MultiMedia6 Playback", 0, SND_SOC_NOPM, 0, 0),
1195     SND_SOC_DAPM_AIF_IN("MM_DL7", "MultiMedia7 Playback", 0, SND_SOC_NOPM, 0, 0),
1196     SND_SOC_DAPM_AIF_IN("MM_DL8", "MultiMedia8 Playback", 0, SND_SOC_NOPM, 0, 0),
1197     SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, SND_SOC_NOPM, 0, 0),
1198     SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, SND_SOC_NOPM, 0, 0),
1199     SND_SOC_DAPM_AIF_OUT("MM_UL3", "MultiMedia3 Capture", 0, SND_SOC_NOPM, 0, 0),
1200     SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, SND_SOC_NOPM, 0, 0),
1201     SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, SND_SOC_NOPM, 0, 0),
1202     SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, SND_SOC_NOPM, 0, 0),
1203     SND_SOC_DAPM_AIF_OUT("MM_UL7", "MultiMedia7 Capture", 0, SND_SOC_NOPM, 0, 0),
1204     SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, SND_SOC_NOPM, 0, 0),
1205 };
1206 
1207 static const struct snd_soc_component_driver q6asm_fe_dai_component = {
1208     .name           = DRV_NAME,
1209     .open           = q6asm_dai_open,
1210     .hw_params      = q6asm_dai_hw_params,
1211     .close          = q6asm_dai_close,
1212     .prepare        = q6asm_dai_prepare,
1213     .trigger        = q6asm_dai_trigger,
1214     .pointer        = q6asm_dai_pointer,
1215     .pcm_construct      = q6asm_dai_pcm_new,
1216     .compress_ops       = &q6asm_dai_compress_ops,
1217     .dapm_widgets       = q6asm_dapm_widgets,
1218     .num_dapm_widgets   = ARRAY_SIZE(q6asm_dapm_widgets),
1219     .legacy_dai_naming  = 1,
1220 };
1221 
1222 static struct snd_soc_dai_driver q6asm_fe_dais_template[] = {
1223     Q6ASM_FEDAI_DRIVER(1),
1224     Q6ASM_FEDAI_DRIVER(2),
1225     Q6ASM_FEDAI_DRIVER(3),
1226     Q6ASM_FEDAI_DRIVER(4),
1227     Q6ASM_FEDAI_DRIVER(5),
1228     Q6ASM_FEDAI_DRIVER(6),
1229     Q6ASM_FEDAI_DRIVER(7),
1230     Q6ASM_FEDAI_DRIVER(8),
1231 };
1232 
1233 static int of_q6asm_parse_dai_data(struct device *dev,
1234                     struct q6asm_dai_data *pdata)
1235 {
1236     struct snd_soc_dai_driver *dai_drv;
1237     struct snd_soc_pcm_stream empty_stream;
1238     struct device_node *node;
1239     int ret, id, dir, idx = 0;
1240 
1241 
1242     pdata->num_dais = of_get_child_count(dev->of_node);
1243     if (!pdata->num_dais) {
1244         dev_err(dev, "No dais found in DT\n");
1245         return -EINVAL;
1246     }
1247 
1248     pdata->dais = devm_kcalloc(dev, pdata->num_dais, sizeof(*dai_drv),
1249                    GFP_KERNEL);
1250     if (!pdata->dais)
1251         return -ENOMEM;
1252 
1253     memset(&empty_stream, 0, sizeof(empty_stream));
1254 
1255     for_each_child_of_node(dev->of_node, node) {
1256         ret = of_property_read_u32(node, "reg", &id);
1257         if (ret || id >= MAX_SESSIONS || id < 0) {
1258             dev_err(dev, "valid dai id not found:%d\n", ret);
1259             continue;
1260         }
1261 
1262         dai_drv = &pdata->dais[idx++];
1263         *dai_drv = q6asm_fe_dais_template[id];
1264 
1265         ret = of_property_read_u32(node, "direction", &dir);
1266         if (ret)
1267             continue;
1268 
1269         if (dir == Q6ASM_DAI_RX)
1270             dai_drv->capture = empty_stream;
1271         else if (dir == Q6ASM_DAI_TX)
1272             dai_drv->playback = empty_stream;
1273 
1274         if (of_property_read_bool(node, "is-compress-dai"))
1275             dai_drv->compress_new = snd_soc_new_compress;
1276     }
1277 
1278     return 0;
1279 }
1280 
1281 static int q6asm_dai_probe(struct platform_device *pdev)
1282 {
1283     struct device *dev = &pdev->dev;
1284     struct device_node *node = dev->of_node;
1285     struct of_phandle_args args;
1286     struct q6asm_dai_data *pdata;
1287     int rc;
1288 
1289     pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
1290     if (!pdata)
1291         return -ENOMEM;
1292 
1293     rc = of_parse_phandle_with_fixed_args(node, "iommus", 1, 0, &args);
1294     if (rc < 0)
1295         pdata->sid = -1;
1296     else
1297         pdata->sid = args.args[0] & SID_MASK_DEFAULT;
1298 
1299     dev_set_drvdata(dev, pdata);
1300 
1301     rc = of_q6asm_parse_dai_data(dev, pdata);
1302     if (rc)
1303         return rc;
1304 
1305     return devm_snd_soc_register_component(dev, &q6asm_fe_dai_component,
1306                            pdata->dais, pdata->num_dais);
1307 }
1308 
1309 #ifdef CONFIG_OF
1310 static const struct of_device_id q6asm_dai_device_id[] = {
1311     { .compatible = "qcom,q6asm-dais" },
1312     {},
1313 };
1314 MODULE_DEVICE_TABLE(of, q6asm_dai_device_id);
1315 #endif
1316 
1317 static struct platform_driver q6asm_dai_platform_driver = {
1318     .driver = {
1319         .name = "q6asm-dai",
1320         .of_match_table = of_match_ptr(q6asm_dai_device_id),
1321     },
1322     .probe = q6asm_dai_probe,
1323 };
1324 module_platform_driver(q6asm_dai_platform_driver);
1325 
1326 MODULE_DESCRIPTION("Q6ASM dai driver");
1327 MODULE_LICENSE("GPL v2");