linux/sound/soc/qcom/qdsp6/q6asm-dai.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
   3// Copyright (c) 2018, Linaro Limited
   4
   5#include <linux/init.h>
   6#include <linux/err.h>
   7#include <linux/module.h>
   8#include <linux/platform_device.h>
   9#include <linux/slab.h>
  10#include <sound/soc.h>
  11#include <sound/soc-dapm.h>
  12#include <sound/pcm.h>
  13#include <linux/spinlock.h>
  14#include <sound/compress_driver.h>
  15#include <asm/dma.h>
  16#include <linux/dma-mapping.h>
  17#include <linux/of_device.h>
  18#include <sound/pcm_params.h>
  19#include "q6asm.h"
  20#include "q6routing.h"
  21#include "q6dsp-errno.h"
  22
  23#define DRV_NAME        "q6asm-fe-dai"
  24
  25#define PLAYBACK_MIN_NUM_PERIODS    2
  26#define PLAYBACK_MAX_NUM_PERIODS   8
  27#define PLAYBACK_MAX_PERIOD_SIZE    65536
  28#define PLAYBACK_MIN_PERIOD_SIZE    128
  29#define CAPTURE_MIN_NUM_PERIODS     2
  30#define CAPTURE_MAX_NUM_PERIODS     8
  31#define CAPTURE_MAX_PERIOD_SIZE     4096
  32#define CAPTURE_MIN_PERIOD_SIZE     320
  33#define SID_MASK_DEFAULT        0xF
  34
  35/* Default values used if user space does not set */
  36#define COMPR_PLAYBACK_MIN_FRAGMENT_SIZE (8 * 1024)
  37#define COMPR_PLAYBACK_MAX_FRAGMENT_SIZE (128 * 1024)
  38#define COMPR_PLAYBACK_MIN_NUM_FRAGMENTS (4)
  39#define COMPR_PLAYBACK_MAX_NUM_FRAGMENTS (16 * 4)
  40#define Q6ASM_DAI_TX_RX 0
  41#define Q6ASM_DAI_TX    1
  42#define Q6ASM_DAI_RX    2
  43
  44enum stream_state {
  45        Q6ASM_STREAM_IDLE = 0,
  46        Q6ASM_STREAM_STOPPED,
  47        Q6ASM_STREAM_RUNNING,
  48};
  49
  50struct q6asm_dai_rtd {
  51        struct snd_pcm_substream *substream;
  52        struct snd_compr_stream *cstream;
  53        struct snd_compr_params codec_param;
  54        struct snd_dma_buffer dma_buffer;
  55        spinlock_t lock;
  56        phys_addr_t phys;
  57        unsigned int pcm_size;
  58        unsigned int pcm_count;
  59        unsigned int pcm_irq_pos;       /* IRQ position */
  60        unsigned int periods;
  61        unsigned int bytes_sent;
  62        unsigned int bytes_received;
  63        unsigned int copied_total;
  64        uint16_t bits_per_sample;
  65        uint16_t source; /* Encoding source bit mask */
  66        struct audio_client *audio_client;
  67        uint16_t session_id;
  68        enum stream_state state;
  69};
  70
  71struct q6asm_dai_data {
  72        long long int sid;
  73};
  74
  75static struct snd_pcm_hardware q6asm_dai_hardware_capture = {
  76        .info =                 (SNDRV_PCM_INFO_MMAP |
  77                                SNDRV_PCM_INFO_BLOCK_TRANSFER |
  78                                SNDRV_PCM_INFO_MMAP_VALID |
  79                                SNDRV_PCM_INFO_INTERLEAVED |
  80                                SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
  81        .formats =              (SNDRV_PCM_FMTBIT_S16_LE |
  82                                SNDRV_PCM_FMTBIT_S24_LE),
  83        .rates =                SNDRV_PCM_RATE_8000_48000,
  84        .rate_min =             8000,
  85        .rate_max =             48000,
  86        .channels_min =         1,
  87        .channels_max =         4,
  88        .buffer_bytes_max =     CAPTURE_MAX_NUM_PERIODS *
  89                                CAPTURE_MAX_PERIOD_SIZE,
  90        .period_bytes_min =     CAPTURE_MIN_PERIOD_SIZE,
  91        .period_bytes_max =     CAPTURE_MAX_PERIOD_SIZE,
  92        .periods_min =          CAPTURE_MIN_NUM_PERIODS,
  93        .periods_max =          CAPTURE_MAX_NUM_PERIODS,
  94        .fifo_size =            0,
  95};
  96
  97static struct snd_pcm_hardware q6asm_dai_hardware_playback = {
  98        .info =                 (SNDRV_PCM_INFO_MMAP |
  99                                SNDRV_PCM_INFO_BLOCK_TRANSFER |
 100                                SNDRV_PCM_INFO_MMAP_VALID |
 101                                SNDRV_PCM_INFO_INTERLEAVED |
 102                                SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
 103        .formats =              (SNDRV_PCM_FMTBIT_S16_LE |
 104                                SNDRV_PCM_FMTBIT_S24_LE),
 105        .rates =                SNDRV_PCM_RATE_8000_192000,
 106        .rate_min =             8000,
 107        .rate_max =             192000,
 108        .channels_min =         1,
 109        .channels_max =         8,
 110        .buffer_bytes_max =     (PLAYBACK_MAX_NUM_PERIODS *
 111                                PLAYBACK_MAX_PERIOD_SIZE),
 112        .period_bytes_min =     PLAYBACK_MIN_PERIOD_SIZE,
 113        .period_bytes_max =     PLAYBACK_MAX_PERIOD_SIZE,
 114        .periods_min =          PLAYBACK_MIN_NUM_PERIODS,
 115        .periods_max =          PLAYBACK_MAX_NUM_PERIODS,
 116        .fifo_size =            0,
 117};
 118
 119#define Q6ASM_FEDAI_DRIVER(num) { \
 120                .playback = {                                           \
 121                        .stream_name = "MultiMedia"#num" Playback",     \
 122                        .rates = (SNDRV_PCM_RATE_8000_192000|           \
 123                                        SNDRV_PCM_RATE_KNOT),           \
 124                        .formats = (SNDRV_PCM_FMTBIT_S16_LE |           \
 125                                        SNDRV_PCM_FMTBIT_S24_LE),       \
 126                        .channels_min = 1,                              \
 127                        .channels_max = 8,                              \
 128                        .rate_min =     8000,                           \
 129                        .rate_max =     192000,                         \
 130                },                                                      \
 131                .capture = {                                            \
 132                        .stream_name = "MultiMedia"#num" Capture",      \
 133                        .rates = (SNDRV_PCM_RATE_8000_48000|            \
 134                                        SNDRV_PCM_RATE_KNOT),           \
 135                        .formats = (SNDRV_PCM_FMTBIT_S16_LE |           \
 136                                    SNDRV_PCM_FMTBIT_S24_LE),           \
 137                        .channels_min = 1,                              \
 138                        .channels_max = 4,                              \
 139                        .rate_min =     8000,                           \
 140                        .rate_max =     48000,                          \
 141                },                                                      \
 142                .name = "MultiMedia"#num,                               \
 143                .id = MSM_FRONTEND_DAI_MULTIMEDIA##num,                 \
 144        }
 145
 146/* Conventional and unconventional sample rate supported */
 147static unsigned int supported_sample_rates[] = {
 148        8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
 149        88200, 96000, 176400, 192000
 150};
 151
 152static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
 153        .count = ARRAY_SIZE(supported_sample_rates),
 154        .list = supported_sample_rates,
 155        .mask = 0,
 156};
 157
 158static const struct snd_compr_codec_caps q6asm_compr_caps = {
 159        .num_descriptors = 1,
 160        .descriptor[0].max_ch = 2,
 161        .descriptor[0].sample_rates = { 8000, 11025, 12000, 16000, 22050,
 162                                        24000, 32000, 44100, 48000, 88200,
 163                                        96000, 176400, 192000 },
 164        .descriptor[0].num_sample_rates = 13,
 165        .descriptor[0].bit_rate[0] = 320,
 166        .descriptor[0].bit_rate[1] = 128,
 167        .descriptor[0].num_bitrates = 2,
 168        .descriptor[0].profiles = 0,
 169        .descriptor[0].modes = SND_AUDIOCHANMODE_MP3_STEREO,
 170        .descriptor[0].formats = 0,
 171};
 172
 173static void event_handler(uint32_t opcode, uint32_t token,
 174                          uint32_t *payload, void *priv)
 175{
 176        struct q6asm_dai_rtd *prtd = priv;
 177        struct snd_pcm_substream *substream = prtd->substream;
 178
 179        switch (opcode) {
 180        case ASM_CLIENT_EVENT_CMD_RUN_DONE:
 181                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 182                        q6asm_write_async(prtd->audio_client,
 183                                   prtd->pcm_count, 0, 0, NO_TIMESTAMP);
 184                break;
 185        case ASM_CLIENT_EVENT_CMD_EOS_DONE:
 186                prtd->state = Q6ASM_STREAM_STOPPED;
 187                break;
 188        case ASM_CLIENT_EVENT_DATA_WRITE_DONE: {
 189                prtd->pcm_irq_pos += prtd->pcm_count;
 190                snd_pcm_period_elapsed(substream);
 191                if (prtd->state == Q6ASM_STREAM_RUNNING)
 192                        q6asm_write_async(prtd->audio_client,
 193                                           prtd->pcm_count, 0, 0, NO_TIMESTAMP);
 194
 195                break;
 196                }
 197        case ASM_CLIENT_EVENT_DATA_READ_DONE:
 198                prtd->pcm_irq_pos += prtd->pcm_count;
 199                snd_pcm_period_elapsed(substream);
 200                if (prtd->state == Q6ASM_STREAM_RUNNING)
 201                        q6asm_read(prtd->audio_client);
 202
 203                break;
 204        default:
 205                break;
 206        }
 207}
 208
 209static int q6asm_dai_prepare(struct snd_pcm_substream *substream)
 210{
 211        struct snd_pcm_runtime *runtime = substream->runtime;
 212        struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
 213        struct q6asm_dai_rtd *prtd = runtime->private_data;
 214        struct snd_soc_component *c = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
 215        struct q6asm_dai_data *pdata;
 216        int ret, i;
 217
 218        pdata = snd_soc_component_get_drvdata(c);
 219        if (!pdata)
 220                return -EINVAL;
 221
 222        if (!prtd || !prtd->audio_client) {
 223                pr_err("%s: private data null or audio client freed\n",
 224                        __func__);
 225                return -EINVAL;
 226        }
 227
 228        prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
 229        prtd->pcm_irq_pos = 0;
 230        /* rate and channels are sent to audio driver */
 231        if (prtd->state) {
 232                /* clear the previous setup if any  */
 233                q6asm_cmd(prtd->audio_client, CMD_CLOSE);
 234                q6asm_unmap_memory_regions(substream->stream,
 235                                           prtd->audio_client);
 236                q6routing_stream_close(soc_prtd->dai_link->id,
 237                                         substream->stream);
 238        }
 239
 240        ret = q6asm_map_memory_regions(substream->stream, prtd->audio_client,
 241                                       prtd->phys,
 242                                       (prtd->pcm_size / prtd->periods),
 243                                       prtd->periods);
 244
 245        if (ret < 0) {
 246                pr_err("Audio Start: Buffer Allocation failed rc = %d\n",
 247                                                        ret);
 248                return -ENOMEM;
 249        }
 250
 251        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 252                ret = q6asm_open_write(prtd->audio_client, FORMAT_LINEAR_PCM,
 253                                       prtd->bits_per_sample);
 254        } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
 255                ret = q6asm_open_read(prtd->audio_client, FORMAT_LINEAR_PCM,
 256                                       prtd->bits_per_sample);
 257        }
 258
 259        if (ret < 0) {
 260                pr_err("%s: q6asm_open_write failed\n", __func__);
 261                q6asm_audio_client_free(prtd->audio_client);
 262                prtd->audio_client = NULL;
 263                return -ENOMEM;
 264        }
 265
 266        prtd->session_id = q6asm_get_session_id(prtd->audio_client);
 267        ret = q6routing_stream_open(soc_prtd->dai_link->id, LEGACY_PCM_MODE,
 268                              prtd->session_id, substream->stream);
 269        if (ret) {
 270                pr_err("%s: stream reg failed ret:%d\n", __func__, ret);
 271                return ret;
 272        }
 273
 274        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 275                ret = q6asm_media_format_block_multi_ch_pcm(
 276                                prtd->audio_client, runtime->rate,
 277                                runtime->channels, NULL,
 278                                prtd->bits_per_sample);
 279        } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
 280                ret = q6asm_enc_cfg_blk_pcm_format_support(prtd->audio_client,
 281                                        runtime->rate, runtime->channels,
 282                                        prtd->bits_per_sample);
 283
 284                /* Queue the buffers */
 285                for (i = 0; i < runtime->periods; i++)
 286                        q6asm_read(prtd->audio_client);
 287
 288        }
 289        if (ret < 0)
 290                pr_info("%s: CMD Format block failed\n", __func__);
 291
 292        prtd->state = Q6ASM_STREAM_RUNNING;
 293
 294        return 0;
 295}
 296
 297static int q6asm_dai_trigger(struct snd_pcm_substream *substream, int cmd)
 298{
 299        int ret = 0;
 300        struct snd_pcm_runtime *runtime = substream->runtime;
 301        struct q6asm_dai_rtd *prtd = runtime->private_data;
 302
 303        switch (cmd) {
 304        case SNDRV_PCM_TRIGGER_START:
 305        case SNDRV_PCM_TRIGGER_RESUME:
 306        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 307                ret = q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
 308                break;
 309        case SNDRV_PCM_TRIGGER_STOP:
 310                prtd->state = Q6ASM_STREAM_STOPPED;
 311                ret = q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
 312                break;
 313        case SNDRV_PCM_TRIGGER_SUSPEND:
 314        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 315                ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
 316                break;
 317        default:
 318                ret = -EINVAL;
 319                break;
 320        }
 321
 322        return ret;
 323}
 324
 325static int q6asm_dai_open(struct snd_pcm_substream *substream)
 326{
 327        struct snd_pcm_runtime *runtime = substream->runtime;
 328        struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
 329        struct snd_soc_dai *cpu_dai = soc_prtd->cpu_dai;
 330        struct snd_soc_component *c = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
 331        struct q6asm_dai_rtd *prtd;
 332        struct q6asm_dai_data *pdata;
 333        struct device *dev = c->dev;
 334        int ret = 0;
 335        int stream_id;
 336
 337        stream_id = cpu_dai->driver->id;
 338
 339        pdata = snd_soc_component_get_drvdata(c);
 340        if (!pdata) {
 341                pr_err("Drv data not found ..\n");
 342                return -EINVAL;
 343        }
 344
 345        prtd = kzalloc(sizeof(struct q6asm_dai_rtd), GFP_KERNEL);
 346        if (prtd == NULL)
 347                return -ENOMEM;
 348
 349        prtd->substream = substream;
 350        prtd->audio_client = q6asm_audio_client_alloc(dev,
 351                                (q6asm_cb)event_handler, prtd, stream_id,
 352                                LEGACY_PCM_MODE);
 353        if (IS_ERR(prtd->audio_client)) {
 354                pr_info("%s: Could not allocate memory\n", __func__);
 355                ret = PTR_ERR(prtd->audio_client);
 356                kfree(prtd);
 357                return ret;
 358        }
 359
 360        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 361                runtime->hw = q6asm_dai_hardware_playback;
 362        else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
 363                runtime->hw = q6asm_dai_hardware_capture;
 364
 365        ret = snd_pcm_hw_constraint_list(runtime, 0,
 366                                SNDRV_PCM_HW_PARAM_RATE,
 367                                &constraints_sample_rates);
 368        if (ret < 0)
 369                pr_info("snd_pcm_hw_constraint_list failed\n");
 370        /* Ensure that buffer size is a multiple of period size */
 371        ret = snd_pcm_hw_constraint_integer(runtime,
 372                                            SNDRV_PCM_HW_PARAM_PERIODS);
 373        if (ret < 0)
 374                pr_info("snd_pcm_hw_constraint_integer failed\n");
 375
 376        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 377                ret = snd_pcm_hw_constraint_minmax(runtime,
 378                        SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
 379                        PLAYBACK_MIN_NUM_PERIODS * PLAYBACK_MIN_PERIOD_SIZE,
 380                        PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE);
 381                if (ret < 0) {
 382                        pr_err("constraint for buffer bytes min max ret = %d\n",
 383                                                                        ret);
 384                }
 385        }
 386
 387        ret = snd_pcm_hw_constraint_step(runtime, 0,
 388                SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
 389        if (ret < 0) {
 390                pr_err("constraint for period bytes step ret = %d\n",
 391                                                                ret);
 392        }
 393        ret = snd_pcm_hw_constraint_step(runtime, 0,
 394                SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
 395        if (ret < 0) {
 396                pr_err("constraint for buffer bytes step ret = %d\n",
 397                                                                ret);
 398        }
 399
 400        runtime->private_data = prtd;
 401
 402        snd_soc_set_runtime_hwparams(substream, &q6asm_dai_hardware_playback);
 403
 404        runtime->dma_bytes = q6asm_dai_hardware_playback.buffer_bytes_max;
 405
 406
 407        if (pdata->sid < 0)
 408                prtd->phys = substream->dma_buffer.addr;
 409        else
 410                prtd->phys = substream->dma_buffer.addr | (pdata->sid << 32);
 411
 412        snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
 413
 414        return 0;
 415}
 416
 417static int q6asm_dai_close(struct snd_pcm_substream *substream)
 418{
 419        struct snd_pcm_runtime *runtime = substream->runtime;
 420        struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
 421        struct q6asm_dai_rtd *prtd = runtime->private_data;
 422
 423        if (prtd->audio_client) {
 424                if (prtd->state)
 425                        q6asm_cmd(prtd->audio_client, CMD_CLOSE);
 426
 427                q6asm_unmap_memory_regions(substream->stream,
 428                                           prtd->audio_client);
 429                q6asm_audio_client_free(prtd->audio_client);
 430                prtd->audio_client = NULL;
 431        }
 432        q6routing_stream_close(soc_prtd->dai_link->id,
 433                                                substream->stream);
 434        kfree(prtd);
 435        return 0;
 436}
 437
 438static snd_pcm_uframes_t q6asm_dai_pointer(struct snd_pcm_substream *substream)
 439{
 440
 441        struct snd_pcm_runtime *runtime = substream->runtime;
 442        struct q6asm_dai_rtd *prtd = runtime->private_data;
 443
 444        if (prtd->pcm_irq_pos >= prtd->pcm_size)
 445                prtd->pcm_irq_pos = 0;
 446
 447        return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
 448}
 449
 450static int q6asm_dai_mmap(struct snd_pcm_substream *substream,
 451                                struct vm_area_struct *vma)
 452{
 453
 454        struct snd_pcm_runtime *runtime = substream->runtime;
 455        struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
 456        struct snd_soc_component *c = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
 457        struct device *dev = c->dev;
 458
 459        return dma_mmap_coherent(dev, vma,
 460                        runtime->dma_area, runtime->dma_addr,
 461                        runtime->dma_bytes);
 462}
 463
 464static int q6asm_dai_hw_params(struct snd_pcm_substream *substream,
 465                                struct snd_pcm_hw_params *params)
 466{
 467        struct snd_pcm_runtime *runtime = substream->runtime;
 468        struct q6asm_dai_rtd *prtd = runtime->private_data;
 469
 470        prtd->pcm_size = params_buffer_bytes(params);
 471        prtd->periods = params_periods(params);
 472
 473        switch (params_format(params)) {
 474        case SNDRV_PCM_FORMAT_S16_LE:
 475                prtd->bits_per_sample = 16;
 476                break;
 477        case SNDRV_PCM_FORMAT_S24_LE:
 478                prtd->bits_per_sample = 24;
 479                break;
 480        }
 481
 482        return 0;
 483}
 484
 485static struct snd_pcm_ops q6asm_dai_ops = {
 486        .open           = q6asm_dai_open,
 487        .hw_params      = q6asm_dai_hw_params,
 488        .close          = q6asm_dai_close,
 489        .ioctl          = snd_pcm_lib_ioctl,
 490        .prepare        = q6asm_dai_prepare,
 491        .trigger        = q6asm_dai_trigger,
 492        .pointer        = q6asm_dai_pointer,
 493        .mmap           = q6asm_dai_mmap,
 494};
 495
 496static void compress_event_handler(uint32_t opcode, uint32_t token,
 497                                   uint32_t *payload, void *priv)
 498{
 499        struct q6asm_dai_rtd *prtd = priv;
 500        struct snd_compr_stream *substream = prtd->cstream;
 501        unsigned long flags;
 502        uint64_t avail;
 503
 504        switch (opcode) {
 505        case ASM_CLIENT_EVENT_CMD_RUN_DONE:
 506                spin_lock_irqsave(&prtd->lock, flags);
 507                if (!prtd->bytes_sent) {
 508                        q6asm_write_async(prtd->audio_client, prtd->pcm_count,
 509                                          0, 0, NO_TIMESTAMP);
 510                        prtd->bytes_sent += prtd->pcm_count;
 511                }
 512
 513                spin_unlock_irqrestore(&prtd->lock, flags);
 514                break;
 515
 516        case ASM_CLIENT_EVENT_CMD_EOS_DONE:
 517                prtd->state = Q6ASM_STREAM_STOPPED;
 518                break;
 519
 520        case ASM_CLIENT_EVENT_DATA_WRITE_DONE:
 521                spin_lock_irqsave(&prtd->lock, flags);
 522
 523                prtd->copied_total += prtd->pcm_count;
 524                snd_compr_fragment_elapsed(substream);
 525
 526                if (prtd->state != Q6ASM_STREAM_RUNNING) {
 527                        spin_unlock_irqrestore(&prtd->lock, flags);
 528                        break;
 529                }
 530
 531                avail = prtd->bytes_received - prtd->bytes_sent;
 532
 533                if (avail >= prtd->pcm_count) {
 534                        q6asm_write_async(prtd->audio_client,
 535                                           prtd->pcm_count, 0, 0, NO_TIMESTAMP);
 536                        prtd->bytes_sent += prtd->pcm_count;
 537                }
 538
 539                spin_unlock_irqrestore(&prtd->lock, flags);
 540                break;
 541
 542        default:
 543                break;
 544        }
 545}
 546
 547static int q6asm_dai_compr_open(struct snd_compr_stream *stream)
 548{
 549        struct snd_soc_pcm_runtime *rtd = stream->private_data;
 550        struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 551        struct snd_compr_runtime *runtime = stream->runtime;
 552        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 553        struct q6asm_dai_data *pdata;
 554        struct device *dev = c->dev;
 555        struct q6asm_dai_rtd *prtd;
 556        int stream_id, size, ret;
 557
 558        stream_id = cpu_dai->driver->id;
 559        pdata = snd_soc_component_get_drvdata(c);
 560        if (!pdata) {
 561                dev_err(dev, "Drv data not found ..\n");
 562                return -EINVAL;
 563        }
 564
 565        prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
 566        if (!prtd)
 567                return -ENOMEM;
 568
 569        prtd->cstream = stream;
 570        prtd->audio_client = q6asm_audio_client_alloc(dev,
 571                                        (q6asm_cb)compress_event_handler,
 572                                        prtd, stream_id, LEGACY_PCM_MODE);
 573        if (IS_ERR(prtd->audio_client)) {
 574                dev_err(dev, "Could not allocate memory\n");
 575                ret = PTR_ERR(prtd->audio_client);
 576                goto free_prtd;
 577        }
 578
 579        size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE *
 580                        COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
 581        ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size,
 582                                  &prtd->dma_buffer);
 583        if (ret) {
 584                dev_err(dev, "Cannot allocate buffer(s)\n");
 585                goto free_client;
 586        }
 587
 588        if (pdata->sid < 0)
 589                prtd->phys = prtd->dma_buffer.addr;
 590        else
 591                prtd->phys = prtd->dma_buffer.addr | (pdata->sid << 32);
 592
 593        snd_compr_set_runtime_buffer(stream, &prtd->dma_buffer);
 594        spin_lock_init(&prtd->lock);
 595        runtime->private_data = prtd;
 596
 597        return 0;
 598
 599free_client:
 600        q6asm_audio_client_free(prtd->audio_client);
 601free_prtd:
 602        kfree(prtd);
 603
 604        return ret;
 605}
 606
 607static int q6asm_dai_compr_free(struct snd_compr_stream *stream)
 608{
 609        struct snd_compr_runtime *runtime = stream->runtime;
 610        struct q6asm_dai_rtd *prtd = runtime->private_data;
 611        struct snd_soc_pcm_runtime *rtd = stream->private_data;
 612
 613        if (prtd->audio_client) {
 614                if (prtd->state)
 615                        q6asm_cmd(prtd->audio_client, CMD_CLOSE);
 616
 617                snd_dma_free_pages(&prtd->dma_buffer);
 618                q6asm_unmap_memory_regions(stream->direction,
 619                                           prtd->audio_client);
 620                q6asm_audio_client_free(prtd->audio_client);
 621                prtd->audio_client = NULL;
 622        }
 623        q6routing_stream_close(rtd->dai_link->id, stream->direction);
 624        kfree(prtd);
 625
 626        return 0;
 627}
 628
 629static int q6asm_dai_compr_set_params(struct snd_compr_stream *stream,
 630                                      struct snd_compr_params *params)
 631{
 632        struct snd_compr_runtime *runtime = stream->runtime;
 633        struct q6asm_dai_rtd *prtd = runtime->private_data;
 634        struct snd_soc_pcm_runtime *rtd = stream->private_data;
 635        struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 636        int dir = stream->direction;
 637        struct q6asm_dai_data *pdata;
 638        struct device *dev = c->dev;
 639        int ret;
 640
 641        memcpy(&prtd->codec_param, params, sizeof(*params));
 642
 643        pdata = snd_soc_component_get_drvdata(c);
 644        if (!pdata)
 645                return -EINVAL;
 646
 647        if (!prtd || !prtd->audio_client) {
 648                dev_err(dev, "private data null or audio client freed\n");
 649                return -EINVAL;
 650        }
 651
 652        prtd->periods = runtime->fragments;
 653        prtd->pcm_count = runtime->fragment_size;
 654        prtd->pcm_size = runtime->fragments * runtime->fragment_size;
 655        prtd->bits_per_sample = 16;
 656        if (dir == SND_COMPRESS_PLAYBACK) {
 657                ret = q6asm_open_write(prtd->audio_client, params->codec.id,
 658                                        prtd->bits_per_sample);
 659
 660                if (ret < 0) {
 661                        dev_err(dev, "q6asm_open_write failed\n");
 662                        q6asm_audio_client_free(prtd->audio_client);
 663                        prtd->audio_client = NULL;
 664                        return ret;
 665                }
 666        }
 667
 668        prtd->session_id = q6asm_get_session_id(prtd->audio_client);
 669        ret = q6routing_stream_open(rtd->dai_link->id, LEGACY_PCM_MODE,
 670                              prtd->session_id, dir);
 671        if (ret) {
 672                dev_err(dev, "Stream reg failed ret:%d\n", ret);
 673                return ret;
 674        }
 675
 676        ret = q6asm_map_memory_regions(dir, prtd->audio_client, prtd->phys,
 677                                       (prtd->pcm_size / prtd->periods),
 678                                       prtd->periods);
 679
 680        if (ret < 0) {
 681                dev_err(dev, "Buffer Mapping failed ret:%d\n", ret);
 682                return -ENOMEM;
 683        }
 684
 685        prtd->state = Q6ASM_STREAM_RUNNING;
 686
 687        return 0;
 688}
 689
 690static int q6asm_dai_compr_trigger(struct snd_compr_stream *stream, int cmd)
 691{
 692        struct snd_compr_runtime *runtime = stream->runtime;
 693        struct q6asm_dai_rtd *prtd = runtime->private_data;
 694        int ret = 0;
 695
 696        switch (cmd) {
 697        case SNDRV_PCM_TRIGGER_START:
 698        case SNDRV_PCM_TRIGGER_RESUME:
 699        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 700                ret = q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
 701                break;
 702        case SNDRV_PCM_TRIGGER_STOP:
 703                prtd->state = Q6ASM_STREAM_STOPPED;
 704                ret = q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
 705                break;
 706        case SNDRV_PCM_TRIGGER_SUSPEND:
 707        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 708                ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
 709                break;
 710        default:
 711                ret = -EINVAL;
 712                break;
 713        }
 714
 715        return ret;
 716}
 717
 718static int q6asm_dai_compr_pointer(struct snd_compr_stream *stream,
 719                struct snd_compr_tstamp *tstamp)
 720{
 721        struct snd_compr_runtime *runtime = stream->runtime;
 722        struct q6asm_dai_rtd *prtd = runtime->private_data;
 723        unsigned long flags;
 724
 725        spin_lock_irqsave(&prtd->lock, flags);
 726
 727        tstamp->copied_total = prtd->copied_total;
 728        tstamp->byte_offset = prtd->copied_total % prtd->pcm_size;
 729
 730        spin_unlock_irqrestore(&prtd->lock, flags);
 731
 732        return 0;
 733}
 734
 735static int q6asm_dai_compr_ack(struct snd_compr_stream *stream,
 736                                size_t count)
 737{
 738        struct snd_compr_runtime *runtime = stream->runtime;
 739        struct q6asm_dai_rtd *prtd = runtime->private_data;
 740        unsigned long flags;
 741
 742        spin_lock_irqsave(&prtd->lock, flags);
 743        prtd->bytes_received += count;
 744        spin_unlock_irqrestore(&prtd->lock, flags);
 745
 746        return count;
 747}
 748
 749static int q6asm_dai_compr_mmap(struct snd_compr_stream *stream,
 750                struct vm_area_struct *vma)
 751{
 752        struct snd_compr_runtime *runtime = stream->runtime;
 753        struct q6asm_dai_rtd *prtd = runtime->private_data;
 754        struct snd_soc_pcm_runtime *rtd = stream->private_data;
 755        struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 756        struct device *dev = c->dev;
 757
 758        return dma_mmap_coherent(dev, vma,
 759                        prtd->dma_buffer.area, prtd->dma_buffer.addr,
 760                        prtd->dma_buffer.bytes);
 761}
 762
 763static int q6asm_dai_compr_get_caps(struct snd_compr_stream *stream,
 764                                    struct snd_compr_caps *caps)
 765{
 766        caps->direction = SND_COMPRESS_PLAYBACK;
 767        caps->min_fragment_size = COMPR_PLAYBACK_MIN_FRAGMENT_SIZE;
 768        caps->max_fragment_size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE;
 769        caps->min_fragments = COMPR_PLAYBACK_MIN_NUM_FRAGMENTS;
 770        caps->max_fragments = COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
 771        caps->num_codecs = 1;
 772        caps->codecs[0] = SND_AUDIOCODEC_MP3;
 773
 774        return 0;
 775}
 776
 777static int q6asm_dai_compr_get_codec_caps(struct snd_compr_stream *stream,
 778                                          struct snd_compr_codec_caps *codec)
 779{
 780        switch (codec->codec) {
 781        case SND_AUDIOCODEC_MP3:
 782                *codec = q6asm_compr_caps;
 783                break;
 784        default:
 785                break;
 786        }
 787
 788        return 0;
 789}
 790
 791static struct snd_compr_ops q6asm_dai_compr_ops = {
 792        .open           = q6asm_dai_compr_open,
 793        .free           = q6asm_dai_compr_free,
 794        .set_params     = q6asm_dai_compr_set_params,
 795        .pointer        = q6asm_dai_compr_pointer,
 796        .trigger        = q6asm_dai_compr_trigger,
 797        .get_caps       = q6asm_dai_compr_get_caps,
 798        .get_codec_caps = q6asm_dai_compr_get_codec_caps,
 799        .mmap           = q6asm_dai_compr_mmap,
 800        .ack            = q6asm_dai_compr_ack,
 801};
 802
 803static int q6asm_dai_pcm_new(struct snd_soc_pcm_runtime *rtd)
 804{
 805        struct snd_pcm_substream *psubstream, *csubstream;
 806        struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 807        struct snd_pcm *pcm = rtd->pcm;
 808        struct device *dev;
 809        int size, ret;
 810
 811        dev = c->dev;
 812        size = q6asm_dai_hardware_playback.buffer_bytes_max;
 813        psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
 814        if (psubstream) {
 815                ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size,
 816                                          &psubstream->dma_buffer);
 817                if (ret) {
 818                        dev_err(dev, "Cannot allocate buffer(s)\n");
 819                        return ret;
 820                }
 821        }
 822
 823        csubstream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
 824        if (csubstream) {
 825                ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size,
 826                                          &csubstream->dma_buffer);
 827                if (ret) {
 828                        dev_err(dev, "Cannot allocate buffer(s)\n");
 829                        if (psubstream)
 830                                snd_dma_free_pages(&psubstream->dma_buffer);
 831                        return ret;
 832                }
 833        }
 834
 835        return 0;
 836}
 837
 838static void q6asm_dai_pcm_free(struct snd_pcm *pcm)
 839{
 840        struct snd_pcm_substream *substream;
 841        int i;
 842
 843        for (i = 0; i < ARRAY_SIZE(pcm->streams); i++) {
 844                substream = pcm->streams[i].substream;
 845                if (substream) {
 846                        snd_dma_free_pages(&substream->dma_buffer);
 847                        substream->dma_buffer.area = NULL;
 848                        substream->dma_buffer.addr = 0;
 849                }
 850        }
 851}
 852
 853static const struct snd_soc_component_driver q6asm_fe_dai_component = {
 854        .name           = DRV_NAME,
 855        .ops            = &q6asm_dai_ops,
 856        .pcm_new        = q6asm_dai_pcm_new,
 857        .pcm_free       = q6asm_dai_pcm_free,
 858        .compr_ops      = &q6asm_dai_compr_ops,
 859};
 860
 861static struct snd_soc_dai_driver q6asm_fe_dais[] = {
 862        Q6ASM_FEDAI_DRIVER(1),
 863        Q6ASM_FEDAI_DRIVER(2),
 864        Q6ASM_FEDAI_DRIVER(3),
 865        Q6ASM_FEDAI_DRIVER(4),
 866        Q6ASM_FEDAI_DRIVER(5),
 867        Q6ASM_FEDAI_DRIVER(6),
 868        Q6ASM_FEDAI_DRIVER(7),
 869        Q6ASM_FEDAI_DRIVER(8),
 870};
 871
 872static int of_q6asm_parse_dai_data(struct device *dev,
 873                                    struct q6asm_dai_data *pdata)
 874{
 875        static struct snd_soc_dai_driver *dai_drv;
 876        struct snd_soc_pcm_stream empty_stream;
 877        struct device_node *node;
 878        int ret, id, dir;
 879
 880        memset(&empty_stream, 0, sizeof(empty_stream));
 881
 882        for_each_child_of_node(dev->of_node, node) {
 883                ret = of_property_read_u32(node, "reg", &id);
 884                if (ret || id >= MAX_SESSIONS || id < 0) {
 885                        dev_err(dev, "valid dai id not found:%d\n", ret);
 886                        continue;
 887                }
 888
 889                dai_drv = &q6asm_fe_dais[id];
 890
 891                ret = of_property_read_u32(node, "direction", &dir);
 892                if (ret)
 893                        continue;
 894
 895                if (dir == Q6ASM_DAI_RX)
 896                        dai_drv->capture = empty_stream;
 897                else if (dir == Q6ASM_DAI_TX)
 898                        dai_drv->playback = empty_stream;
 899
 900                if (of_property_read_bool(node, "is-compress-dai"))
 901                        dai_drv->compress_new = snd_soc_new_compress;
 902        }
 903
 904        return 0;
 905}
 906
 907static int q6asm_dai_probe(struct platform_device *pdev)
 908{
 909        struct device *dev = &pdev->dev;
 910        struct device_node *node = dev->of_node;
 911        struct of_phandle_args args;
 912        struct q6asm_dai_data *pdata;
 913        int rc;
 914
 915        pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
 916        if (!pdata)
 917                return -ENOMEM;
 918
 919        rc = of_parse_phandle_with_fixed_args(node, "iommus", 1, 0, &args);
 920        if (rc < 0)
 921                pdata->sid = -1;
 922        else
 923                pdata->sid = args.args[0] & SID_MASK_DEFAULT;
 924
 925        dev_set_drvdata(dev, pdata);
 926
 927        of_q6asm_parse_dai_data(dev, pdata);
 928
 929        return devm_snd_soc_register_component(dev, &q6asm_fe_dai_component,
 930                                        q6asm_fe_dais,
 931                                        ARRAY_SIZE(q6asm_fe_dais));
 932}
 933
 934static const struct of_device_id q6asm_dai_device_id[] = {
 935        { .compatible = "qcom,q6asm-dais" },
 936        {},
 937};
 938MODULE_DEVICE_TABLE(of, q6asm_dai_device_id);
 939
 940static struct platform_driver q6asm_dai_platform_driver = {
 941        .driver = {
 942                .name = "q6asm-dai",
 943                .of_match_table = of_match_ptr(q6asm_dai_device_id),
 944        },
 945        .probe = q6asm_dai_probe,
 946};
 947module_platform_driver(q6asm_dai_platform_driver);
 948
 949MODULE_DESCRIPTION("Q6ASM dai driver");
 950MODULE_LICENSE("GPL v2");
 951