linux/sound/soc/qcom/qdsp6/q6asm.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/mutex.h>
   6#include <linux/wait.h>
   7#include <linux/module.h>
   8#include <linux/soc/qcom/apr.h>
   9#include <linux/device.h>
  10#include <linux/of_platform.h>
  11#include <linux/spinlock.h>
  12#include <linux/kref.h>
  13#include <linux/of.h>
  14#include <uapi/sound/asound.h>
  15#include <uapi/sound/compress_params.h>
  16#include <linux/delay.h>
  17#include <linux/slab.h>
  18#include <linux/mm.h>
  19#include "q6asm.h"
  20#include "q6core.h"
  21#include "q6dsp-errno.h"
  22#include "q6dsp-common.h"
  23
  24#define ASM_STREAM_CMD_CLOSE                    0x00010BCD
  25#define ASM_STREAM_CMD_FLUSH                    0x00010BCE
  26#define ASM_SESSION_CMD_PAUSE                   0x00010BD3
  27#define ASM_DATA_CMD_EOS                        0x00010BDB
  28#define ASM_NULL_POPP_TOPOLOGY                  0x00010C68
  29#define ASM_STREAM_CMD_FLUSH_READBUFS           0x00010C09
  30#define ASM_STREAM_CMD_SET_ENCDEC_PARAM         0x00010C10
  31#define ASM_STREAM_POSTPROC_TOPO_ID_NONE        0x00010C68
  32#define ASM_CMD_SHARED_MEM_MAP_REGIONS          0x00010D92
  33#define ASM_CMDRSP_SHARED_MEM_MAP_REGIONS       0x00010D93
  34#define ASM_CMD_SHARED_MEM_UNMAP_REGIONS        0x00010D94
  35#define ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2        0x00010D98
  36#define ASM_DATA_EVENT_WRITE_DONE_V2            0x00010D99
  37#define ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2      0x00010DA3
  38#define ASM_SESSION_CMD_RUN_V2                  0x00010DAA
  39#define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2      0x00010DA5
  40#define ASM_MEDIA_FMT_MP3                       0x00010BE9
  41#define ASM_DATA_CMD_WRITE_V2                   0x00010DAB
  42#define ASM_DATA_CMD_READ_V2                    0x00010DAC
  43#define ASM_SESSION_CMD_SUSPEND                 0x00010DEC
  44#define ASM_STREAM_CMD_OPEN_WRITE_V3            0x00010DB3
  45#define ASM_STREAM_CMD_OPEN_READ_V3                 0x00010DB4
  46#define ASM_DATA_EVENT_READ_DONE_V2 0x00010D9A
  47#define ASM_STREAM_CMD_OPEN_READWRITE_V2        0x00010D8D
  48
  49
  50#define ASM_LEGACY_STREAM_SESSION       0
  51/* Bit shift for the stream_perf_mode subfield. */
  52#define ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ              29
  53#define ASM_END_POINT_DEVICE_MATRIX     0
  54#define ASM_DEFAULT_APP_TYPE            0
  55#define ASM_SYNC_IO_MODE                0x0001
  56#define ASM_ASYNC_IO_MODE               0x0002
  57#define ASM_TUN_READ_IO_MODE            0x0004  /* tunnel read write mode */
  58#define ASM_TUN_WRITE_IO_MODE           0x0008  /* tunnel read write mode */
  59#define ASM_SHIFT_GAPLESS_MODE_FLAG     31
  60#define ADSP_MEMORY_MAP_SHMEM8_4K_POOL  3
  61
  62struct avs_cmd_shared_mem_map_regions {
  63        u16 mem_pool_id;
  64        u16 num_regions;
  65        u32 property_flag;
  66} __packed;
  67
  68struct avs_shared_map_region_payload {
  69        u32 shm_addr_lsw;
  70        u32 shm_addr_msw;
  71        u32 mem_size_bytes;
  72} __packed;
  73
  74struct avs_cmd_shared_mem_unmap_regions {
  75        u32 mem_map_handle;
  76} __packed;
  77
  78struct asm_data_cmd_media_fmt_update_v2 {
  79        u32 fmt_blk_size;
  80} __packed;
  81
  82struct asm_multi_channel_pcm_fmt_blk_v2 {
  83        struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
  84        u16 num_channels;
  85        u16 bits_per_sample;
  86        u32 sample_rate;
  87        u16 is_signed;
  88        u16 reserved;
  89        u8 channel_mapping[PCM_MAX_NUM_CHANNEL];
  90} __packed;
  91
  92struct asm_stream_cmd_set_encdec_param {
  93        u32                  param_id;
  94        u32                  param_size;
  95} __packed;
  96
  97struct asm_enc_cfg_blk_param_v2 {
  98        u32                  frames_per_buf;
  99        u32                  enc_cfg_blk_size;
 100} __packed;
 101
 102struct asm_multi_channel_pcm_enc_cfg_v2 {
 103        struct asm_stream_cmd_set_encdec_param  encdec;
 104        struct asm_enc_cfg_blk_param_v2 encblk;
 105        uint16_t  num_channels;
 106        uint16_t  bits_per_sample;
 107        uint32_t  sample_rate;
 108        uint16_t  is_signed;
 109        uint16_t  reserved;
 110        uint8_t   channel_mapping[8];
 111} __packed;
 112
 113struct asm_data_cmd_read_v2 {
 114        u32                  buf_addr_lsw;
 115        u32                  buf_addr_msw;
 116        u32                  mem_map_handle;
 117        u32                  buf_size;
 118        u32                  seq_id;
 119} __packed;
 120
 121struct asm_data_cmd_read_v2_done {
 122        u32     status;
 123        u32     buf_addr_lsw;
 124        u32     buf_addr_msw;
 125};
 126
 127struct asm_stream_cmd_open_read_v3 {
 128        u32                    mode_flags;
 129        u32                    src_endpointype;
 130        u32                    preprocopo_id;
 131        u32                    enc_cfg_id;
 132        u16                    bits_per_sample;
 133        u16                    reserved;
 134} __packed;
 135
 136struct asm_data_cmd_write_v2 {
 137        u32 buf_addr_lsw;
 138        u32 buf_addr_msw;
 139        u32 mem_map_handle;
 140        u32 buf_size;
 141        u32 seq_id;
 142        u32 timestamp_lsw;
 143        u32 timestamp_msw;
 144        u32 flags;
 145} __packed;
 146
 147struct asm_stream_cmd_open_write_v3 {
 148        uint32_t mode_flags;
 149        uint16_t sink_endpointype;
 150        uint16_t bits_per_sample;
 151        uint32_t postprocopo_id;
 152        uint32_t dec_fmt_id;
 153} __packed;
 154
 155struct asm_session_cmd_run_v2 {
 156        u32 flags;
 157        u32 time_lsw;
 158        u32 time_msw;
 159} __packed;
 160
 161struct audio_buffer {
 162        phys_addr_t phys;
 163        uint32_t size;          /* size of buffer */
 164};
 165
 166struct audio_port_data {
 167        struct audio_buffer *buf;
 168        uint32_t num_periods;
 169        uint32_t dsp_buf;
 170        uint32_t mem_map_handle;
 171};
 172
 173struct q6asm {
 174        struct apr_device *adev;
 175        struct device *dev;
 176        struct q6core_svc_api_info ainfo;
 177        wait_queue_head_t mem_wait;
 178        spinlock_t slock;
 179        struct audio_client *session[MAX_SESSIONS + 1];
 180};
 181
 182struct audio_client {
 183        int session;
 184        q6asm_cb cb;
 185        void *priv;
 186        uint32_t io_mode;
 187        struct apr_device *adev;
 188        struct mutex cmd_lock;
 189        spinlock_t lock;
 190        struct kref refcount;
 191        /* idx:1 out port, 0: in port */
 192        struct audio_port_data port[2];
 193        wait_queue_head_t cmd_wait;
 194        struct aprv2_ibasic_rsp_result_t result;
 195        int perf_mode;
 196        int stream_id;
 197        struct q6asm *q6asm;
 198        struct device *dev;
 199};
 200
 201static inline void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
 202                                 uint32_t pkt_size, bool cmd_flg,
 203                                 uint32_t stream_id)
 204{
 205        hdr->hdr_field = APR_SEQ_CMD_HDR_FIELD;
 206        hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id);
 207        hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id);
 208        hdr->pkt_size = pkt_size;
 209        if (cmd_flg)
 210                hdr->token = ac->session;
 211}
 212
 213static int q6asm_apr_send_session_pkt(struct q6asm *a, struct audio_client *ac,
 214                                      struct apr_pkt *pkt, uint32_t rsp_opcode)
 215{
 216        struct apr_hdr *hdr = &pkt->hdr;
 217        int rc;
 218
 219        mutex_lock(&ac->cmd_lock);
 220        ac->result.opcode = 0;
 221        ac->result.status = 0;
 222        rc = apr_send_pkt(a->adev, pkt);
 223        if (rc < 0)
 224                goto err;
 225
 226        if (rsp_opcode)
 227                rc = wait_event_timeout(a->mem_wait,
 228                                        (ac->result.opcode == hdr->opcode) ||
 229                                        (ac->result.opcode == rsp_opcode),
 230                                        5 * HZ);
 231        else
 232                rc = wait_event_timeout(a->mem_wait,
 233                                        (ac->result.opcode == hdr->opcode),
 234                                        5 * HZ);
 235
 236        if (!rc) {
 237                dev_err(a->dev, "CMD timeout\n");
 238                rc = -ETIMEDOUT;
 239        } else if (ac->result.status > 0) {
 240                dev_err(a->dev, "DSP returned error[%x]\n",
 241                        ac->result.status);
 242                rc = -EINVAL;
 243        }
 244
 245err:
 246        mutex_unlock(&ac->cmd_lock);
 247        return rc;
 248}
 249
 250static int __q6asm_memory_unmap(struct audio_client *ac,
 251                                phys_addr_t buf_add, int dir)
 252{
 253        struct avs_cmd_shared_mem_unmap_regions *mem_unmap;
 254        struct q6asm *a = dev_get_drvdata(ac->dev->parent);
 255        struct apr_pkt *pkt;
 256        int rc, pkt_size;
 257        void *p;
 258
 259        if (ac->port[dir].mem_map_handle == 0) {
 260                dev_err(ac->dev, "invalid mem handle\n");
 261                return -EINVAL;
 262        }
 263
 264        pkt_size = APR_HDR_SIZE + sizeof(*mem_unmap);
 265        p = kzalloc(pkt_size, GFP_KERNEL);
 266        if (!p)
 267                return -ENOMEM;
 268
 269        pkt = p;
 270        mem_unmap = p + APR_HDR_SIZE;
 271
 272        pkt->hdr.hdr_field = APR_SEQ_CMD_HDR_FIELD;
 273        pkt->hdr.src_port = 0;
 274        pkt->hdr.dest_port = 0;
 275        pkt->hdr.pkt_size = pkt_size;
 276        pkt->hdr.token = ((ac->session << 8) | dir);
 277
 278        pkt->hdr.opcode = ASM_CMD_SHARED_MEM_UNMAP_REGIONS;
 279        mem_unmap->mem_map_handle = ac->port[dir].mem_map_handle;
 280
 281        rc = q6asm_apr_send_session_pkt(a, ac, pkt, 0);
 282        if (rc < 0) {
 283                kfree(pkt);
 284                return rc;
 285        }
 286
 287        ac->port[dir].mem_map_handle = 0;
 288
 289        kfree(pkt);
 290        return 0;
 291}
 292
 293
 294static void q6asm_audio_client_free_buf(struct audio_client *ac,
 295                                        struct audio_port_data *port)
 296{
 297        unsigned long flags;
 298
 299        spin_lock_irqsave(&ac->lock, flags);
 300        port->num_periods = 0;
 301        kfree(port->buf);
 302        port->buf = NULL;
 303        spin_unlock_irqrestore(&ac->lock, flags);
 304}
 305
 306/**
 307 * q6asm_unmap_memory_regions() - unmap memory regions in the dsp.
 308 *
 309 * @dir: direction of audio stream
 310 * @ac: audio client instanace
 311 *
 312 * Return: Will be an negative value on failure or zero on success
 313 */
 314int q6asm_unmap_memory_regions(unsigned int dir, struct audio_client *ac)
 315{
 316        struct audio_port_data *port;
 317        int cnt = 0;
 318        int rc = 0;
 319
 320        port = &ac->port[dir];
 321        if (!port->buf) {
 322                rc = -EINVAL;
 323                goto err;
 324        }
 325
 326        cnt = port->num_periods - 1;
 327        if (cnt >= 0) {
 328                rc = __q6asm_memory_unmap(ac, port->buf[dir].phys, dir);
 329                if (rc < 0) {
 330                        dev_err(ac->dev, "%s: Memory_unmap_regions failed %d\n",
 331                                __func__, rc);
 332                        goto err;
 333                }
 334        }
 335
 336        q6asm_audio_client_free_buf(ac, port);
 337
 338err:
 339        return rc;
 340}
 341EXPORT_SYMBOL_GPL(q6asm_unmap_memory_regions);
 342
 343static int __q6asm_memory_map_regions(struct audio_client *ac, int dir,
 344                                      size_t period_sz, unsigned int periods,
 345                                      bool is_contiguous)
 346{
 347        struct avs_cmd_shared_mem_map_regions *cmd = NULL;
 348        struct avs_shared_map_region_payload *mregions = NULL;
 349        struct q6asm *a = dev_get_drvdata(ac->dev->parent);
 350        struct audio_port_data *port = NULL;
 351        struct audio_buffer *ab = NULL;
 352        struct apr_pkt *pkt;
 353        void *p;
 354        unsigned long flags;
 355        uint32_t num_regions, buf_sz;
 356        int rc, i, pkt_size;
 357
 358        if (is_contiguous) {
 359                num_regions = 1;
 360                buf_sz = period_sz * periods;
 361        } else {
 362                buf_sz = period_sz;
 363                num_regions = periods;
 364        }
 365
 366        /* DSP expects size should be aligned to 4K */
 367        buf_sz = ALIGN(buf_sz, 4096);
 368
 369        pkt_size = APR_HDR_SIZE + sizeof(*cmd) +
 370                   (sizeof(*mregions) * num_regions);
 371
 372        p = kzalloc(pkt_size, GFP_KERNEL);
 373        if (!p)
 374                return -ENOMEM;
 375
 376        pkt = p;
 377        cmd = p + APR_HDR_SIZE;
 378        mregions = p + APR_HDR_SIZE +  sizeof(*cmd);
 379
 380        pkt->hdr.hdr_field = APR_SEQ_CMD_HDR_FIELD;
 381        pkt->hdr.src_port = 0;
 382        pkt->hdr.dest_port = 0;
 383        pkt->hdr.pkt_size = pkt_size;
 384        pkt->hdr.token = ((ac->session << 8) | dir);
 385        pkt->hdr.opcode = ASM_CMD_SHARED_MEM_MAP_REGIONS;
 386
 387        cmd->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
 388        cmd->num_regions = num_regions;
 389        cmd->property_flag = 0x00;
 390
 391        spin_lock_irqsave(&ac->lock, flags);
 392        port = &ac->port[dir];
 393
 394        for (i = 0; i < num_regions; i++) {
 395                ab = &port->buf[i];
 396                mregions->shm_addr_lsw = lower_32_bits(ab->phys);
 397                mregions->shm_addr_msw = upper_32_bits(ab->phys);
 398                mregions->mem_size_bytes = buf_sz;
 399                ++mregions;
 400        }
 401        spin_unlock_irqrestore(&ac->lock, flags);
 402
 403        rc = q6asm_apr_send_session_pkt(a, ac, pkt,
 404                                        ASM_CMDRSP_SHARED_MEM_MAP_REGIONS);
 405
 406        kfree(pkt);
 407
 408        return rc;
 409}
 410
 411/**
 412 * q6asm_map_memory_regions() - map memory regions in the dsp.
 413 *
 414 * @dir: direction of audio stream
 415 * @ac: audio client instanace
 416 * @phys: physcial address that needs mapping.
 417 * @period_sz: audio period size
 418 * @periods: number of periods
 419 *
 420 * Return: Will be an negative value on failure or zero on success
 421 */
 422int q6asm_map_memory_regions(unsigned int dir, struct audio_client *ac,
 423                             phys_addr_t phys,
 424                             size_t period_sz, unsigned int periods)
 425{
 426        struct audio_buffer *buf;
 427        unsigned long flags;
 428        int cnt;
 429        int rc;
 430
 431        spin_lock_irqsave(&ac->lock, flags);
 432        if (ac->port[dir].buf) {
 433                dev_err(ac->dev, "Buffer already allocated\n");
 434                spin_unlock_irqrestore(&ac->lock, flags);
 435                return 0;
 436        }
 437
 438        buf = kzalloc(((sizeof(struct audio_buffer)) * periods), GFP_ATOMIC);
 439        if (!buf) {
 440                spin_unlock_irqrestore(&ac->lock, flags);
 441                return -ENOMEM;
 442        }
 443
 444
 445        ac->port[dir].buf = buf;
 446
 447        buf[0].phys = phys;
 448        buf[0].size = period_sz;
 449
 450        for (cnt = 1; cnt < periods; cnt++) {
 451                if (period_sz > 0) {
 452                        buf[cnt].phys = buf[0].phys + (cnt * period_sz);
 453                        buf[cnt].size = period_sz;
 454                }
 455        }
 456        ac->port[dir].num_periods = periods;
 457
 458        spin_unlock_irqrestore(&ac->lock, flags);
 459
 460        rc = __q6asm_memory_map_regions(ac, dir, period_sz, periods, 1);
 461        if (rc < 0) {
 462                dev_err(ac->dev, "Memory_map_regions failed\n");
 463                q6asm_audio_client_free_buf(ac, &ac->port[dir]);
 464        }
 465
 466        return rc;
 467}
 468EXPORT_SYMBOL_GPL(q6asm_map_memory_regions);
 469
 470static void q6asm_audio_client_release(struct kref *ref)
 471{
 472        struct audio_client *ac;
 473        struct q6asm *a;
 474        unsigned long flags;
 475
 476        ac = container_of(ref, struct audio_client, refcount);
 477        a = ac->q6asm;
 478
 479        spin_lock_irqsave(&a->slock, flags);
 480        a->session[ac->session] = NULL;
 481        spin_unlock_irqrestore(&a->slock, flags);
 482
 483        kfree(ac);
 484}
 485
 486/**
 487 * q6asm_audio_client_free() - Freee allocated audio client
 488 *
 489 * @ac: audio client to free
 490 */
 491void q6asm_audio_client_free(struct audio_client *ac)
 492{
 493        kref_put(&ac->refcount, q6asm_audio_client_release);
 494}
 495EXPORT_SYMBOL_GPL(q6asm_audio_client_free);
 496
 497static struct audio_client *q6asm_get_audio_client(struct q6asm *a,
 498                                                   int session_id)
 499{
 500        struct audio_client *ac = NULL;
 501        unsigned long flags;
 502
 503        spin_lock_irqsave(&a->slock, flags);
 504        if ((session_id <= 0) || (session_id > MAX_SESSIONS)) {
 505                dev_err(a->dev, "invalid session: %d\n", session_id);
 506                goto err;
 507        }
 508
 509        /* check for valid session */
 510        if (!a->session[session_id])
 511                goto err;
 512        else if (a->session[session_id]->session != session_id)
 513                goto err;
 514
 515        ac = a->session[session_id];
 516        kref_get(&ac->refcount);
 517err:
 518        spin_unlock_irqrestore(&a->slock, flags);
 519        return ac;
 520}
 521
 522static int32_t q6asm_stream_callback(struct apr_device *adev,
 523                                     struct apr_resp_pkt *data,
 524                                     int session_id)
 525{
 526        struct q6asm *q6asm = dev_get_drvdata(&adev->dev);
 527        struct aprv2_ibasic_rsp_result_t *result;
 528        struct apr_hdr *hdr = &data->hdr;
 529        struct audio_port_data *port;
 530        struct audio_client *ac;
 531        uint32_t client_event = 0;
 532        int ret = 0;
 533
 534        ac = q6asm_get_audio_client(q6asm, session_id);
 535        if (!ac)/* Audio client might already be freed by now */
 536                return 0;
 537
 538        result = data->payload;
 539
 540        switch (hdr->opcode) {
 541        case APR_BASIC_RSP_RESULT:
 542                switch (result->opcode) {
 543                case ASM_SESSION_CMD_PAUSE:
 544                        client_event = ASM_CLIENT_EVENT_CMD_PAUSE_DONE;
 545                        break;
 546                case ASM_SESSION_CMD_SUSPEND:
 547                        client_event = ASM_CLIENT_EVENT_CMD_SUSPEND_DONE;
 548                        break;
 549                case ASM_DATA_CMD_EOS:
 550                        client_event = ASM_CLIENT_EVENT_CMD_EOS_DONE;
 551                        break;
 552                case ASM_STREAM_CMD_FLUSH:
 553                        client_event = ASM_CLIENT_EVENT_CMD_FLUSH_DONE;
 554                        break;
 555                case ASM_SESSION_CMD_RUN_V2:
 556                        client_event = ASM_CLIENT_EVENT_CMD_RUN_DONE;
 557                        break;
 558                case ASM_STREAM_CMD_CLOSE:
 559                        client_event = ASM_CLIENT_EVENT_CMD_CLOSE_DONE;
 560                        break;
 561                case ASM_STREAM_CMD_FLUSH_READBUFS:
 562                        client_event = ASM_CLIENT_EVENT_CMD_OUT_FLUSH_DONE;
 563                        break;
 564                case ASM_STREAM_CMD_OPEN_WRITE_V3:
 565                case ASM_STREAM_CMD_OPEN_READ_V3:
 566                case ASM_STREAM_CMD_OPEN_READWRITE_V2:
 567                case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
 568                case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
 569                        if (result->status != 0) {
 570                                dev_err(ac->dev,
 571                                        "cmd = 0x%x returned error = 0x%x\n",
 572                                        result->opcode, result->status);
 573                                ac->result = *result;
 574                                wake_up(&ac->cmd_wait);
 575                                ret = 0;
 576                                goto done;
 577                        }
 578                        break;
 579                default:
 580                        dev_err(ac->dev, "command[0x%x] not expecting rsp\n",
 581                                result->opcode);
 582                        break;
 583                }
 584
 585                ac->result = *result;
 586                wake_up(&ac->cmd_wait);
 587
 588                if (ac->cb)
 589                        ac->cb(client_event, hdr->token,
 590                               data->payload, ac->priv);
 591
 592                ret = 0;
 593                goto done;
 594
 595        case ASM_DATA_EVENT_WRITE_DONE_V2:
 596                client_event = ASM_CLIENT_EVENT_DATA_WRITE_DONE;
 597                if (ac->io_mode & ASM_SYNC_IO_MODE) {
 598                        phys_addr_t phys;
 599                        unsigned long flags;
 600
 601                        spin_lock_irqsave(&ac->lock, flags);
 602
 603                        port =  &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
 604
 605                        if (!port->buf) {
 606                                spin_unlock_irqrestore(&ac->lock, flags);
 607                                ret = 0;
 608                                goto done;
 609                        }
 610
 611                        phys = port->buf[hdr->token].phys;
 612
 613                        if (lower_32_bits(phys) != result->opcode ||
 614                            upper_32_bits(phys) != result->status) {
 615                                dev_err(ac->dev, "Expected addr %pa\n",
 616                                        &port->buf[hdr->token].phys);
 617                                spin_unlock_irqrestore(&ac->lock, flags);
 618                                ret = -EINVAL;
 619                                goto done;
 620                        }
 621                        spin_unlock_irqrestore(&ac->lock, flags);
 622                }
 623                break;
 624        case ASM_DATA_EVENT_READ_DONE_V2:
 625                client_event = ASM_CLIENT_EVENT_DATA_READ_DONE;
 626                if (ac->io_mode & ASM_SYNC_IO_MODE) {
 627                        struct asm_data_cmd_read_v2_done *done = data->payload;
 628                        unsigned long flags;
 629                        phys_addr_t phys;
 630
 631                        spin_lock_irqsave(&ac->lock, flags);
 632                        port =  &ac->port[SNDRV_PCM_STREAM_CAPTURE];
 633                        if (!port->buf) {
 634                                spin_unlock_irqrestore(&ac->lock, flags);
 635                                ret = 0;
 636                                goto done;
 637                        }
 638
 639                        phys = port->buf[hdr->token].phys;
 640
 641                        if (upper_32_bits(phys) != done->buf_addr_msw ||
 642                            lower_32_bits(phys) != done->buf_addr_lsw) {
 643                                dev_err(ac->dev, "Expected addr %pa %08x-%08x\n",
 644                                        &port->buf[hdr->token].phys,
 645                                        done->buf_addr_lsw,
 646                                        done->buf_addr_msw);
 647                                spin_unlock_irqrestore(&ac->lock, flags);
 648                                ret = -EINVAL;
 649                                goto done;
 650                        }
 651                        spin_unlock_irqrestore(&ac->lock, flags);
 652                }
 653
 654                break;
 655        }
 656
 657        if (ac->cb)
 658                ac->cb(client_event, hdr->token, data->payload, ac->priv);
 659
 660done:
 661        kref_put(&ac->refcount, q6asm_audio_client_release);
 662        return ret;
 663}
 664
 665static int q6asm_srvc_callback(struct apr_device *adev,
 666                               struct apr_resp_pkt *data)
 667{
 668        struct q6asm *q6asm = dev_get_drvdata(&adev->dev);
 669        struct aprv2_ibasic_rsp_result_t *result;
 670        struct audio_port_data *port;
 671        struct audio_client *ac = NULL;
 672        struct apr_hdr *hdr = &data->hdr;
 673        struct q6asm *a;
 674        uint32_t sid = 0;
 675        uint32_t dir = 0;
 676        int session_id;
 677
 678        session_id = (hdr->dest_port >> 8) & 0xFF;
 679        if (session_id)
 680                return q6asm_stream_callback(adev, data, session_id);
 681
 682        sid = (hdr->token >> 8) & 0x0F;
 683        ac = q6asm_get_audio_client(q6asm, sid);
 684        if (!ac) {
 685                dev_err(&adev->dev, "Audio Client not active\n");
 686                return 0;
 687        }
 688
 689        a = dev_get_drvdata(ac->dev->parent);
 690        dir = (hdr->token & 0x0F);
 691        port = &ac->port[dir];
 692        result = data->payload;
 693
 694        switch (hdr->opcode) {
 695        case APR_BASIC_RSP_RESULT:
 696                switch (result->opcode) {
 697                case ASM_CMD_SHARED_MEM_MAP_REGIONS:
 698                case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:
 699                        ac->result = *result;
 700                        wake_up(&a->mem_wait);
 701                        break;
 702                default:
 703                        dev_err(&adev->dev, "command[0x%x] not expecting rsp\n",
 704                                 result->opcode);
 705                        break;
 706                }
 707                goto done;
 708        case ASM_CMDRSP_SHARED_MEM_MAP_REGIONS:
 709                ac->result.status = 0;
 710                ac->result.opcode = hdr->opcode;
 711                port->mem_map_handle = result->opcode;
 712                wake_up(&a->mem_wait);
 713                break;
 714        case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:
 715                ac->result.opcode = hdr->opcode;
 716                ac->result.status = 0;
 717                port->mem_map_handle = 0;
 718                wake_up(&a->mem_wait);
 719                break;
 720        default:
 721                dev_dbg(&adev->dev, "command[0x%x]success [0x%x]\n",
 722                        result->opcode, result->status);
 723                break;
 724        }
 725
 726        if (ac->cb)
 727                ac->cb(hdr->opcode, hdr->token, data->payload, ac->priv);
 728
 729done:
 730        kref_put(&ac->refcount, q6asm_audio_client_release);
 731
 732        return 0;
 733}
 734
 735/**
 736 * q6asm_get_session_id() - get session id for audio client
 737 *
 738 * @c: audio client pointer
 739 *
 740 * Return: Will be an session id of the audio client.
 741 */
 742int q6asm_get_session_id(struct audio_client *c)
 743{
 744        return c->session;
 745}
 746EXPORT_SYMBOL_GPL(q6asm_get_session_id);
 747
 748/**
 749 * q6asm_audio_client_alloc() - Allocate a new audio client
 750 *
 751 * @dev: Pointer to asm child device.
 752 * @cb: event callback.
 753 * @priv: private data associated with this client.
 754 * @stream_id: stream id
 755 * @perf_mode: performace mode for this client
 756 *
 757 * Return: Will be an error pointer on error or a valid audio client
 758 * on success.
 759 */
 760struct audio_client *q6asm_audio_client_alloc(struct device *dev, q6asm_cb cb,
 761                                              void *priv, int stream_id,
 762                                              int perf_mode)
 763{
 764        struct q6asm *a = dev_get_drvdata(dev->parent);
 765        struct audio_client *ac;
 766        unsigned long flags;
 767
 768        ac = q6asm_get_audio_client(a, stream_id + 1);
 769        if (ac) {
 770                dev_err(dev, "Audio Client already active\n");
 771                return ac;
 772        }
 773
 774        ac = kzalloc(sizeof(*ac), GFP_KERNEL);
 775        if (!ac)
 776                return ERR_PTR(-ENOMEM);
 777
 778        spin_lock_irqsave(&a->slock, flags);
 779        a->session[stream_id + 1] = ac;
 780        spin_unlock_irqrestore(&a->slock, flags);
 781        ac->session = stream_id + 1;
 782        ac->cb = cb;
 783        ac->dev = dev;
 784        ac->q6asm = a;
 785        ac->priv = priv;
 786        ac->io_mode = ASM_SYNC_IO_MODE;
 787        ac->perf_mode = perf_mode;
 788        /* DSP expects stream id from 1 */
 789        ac->stream_id = 1;
 790        ac->adev = a->adev;
 791        kref_init(&ac->refcount);
 792
 793        init_waitqueue_head(&ac->cmd_wait);
 794        mutex_init(&ac->cmd_lock);
 795        spin_lock_init(&ac->lock);
 796
 797        return ac;
 798}
 799EXPORT_SYMBOL_GPL(q6asm_audio_client_alloc);
 800
 801static int q6asm_ac_send_cmd_sync(struct audio_client *ac, struct apr_pkt *pkt)
 802{
 803        struct apr_hdr *hdr = &pkt->hdr;
 804        int rc;
 805
 806        mutex_lock(&ac->cmd_lock);
 807        ac->result.opcode = 0;
 808        ac->result.status = 0;
 809
 810        rc = apr_send_pkt(ac->adev, pkt);
 811        if (rc < 0)
 812                goto err;
 813
 814        rc = wait_event_timeout(ac->cmd_wait,
 815                                (ac->result.opcode == hdr->opcode), 5 * HZ);
 816        if (!rc) {
 817                dev_err(ac->dev, "CMD timeout\n");
 818                rc =  -ETIMEDOUT;
 819                goto err;
 820        }
 821
 822        if (ac->result.status > 0) {
 823                dev_err(ac->dev, "DSP returned error[%x]\n",
 824                        ac->result.status);
 825                rc = -EINVAL;
 826        } else {
 827                rc = 0;
 828        }
 829
 830
 831err:
 832        mutex_unlock(&ac->cmd_lock);
 833        return rc;
 834}
 835
 836/**
 837 * q6asm_open_write() - Open audio client for writing
 838 *
 839 * @ac: audio client pointer
 840 * @format: audio sample format
 841 * @bits_per_sample: bits per sample
 842 *
 843 * Return: Will be an negative value on error or zero on success
 844 */
 845int q6asm_open_write(struct audio_client *ac, uint32_t format,
 846                     uint16_t bits_per_sample)
 847{
 848        struct asm_stream_cmd_open_write_v3 *open;
 849        struct apr_pkt *pkt;
 850        void *p;
 851        int rc, pkt_size;
 852
 853        pkt_size = APR_HDR_SIZE + sizeof(*open);
 854
 855        p = kzalloc(pkt_size, GFP_KERNEL);
 856        if (!p)
 857                return -ENOMEM;
 858
 859        pkt = p;
 860        open = p + APR_HDR_SIZE;
 861        q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
 862
 863        pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3;
 864        open->mode_flags = 0x00;
 865        open->mode_flags |= ASM_LEGACY_STREAM_SESSION;
 866
 867        /* source endpoint : matrix */
 868        open->sink_endpointype = ASM_END_POINT_DEVICE_MATRIX;
 869        open->bits_per_sample = bits_per_sample;
 870        open->postprocopo_id = ASM_NULL_POPP_TOPOLOGY;
 871
 872        switch (format) {
 873        case SND_AUDIOCODEC_MP3:
 874                open->dec_fmt_id = ASM_MEDIA_FMT_MP3;
 875                break;
 876        case FORMAT_LINEAR_PCM:
 877                open->dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
 878                break;
 879        default:
 880                dev_err(ac->dev, "Invalid format 0x%x\n", format);
 881                rc = -EINVAL;
 882                goto err;
 883        }
 884
 885        rc = q6asm_ac_send_cmd_sync(ac, pkt);
 886        if (rc < 0)
 887                goto err;
 888
 889        ac->io_mode |= ASM_TUN_WRITE_IO_MODE;
 890
 891err:
 892        kfree(pkt);
 893        return rc;
 894}
 895EXPORT_SYMBOL_GPL(q6asm_open_write);
 896
 897static int __q6asm_run(struct audio_client *ac, uint32_t flags,
 898              uint32_t msw_ts, uint32_t lsw_ts, bool wait)
 899{
 900        struct asm_session_cmd_run_v2 *run;
 901        struct apr_pkt *pkt;
 902        int pkt_size, rc;
 903        void *p;
 904
 905        pkt_size = APR_HDR_SIZE + sizeof(*run);
 906        p = kzalloc(pkt_size, GFP_ATOMIC);
 907        if (!p)
 908                return -ENOMEM;
 909
 910        pkt = p;
 911        run = p + APR_HDR_SIZE;
 912
 913        q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
 914
 915        pkt->hdr.opcode = ASM_SESSION_CMD_RUN_V2;
 916        run->flags = flags;
 917        run->time_lsw = lsw_ts;
 918        run->time_msw = msw_ts;
 919        if (wait) {
 920                rc = q6asm_ac_send_cmd_sync(ac, pkt);
 921        } else {
 922                rc = apr_send_pkt(ac->adev, pkt);
 923                if (rc == pkt_size)
 924                        rc = 0;
 925        }
 926
 927        kfree(pkt);
 928        return rc;
 929}
 930
 931/**
 932 * q6asm_run() - start the audio client
 933 *
 934 * @ac: audio client pointer
 935 * @flags: flags associated with write
 936 * @msw_ts: timestamp msw
 937 * @lsw_ts: timestamp lsw
 938 *
 939 * Return: Will be an negative value on error or zero on success
 940 */
 941int q6asm_run(struct audio_client *ac, uint32_t flags,
 942              uint32_t msw_ts, uint32_t lsw_ts)
 943{
 944        return __q6asm_run(ac, flags, msw_ts, lsw_ts, true);
 945}
 946EXPORT_SYMBOL_GPL(q6asm_run);
 947
 948/**
 949 * q6asm_run_nowait() - start the audio client withou blocking
 950 *
 951 * @ac: audio client pointer
 952 * @flags: flags associated with write
 953 * @msw_ts: timestamp msw
 954 * @lsw_ts: timestamp lsw
 955 *
 956 * Return: Will be an negative value on error or zero on success
 957 */
 958int q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
 959              uint32_t msw_ts, uint32_t lsw_ts)
 960{
 961        return __q6asm_run(ac, flags, msw_ts, lsw_ts, false);
 962}
 963EXPORT_SYMBOL_GPL(q6asm_run_nowait);
 964
 965/**
 966 * q6asm_media_format_block_multi_ch_pcm() - setup pcm configuration
 967 *
 968 * @ac: audio client pointer
 969 * @rate: audio sample rate
 970 * @channels: number of audio channels.
 971 * @channel_map: channel map pointer
 972 * @bits_per_sample: bits per sample
 973 *
 974 * Return: Will be an negative value on error or zero on success
 975 */
 976int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
 977                                          uint32_t rate, uint32_t channels,
 978                                          u8 channel_map[PCM_MAX_NUM_CHANNEL],
 979                                          uint16_t bits_per_sample)
 980{
 981        struct asm_multi_channel_pcm_fmt_blk_v2 *fmt;
 982        struct apr_pkt *pkt;
 983        u8 *channel_mapping;
 984        void *p;
 985        int rc, pkt_size;
 986
 987        pkt_size = APR_HDR_SIZE + sizeof(*fmt);
 988        p = kzalloc(pkt_size, GFP_KERNEL);
 989        if (!p)
 990                return -ENOMEM;
 991
 992        pkt = p;
 993        fmt = p + APR_HDR_SIZE;
 994
 995        q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
 996
 997        pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
 998        fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
 999        fmt->num_channels = channels;
1000        fmt->bits_per_sample = bits_per_sample;
1001        fmt->sample_rate = rate;
1002        fmt->is_signed = 1;
1003
1004        channel_mapping = fmt->channel_mapping;
1005
1006        if (channel_map) {
1007                memcpy(channel_mapping, channel_map, PCM_MAX_NUM_CHANNEL);
1008        } else {
1009                if (q6dsp_map_channels(channel_mapping, channels)) {
1010                        dev_err(ac->dev, " map channels failed %d\n", channels);
1011                        rc = -EINVAL;
1012                        goto err;
1013                }
1014        }
1015
1016        rc = q6asm_ac_send_cmd_sync(ac, pkt);
1017
1018err:
1019        kfree(pkt);
1020        return rc;
1021}
1022EXPORT_SYMBOL_GPL(q6asm_media_format_block_multi_ch_pcm);
1023
1024/**
1025 * q6asm_enc_cfg_blk_pcm_format_support() - setup pcm configuration for capture
1026 *
1027 * @ac: audio client pointer
1028 * @rate: audio sample rate
1029 * @channels: number of audio channels.
1030 * @bits_per_sample: bits per sample
1031 *
1032 * Return: Will be an negative value on error or zero on success
1033 */
1034int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac,
1035                uint32_t rate, uint32_t channels, uint16_t bits_per_sample)
1036{
1037        struct asm_multi_channel_pcm_enc_cfg_v2  *enc_cfg;
1038        struct apr_pkt *pkt;
1039        u8 *channel_mapping;
1040        u32 frames_per_buf = 0;
1041        int pkt_size, rc;
1042        void *p;
1043
1044        pkt_size = APR_HDR_SIZE + sizeof(*enc_cfg);
1045        p = kzalloc(pkt_size, GFP_KERNEL);
1046        if (!p)
1047                return -ENOMEM;
1048
1049        pkt = p;
1050        enc_cfg = p + APR_HDR_SIZE;
1051        q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
1052
1053        pkt->hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
1054        enc_cfg->encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
1055        enc_cfg->encdec.param_size = sizeof(*enc_cfg) - sizeof(enc_cfg->encdec);
1056        enc_cfg->encblk.frames_per_buf = frames_per_buf;
1057        enc_cfg->encblk.enc_cfg_blk_size  = enc_cfg->encdec.param_size -
1058                                        sizeof(struct asm_enc_cfg_blk_param_v2);
1059
1060        enc_cfg->num_channels = channels;
1061        enc_cfg->bits_per_sample = bits_per_sample;
1062        enc_cfg->sample_rate = rate;
1063        enc_cfg->is_signed = 1;
1064        channel_mapping = enc_cfg->channel_mapping;
1065
1066        if (q6dsp_map_channels(channel_mapping, channels)) {
1067                rc = -EINVAL;
1068                goto err;
1069        }
1070
1071        rc = q6asm_ac_send_cmd_sync(ac, pkt);
1072err:
1073        kfree(pkt);
1074        return rc;
1075}
1076EXPORT_SYMBOL_GPL(q6asm_enc_cfg_blk_pcm_format_support);
1077
1078/**
1079 * q6asm_read() - read data of period size from audio client
1080 *
1081 * @ac: audio client pointer
1082 *
1083 * Return: Will be an negative value on error or zero on success
1084 */
1085int q6asm_read(struct audio_client *ac)
1086{
1087        struct asm_data_cmd_read_v2 *read;
1088        struct audio_port_data *port;
1089        struct audio_buffer *ab;
1090        struct apr_pkt *pkt;
1091        unsigned long flags;
1092        int pkt_size;
1093        int rc = 0;
1094        void *p;
1095
1096        pkt_size = APR_HDR_SIZE + sizeof(*read);
1097        p = kzalloc(pkt_size, GFP_ATOMIC);
1098        if (!p)
1099                return -ENOMEM;
1100
1101        pkt = p;
1102        read = p + APR_HDR_SIZE;
1103
1104        spin_lock_irqsave(&ac->lock, flags);
1105        port = &ac->port[SNDRV_PCM_STREAM_CAPTURE];
1106        q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, ac->stream_id);
1107        ab = &port->buf[port->dsp_buf];
1108        pkt->hdr.opcode = ASM_DATA_CMD_READ_V2;
1109        read->buf_addr_lsw = lower_32_bits(ab->phys);
1110        read->buf_addr_msw = upper_32_bits(ab->phys);
1111        read->mem_map_handle = port->mem_map_handle;
1112
1113        read->buf_size = ab->size;
1114        read->seq_id = port->dsp_buf;
1115        pkt->hdr.token = port->dsp_buf;
1116
1117        port->dsp_buf++;
1118
1119        if (port->dsp_buf >= port->num_periods)
1120                port->dsp_buf = 0;
1121
1122        spin_unlock_irqrestore(&ac->lock, flags);
1123        rc = apr_send_pkt(ac->adev, pkt);
1124        if (rc == pkt_size)
1125                rc = 0;
1126        else
1127                pr_err("read op[0x%x]rc[%d]\n", pkt->hdr.opcode, rc);
1128
1129        kfree(pkt);
1130        return rc;
1131}
1132EXPORT_SYMBOL_GPL(q6asm_read);
1133
1134static int __q6asm_open_read(struct audio_client *ac,
1135                uint32_t format, uint16_t bits_per_sample)
1136{
1137        struct asm_stream_cmd_open_read_v3 *open;
1138        struct apr_pkt *pkt;
1139        int pkt_size, rc;
1140        void *p;
1141
1142        pkt_size = APR_HDR_SIZE + sizeof(*open);
1143        p = kzalloc(pkt_size, GFP_KERNEL);
1144        if (!p)
1145                return -ENOMEM;
1146
1147        pkt = p;
1148        open = p + APR_HDR_SIZE;
1149
1150        q6asm_add_hdr(ac, &pkt->hdr,  pkt_size, true, ac->stream_id);
1151        pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V3;
1152        /* Stream prio : High, provide meta info with encoded frames */
1153        open->src_endpointype = ASM_END_POINT_DEVICE_MATRIX;
1154
1155        open->preprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_NONE;
1156        open->bits_per_sample = bits_per_sample;
1157        open->mode_flags = 0x0;
1158
1159        open->mode_flags |= ASM_LEGACY_STREAM_SESSION <<
1160                                ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ;
1161
1162        switch (format) {
1163        case FORMAT_LINEAR_PCM:
1164                open->mode_flags |= 0x00;
1165                open->enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
1166                break;
1167        default:
1168                pr_err("Invalid format[%d]\n", format);
1169        }
1170
1171        rc = q6asm_ac_send_cmd_sync(ac, pkt);
1172
1173        kfree(pkt);
1174        return rc;
1175}
1176
1177/**
1178 * q6asm_open_read() - Open audio client for reading
1179 *
1180 * @ac: audio client pointer
1181 * @format: audio sample format
1182 * @bits_per_sample: bits per sample
1183 *
1184 * Return: Will be an negative value on error or zero on success
1185 */
1186int q6asm_open_read(struct audio_client *ac, uint32_t format,
1187                        uint16_t bits_per_sample)
1188{
1189        return __q6asm_open_read(ac, format, bits_per_sample);
1190}
1191EXPORT_SYMBOL_GPL(q6asm_open_read);
1192
1193/**
1194 * q6asm_write_async() - non blocking write
1195 *
1196 * @ac: audio client pointer
1197 * @len: length in bytes
1198 * @msw_ts: timestamp msw
1199 * @lsw_ts: timestamp lsw
1200 * @wflags: flags associated with write
1201 *
1202 * Return: Will be an negative value on error or zero on success
1203 */
1204int q6asm_write_async(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
1205                       uint32_t lsw_ts, uint32_t wflags)
1206{
1207        struct asm_data_cmd_write_v2 *write;
1208        struct audio_port_data *port;
1209        struct audio_buffer *ab;
1210        unsigned long flags;
1211        struct apr_pkt *pkt;
1212        int pkt_size;
1213        int rc = 0;
1214        void *p;
1215
1216        pkt_size = APR_HDR_SIZE + sizeof(*write);
1217        p = kzalloc(pkt_size, GFP_ATOMIC);
1218        if (!p)
1219                return -ENOMEM;
1220
1221        pkt = p;
1222        write = p + APR_HDR_SIZE;
1223
1224        spin_lock_irqsave(&ac->lock, flags);
1225        port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
1226        q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, ac->stream_id);
1227
1228        ab = &port->buf[port->dsp_buf];
1229        pkt->hdr.token = port->dsp_buf;
1230        pkt->hdr.opcode = ASM_DATA_CMD_WRITE_V2;
1231        write->buf_addr_lsw = lower_32_bits(ab->phys);
1232        write->buf_addr_msw = upper_32_bits(ab->phys);
1233        write->buf_size = len;
1234        write->seq_id = port->dsp_buf;
1235        write->timestamp_lsw = lsw_ts;
1236        write->timestamp_msw = msw_ts;
1237        write->mem_map_handle =
1238            ac->port[SNDRV_PCM_STREAM_PLAYBACK].mem_map_handle;
1239
1240        if (wflags == NO_TIMESTAMP)
1241                write->flags = (wflags & 0x800000FF);
1242        else
1243                write->flags = (0x80000000 | wflags);
1244
1245        port->dsp_buf++;
1246
1247        if (port->dsp_buf >= port->num_periods)
1248                port->dsp_buf = 0;
1249
1250        spin_unlock_irqrestore(&ac->lock, flags);
1251        rc = apr_send_pkt(ac->adev, pkt);
1252        if (rc == pkt_size)
1253                rc = 0;
1254
1255        kfree(pkt);
1256        return rc;
1257}
1258EXPORT_SYMBOL_GPL(q6asm_write_async);
1259
1260static void q6asm_reset_buf_state(struct audio_client *ac)
1261{
1262        struct audio_port_data *port = NULL;
1263        unsigned long flags;
1264
1265        spin_lock_irqsave(&ac->lock, flags);
1266        port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
1267        port->dsp_buf = 0;
1268        port = &ac->port[SNDRV_PCM_STREAM_CAPTURE];
1269        port->dsp_buf = 0;
1270        spin_unlock_irqrestore(&ac->lock, flags);
1271}
1272
1273static int __q6asm_cmd(struct audio_client *ac, int cmd, bool wait)
1274{
1275        int stream_id = ac->stream_id;
1276        struct apr_pkt pkt;
1277        int rc;
1278
1279        q6asm_add_hdr(ac, &pkt.hdr, APR_HDR_SIZE, true, stream_id);
1280
1281        switch (cmd) {
1282        case CMD_PAUSE:
1283                pkt.hdr.opcode = ASM_SESSION_CMD_PAUSE;
1284                break;
1285        case CMD_SUSPEND:
1286                pkt.hdr.opcode = ASM_SESSION_CMD_SUSPEND;
1287                break;
1288        case CMD_FLUSH:
1289                pkt.hdr.opcode = ASM_STREAM_CMD_FLUSH;
1290                break;
1291        case CMD_OUT_FLUSH:
1292                pkt.hdr.opcode = ASM_STREAM_CMD_FLUSH_READBUFS;
1293                break;
1294        case CMD_EOS:
1295                pkt.hdr.opcode = ASM_DATA_CMD_EOS;
1296                break;
1297        case CMD_CLOSE:
1298                pkt.hdr.opcode = ASM_STREAM_CMD_CLOSE;
1299                break;
1300        default:
1301                return -EINVAL;
1302        }
1303
1304        if (wait)
1305                rc = q6asm_ac_send_cmd_sync(ac, &pkt);
1306        else
1307                return apr_send_pkt(ac->adev, &pkt);
1308
1309        if (rc < 0)
1310                return rc;
1311
1312        if (cmd == CMD_FLUSH)
1313                q6asm_reset_buf_state(ac);
1314
1315        return 0;
1316}
1317
1318/**
1319 * q6asm_cmd() - run cmd on audio client
1320 *
1321 * @ac: audio client pointer
1322 * @cmd: command to run on audio client.
1323 *
1324 * Return: Will be an negative value on error or zero on success
1325 */
1326int q6asm_cmd(struct audio_client *ac, int cmd)
1327{
1328        return __q6asm_cmd(ac, cmd, true);
1329}
1330EXPORT_SYMBOL_GPL(q6asm_cmd);
1331
1332/**
1333 * q6asm_cmd_nowait() - non blocking, run cmd on audio client
1334 *
1335 * @ac: audio client pointer
1336 * @cmd: command to run on audio client.
1337 *
1338 * Return: Will be an negative value on error or zero on success
1339 */
1340int q6asm_cmd_nowait(struct audio_client *ac, int cmd)
1341{
1342        return __q6asm_cmd(ac, cmd, false);
1343}
1344EXPORT_SYMBOL_GPL(q6asm_cmd_nowait);
1345
1346static int q6asm_probe(struct apr_device *adev)
1347{
1348        struct device *dev = &adev->dev;
1349        struct q6asm *q6asm;
1350
1351        q6asm = devm_kzalloc(dev, sizeof(*q6asm), GFP_KERNEL);
1352        if (!q6asm)
1353                return -ENOMEM;
1354
1355        q6core_get_svc_api_info(adev->svc_id, &q6asm->ainfo);
1356
1357        q6asm->dev = dev;
1358        q6asm->adev = adev;
1359        init_waitqueue_head(&q6asm->mem_wait);
1360        spin_lock_init(&q6asm->slock);
1361        dev_set_drvdata(dev, q6asm);
1362
1363        return of_platform_populate(dev->of_node, NULL, NULL, dev);
1364}
1365
1366static int q6asm_remove(struct apr_device *adev)
1367{
1368        of_platform_depopulate(&adev->dev);
1369
1370        return 0;
1371}
1372static const struct of_device_id q6asm_device_id[]  = {
1373        { .compatible = "qcom,q6asm" },
1374        {},
1375};
1376MODULE_DEVICE_TABLE(of, q6asm_device_id);
1377
1378static struct apr_driver qcom_q6asm_driver = {
1379        .probe = q6asm_probe,
1380        .remove = q6asm_remove,
1381        .callback = q6asm_srvc_callback,
1382        .driver = {
1383                .name = "qcom-q6asm",
1384                .of_match_table = of_match_ptr(q6asm_device_id),
1385        },
1386};
1387
1388module_apr_driver(qcom_q6asm_driver);
1389MODULE_DESCRIPTION("Q6 Audio Stream Manager driver");
1390MODULE_LICENSE("GPL v2");
1391