linux/sound/soc/intel/sst-mfld-platform-pcm.c
<<
>>
Prefs
   1/*
   2 *  sst_mfld_platform.c - Intel MID Platform driver
   3 *
   4 *  Copyright (C) 2010-2014 Intel Corp
   5 *  Author: Vinod Koul <vinod.koul@intel.com>
   6 *  Author: Harsha Priya <priya.harsha@intel.com>
   7 *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   8 *
   9 *  This program is free software; you can redistribute it and/or modify
  10 *  it under the terms of the GNU General Public License as published by
  11 *  the Free Software Foundation; version 2 of the License.
  12 *
  13 *  This program is distributed in the hope that it will be useful, but
  14 *  WITHOUT ANY WARRANTY; without even the implied warranty of
  15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16 *  General Public License for more details.
  17 *
  18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  19 */
  20#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  21
  22#include <linux/slab.h>
  23#include <linux/io.h>
  24#include <linux/module.h>
  25#include <sound/core.h>
  26#include <sound/pcm.h>
  27#include <sound/pcm_params.h>
  28#include <sound/soc.h>
  29#include <sound/compress_driver.h>
  30#include <asm/platform_sst_audio.h>
  31#include "sst-mfld-platform.h"
  32#include "sst-atom-controls.h"
  33
  34struct sst_device *sst;
  35static DEFINE_MUTEX(sst_lock);
  36extern struct snd_compr_ops sst_platform_compr_ops;
  37
  38int sst_register_dsp(struct sst_device *dev)
  39{
  40        if (WARN_ON(!dev))
  41                return -EINVAL;
  42        if (!try_module_get(dev->dev->driver->owner))
  43                return -ENODEV;
  44        mutex_lock(&sst_lock);
  45        if (sst) {
  46                dev_err(dev->dev, "we already have a device %s\n", sst->name);
  47                module_put(dev->dev->driver->owner);
  48                mutex_unlock(&sst_lock);
  49                return -EEXIST;
  50        }
  51        dev_dbg(dev->dev, "registering device %s\n", dev->name);
  52        sst = dev;
  53        mutex_unlock(&sst_lock);
  54        return 0;
  55}
  56EXPORT_SYMBOL_GPL(sst_register_dsp);
  57
  58int sst_unregister_dsp(struct sst_device *dev)
  59{
  60        if (WARN_ON(!dev))
  61                return -EINVAL;
  62        if (dev != sst)
  63                return -EINVAL;
  64
  65        mutex_lock(&sst_lock);
  66
  67        if (!sst) {
  68                mutex_unlock(&sst_lock);
  69                return -EIO;
  70        }
  71
  72        module_put(sst->dev->driver->owner);
  73        dev_dbg(dev->dev, "unreg %s\n", sst->name);
  74        sst = NULL;
  75        mutex_unlock(&sst_lock);
  76        return 0;
  77}
  78EXPORT_SYMBOL_GPL(sst_unregister_dsp);
  79
  80static struct snd_pcm_hardware sst_platform_pcm_hw = {
  81        .info = (SNDRV_PCM_INFO_INTERLEAVED |
  82                        SNDRV_PCM_INFO_DOUBLE |
  83                        SNDRV_PCM_INFO_PAUSE |
  84                        SNDRV_PCM_INFO_RESUME |
  85                        SNDRV_PCM_INFO_MMAP|
  86                        SNDRV_PCM_INFO_MMAP_VALID |
  87                        SNDRV_PCM_INFO_BLOCK_TRANSFER |
  88                        SNDRV_PCM_INFO_SYNC_START),
  89        .buffer_bytes_max = SST_MAX_BUFFER,
  90        .period_bytes_min = SST_MIN_PERIOD_BYTES,
  91        .period_bytes_max = SST_MAX_PERIOD_BYTES,
  92        .periods_min = SST_MIN_PERIODS,
  93        .periods_max = SST_MAX_PERIODS,
  94        .fifo_size = SST_FIFO_SIZE,
  95};
  96
  97static struct sst_dev_stream_map dpcm_strm_map[] = {
  98        {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, /* Reserved, not in use */
  99        {MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA1_IN, SST_TASK_ID_MEDIA, 0},
 100        {MERR_DPCM_COMPR, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA0_IN, SST_TASK_ID_MEDIA, 0},
 101        {MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_CAPTURE, PIPE_PCM1_OUT, SST_TASK_ID_MEDIA, 0},
 102};
 103
 104static int sst_media_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
 105{
 106
 107        return sst_send_pipe_gains(dai, stream, mute);
 108}
 109
 110/* helper functions */
 111void sst_set_stream_status(struct sst_runtime_stream *stream,
 112                                        int state)
 113{
 114        unsigned long flags;
 115        spin_lock_irqsave(&stream->status_lock, flags);
 116        stream->stream_status = state;
 117        spin_unlock_irqrestore(&stream->status_lock, flags);
 118}
 119
 120static inline int sst_get_stream_status(struct sst_runtime_stream *stream)
 121{
 122        int state;
 123        unsigned long flags;
 124
 125        spin_lock_irqsave(&stream->status_lock, flags);
 126        state = stream->stream_status;
 127        spin_unlock_irqrestore(&stream->status_lock, flags);
 128        return state;
 129}
 130
 131static void sst_fill_alloc_params(struct snd_pcm_substream *substream,
 132                                struct snd_sst_alloc_params_ext *alloc_param)
 133{
 134        unsigned int channels;
 135        snd_pcm_uframes_t period_size;
 136        ssize_t periodbytes;
 137        ssize_t buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
 138        u32 buffer_addr = virt_to_phys(substream->dma_buffer.area);
 139
 140        channels = substream->runtime->channels;
 141        period_size = substream->runtime->period_size;
 142        periodbytes = samples_to_bytes(substream->runtime, period_size);
 143        alloc_param->ring_buf_info[0].addr = buffer_addr;
 144        alloc_param->ring_buf_info[0].size = buffer_bytes;
 145        alloc_param->sg_count = 1;
 146        alloc_param->reserved = 0;
 147        alloc_param->frag_size = periodbytes * channels;
 148
 149}
 150static void sst_fill_pcm_params(struct snd_pcm_substream *substream,
 151                                struct snd_sst_stream_params *param)
 152{
 153        param->uc.pcm_params.num_chan = (u8) substream->runtime->channels;
 154        param->uc.pcm_params.pcm_wd_sz = substream->runtime->sample_bits;
 155        param->uc.pcm_params.sfreq = substream->runtime->rate;
 156
 157        /* PCM stream via ALSA interface */
 158        param->uc.pcm_params.use_offload_path = 0;
 159        param->uc.pcm_params.reserved2 = 0;
 160        memset(param->uc.pcm_params.channel_map, 0, sizeof(u8));
 161
 162}
 163
 164static int sst_get_stream_mapping(int dev, int sdev, int dir,
 165        struct sst_dev_stream_map *map, int size)
 166{
 167        int i;
 168
 169        if (map == NULL)
 170                return -EINVAL;
 171
 172
 173        /* index 0 is not used in stream map */
 174        for (i = 1; i < size; i++) {
 175                if ((map[i].dev_num == dev) && (map[i].direction == dir))
 176                        return i;
 177        }
 178        return 0;
 179}
 180
 181int sst_fill_stream_params(void *substream,
 182        const struct sst_data *ctx, struct snd_sst_params *str_params, bool is_compress)
 183{
 184        int map_size;
 185        int index;
 186        struct sst_dev_stream_map *map;
 187        struct snd_pcm_substream *pstream = NULL;
 188        struct snd_compr_stream *cstream = NULL;
 189
 190        map = ctx->pdata->pdev_strm_map;
 191        map_size = ctx->pdata->strm_map_size;
 192
 193        if (is_compress == true)
 194                cstream = (struct snd_compr_stream *)substream;
 195        else
 196                pstream = (struct snd_pcm_substream *)substream;
 197
 198        str_params->stream_type = SST_STREAM_TYPE_MUSIC;
 199
 200        /* For pcm streams */
 201        if (pstream) {
 202                index = sst_get_stream_mapping(pstream->pcm->device,
 203                                          pstream->number, pstream->stream,
 204                                          map, map_size);
 205                if (index <= 0)
 206                        return -EINVAL;
 207
 208                str_params->stream_id = index;
 209                str_params->device_type = map[index].device_id;
 210                str_params->task = map[index].task_id;
 211
 212                str_params->ops = (u8)pstream->stream;
 213        }
 214
 215        if (cstream) {
 216                index = sst_get_stream_mapping(cstream->device->device,
 217                                               0, cstream->direction,
 218                                               map, map_size);
 219                if (index <= 0)
 220                        return -EINVAL;
 221                str_params->stream_id = index;
 222                str_params->device_type = map[index].device_id;
 223                str_params->task = map[index].task_id;
 224
 225                str_params->ops = (u8)cstream->direction;
 226        }
 227        return 0;
 228}
 229
 230static int sst_platform_alloc_stream(struct snd_pcm_substream *substream,
 231                struct snd_soc_dai *dai)
 232{
 233        struct sst_runtime_stream *stream =
 234                        substream->runtime->private_data;
 235        struct snd_sst_stream_params param = {{{0,},},};
 236        struct snd_sst_params str_params = {0};
 237        struct snd_sst_alloc_params_ext alloc_params = {0};
 238        int ret_val = 0;
 239        struct sst_data *ctx = snd_soc_dai_get_drvdata(dai);
 240
 241        /* set codec params and inform SST driver the same */
 242        sst_fill_pcm_params(substream, &param);
 243        sst_fill_alloc_params(substream, &alloc_params);
 244        substream->runtime->dma_area = substream->dma_buffer.area;
 245        str_params.sparams = param;
 246        str_params.aparams = alloc_params;
 247        str_params.codec = SST_CODEC_TYPE_PCM;
 248
 249        /* fill the device type and stream id to pass to SST driver */
 250        ret_val = sst_fill_stream_params(substream, ctx, &str_params, false);
 251        if (ret_val < 0)
 252                return ret_val;
 253
 254        stream->stream_info.str_id = str_params.stream_id;
 255
 256        ret_val = stream->ops->open(sst->dev, &str_params);
 257        if (ret_val <= 0)
 258                return ret_val;
 259
 260
 261        return ret_val;
 262}
 263
 264static void sst_period_elapsed(void *arg)
 265{
 266        struct snd_pcm_substream *substream = arg;
 267        struct sst_runtime_stream *stream;
 268        int status;
 269
 270        if (!substream || !substream->runtime)
 271                return;
 272        stream = substream->runtime->private_data;
 273        if (!stream)
 274                return;
 275        status = sst_get_stream_status(stream);
 276        if (status != SST_PLATFORM_RUNNING)
 277                return;
 278        snd_pcm_period_elapsed(substream);
 279}
 280
 281static int sst_platform_init_stream(struct snd_pcm_substream *substream)
 282{
 283        struct sst_runtime_stream *stream =
 284                        substream->runtime->private_data;
 285        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 286        int ret_val;
 287
 288        dev_dbg(rtd->dev, "setting buffer ptr param\n");
 289        sst_set_stream_status(stream, SST_PLATFORM_INIT);
 290        stream->stream_info.period_elapsed = sst_period_elapsed;
 291        stream->stream_info.arg = substream;
 292        stream->stream_info.buffer_ptr = 0;
 293        stream->stream_info.sfreq = substream->runtime->rate;
 294        ret_val = stream->ops->stream_init(sst->dev, &stream->stream_info);
 295        if (ret_val)
 296                dev_err(rtd->dev, "control_set ret error %d\n", ret_val);
 297        return ret_val;
 298
 299}
 300
 301static int power_up_sst(struct sst_runtime_stream *stream)
 302{
 303        return stream->ops->power(sst->dev, true);
 304}
 305
 306static void power_down_sst(struct sst_runtime_stream *stream)
 307{
 308        stream->ops->power(sst->dev, false);
 309}
 310
 311static int sst_media_open(struct snd_pcm_substream *substream,
 312                struct snd_soc_dai *dai)
 313{
 314        int ret_val = 0;
 315        struct snd_pcm_runtime *runtime = substream->runtime;
 316        struct sst_runtime_stream *stream;
 317
 318        stream = kzalloc(sizeof(*stream), GFP_KERNEL);
 319        if (!stream)
 320                return -ENOMEM;
 321        spin_lock_init(&stream->status_lock);
 322
 323        /* get the sst ops */
 324        mutex_lock(&sst_lock);
 325        if (!sst ||
 326            !try_module_get(sst->dev->driver->owner)) {
 327                dev_err(dai->dev, "no device available to run\n");
 328                ret_val = -ENODEV;
 329                goto out_ops;
 330        }
 331        stream->ops = sst->ops;
 332        mutex_unlock(&sst_lock);
 333
 334        stream->stream_info.str_id = 0;
 335
 336        stream->stream_info.arg = substream;
 337        /* allocate memory for SST API set */
 338        runtime->private_data = stream;
 339
 340        ret_val = power_up_sst(stream);
 341        if (ret_val < 0)
 342                return ret_val;
 343
 344        /* Make sure, that the period size is always even */
 345        snd_pcm_hw_constraint_step(substream->runtime, 0,
 346                           SNDRV_PCM_HW_PARAM_PERIODS, 2);
 347
 348        return snd_pcm_hw_constraint_integer(runtime,
 349                         SNDRV_PCM_HW_PARAM_PERIODS);
 350out_ops:
 351        kfree(stream);
 352        mutex_unlock(&sst_lock);
 353        return ret_val;
 354}
 355
 356static void sst_media_close(struct snd_pcm_substream *substream,
 357                struct snd_soc_dai *dai)
 358{
 359        struct sst_runtime_stream *stream;
 360        int ret_val = 0, str_id;
 361
 362        stream = substream->runtime->private_data;
 363        power_down_sst(stream);
 364
 365        str_id = stream->stream_info.str_id;
 366        if (str_id)
 367                ret_val = stream->ops->close(sst->dev, str_id);
 368        module_put(sst->dev->driver->owner);
 369        kfree(stream);
 370}
 371
 372static inline unsigned int get_current_pipe_id(struct snd_soc_dai *dai,
 373                                               struct snd_pcm_substream *substream)
 374{
 375        struct sst_data *sst = snd_soc_dai_get_drvdata(dai);
 376        struct sst_dev_stream_map *map = sst->pdata->pdev_strm_map;
 377        struct sst_runtime_stream *stream =
 378                        substream->runtime->private_data;
 379        u32 str_id = stream->stream_info.str_id;
 380        unsigned int pipe_id;
 381
 382        pipe_id = map[str_id].device_id;
 383
 384        dev_dbg(dai->dev, "got pipe_id = %#x for str_id = %d\n",
 385                        pipe_id, str_id);
 386        return pipe_id;
 387}
 388
 389static int sst_media_prepare(struct snd_pcm_substream *substream,
 390                struct snd_soc_dai *dai)
 391{
 392        struct sst_runtime_stream *stream;
 393        int ret_val = 0, str_id;
 394
 395        stream = substream->runtime->private_data;
 396        str_id = stream->stream_info.str_id;
 397        if (stream->stream_info.str_id) {
 398                ret_val = stream->ops->stream_drop(sst->dev, str_id);
 399                return ret_val;
 400        }
 401
 402        ret_val = sst_platform_alloc_stream(substream, dai);
 403        if (ret_val <= 0)
 404                return ret_val;
 405        snprintf(substream->pcm->id, sizeof(substream->pcm->id),
 406                        "%d", stream->stream_info.str_id);
 407
 408        ret_val = sst_platform_init_stream(substream);
 409        if (ret_val)
 410                return ret_val;
 411        substream->runtime->hw.info = SNDRV_PCM_INFO_BLOCK_TRANSFER;
 412        return ret_val;
 413}
 414
 415static int sst_media_hw_params(struct snd_pcm_substream *substream,
 416                                struct snd_pcm_hw_params *params,
 417                                struct snd_soc_dai *dai)
 418{
 419        snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
 420        memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
 421        return 0;
 422}
 423
 424static int sst_media_hw_free(struct snd_pcm_substream *substream,
 425                struct snd_soc_dai *dai)
 426{
 427        return snd_pcm_lib_free_pages(substream);
 428}
 429
 430static int sst_enable_ssp(struct snd_pcm_substream *substream,
 431                        struct snd_soc_dai *dai)
 432{
 433        int ret = 0;
 434
 435        if (!dai->active) {
 436                ret = sst_handle_vb_timer(dai, true);
 437                if (ret)
 438                        return ret;
 439                ret = send_ssp_cmd(dai, dai->name, 1);
 440        }
 441        return ret;
 442}
 443
 444static void sst_disable_ssp(struct snd_pcm_substream *substream,
 445                        struct snd_soc_dai *dai)
 446{
 447        if (!dai->active) {
 448                send_ssp_cmd(dai, dai->name, 0);
 449                sst_handle_vb_timer(dai, false);
 450        }
 451}
 452
 453static struct snd_soc_dai_ops sst_media_dai_ops = {
 454        .startup = sst_media_open,
 455        .shutdown = sst_media_close,
 456        .prepare = sst_media_prepare,
 457        .hw_params = sst_media_hw_params,
 458        .hw_free = sst_media_hw_free,
 459        .mute_stream = sst_media_digital_mute,
 460};
 461
 462static struct snd_soc_dai_ops sst_compr_dai_ops = {
 463        .mute_stream = sst_media_digital_mute,
 464};
 465
 466static struct snd_soc_dai_ops sst_be_dai_ops = {
 467        .startup = sst_enable_ssp,
 468        .shutdown = sst_disable_ssp,
 469};
 470
 471static struct snd_soc_dai_driver sst_platform_dai[] = {
 472{
 473        .name = "media-cpu-dai",
 474        .ops = &sst_media_dai_ops,
 475        .playback = {
 476                .stream_name = "Headset Playback",
 477                .channels_min = SST_STEREO,
 478                .channels_max = SST_STEREO,
 479                .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
 480                .formats = SNDRV_PCM_FMTBIT_S16_LE,
 481        },
 482        .capture = {
 483                .stream_name = "Headset Capture",
 484                .channels_min = 1,
 485                .channels_max = 2,
 486                .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
 487                .formats = SNDRV_PCM_FMTBIT_S16_LE,
 488        },
 489},
 490{
 491        .name = "compress-cpu-dai",
 492        .compress_dai = 1,
 493        .ops = &sst_compr_dai_ops,
 494        .playback = {
 495                .stream_name = "Compress Playback",
 496                .channels_min = SST_STEREO,
 497                .channels_max = SST_STEREO,
 498                .rates = SNDRV_PCM_RATE_48000,
 499                .formats = SNDRV_PCM_FMTBIT_S16_LE,
 500        },
 501},
 502/* BE CPU  Dais */
 503{
 504        .name = "ssp0-port",
 505        .ops = &sst_be_dai_ops,
 506        .playback = {
 507                .stream_name = "ssp0 Tx",
 508                .channels_min = SST_STEREO,
 509                .channels_max = SST_STEREO,
 510                .rates = SNDRV_PCM_RATE_48000,
 511                .formats = SNDRV_PCM_FMTBIT_S16_LE,
 512        },
 513        .capture = {
 514                .stream_name = "ssp0 Rx",
 515                .channels_min = SST_STEREO,
 516                .channels_max = SST_STEREO,
 517                .rates = SNDRV_PCM_RATE_48000,
 518                .formats = SNDRV_PCM_FMTBIT_S16_LE,
 519        },
 520},
 521{
 522        .name = "ssp1-port",
 523        .ops = &sst_be_dai_ops,
 524        .playback = {
 525                .stream_name = "ssp1 Tx",
 526                .channels_min = SST_STEREO,
 527                .channels_max = SST_STEREO,
 528                .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000,
 529                .formats = SNDRV_PCM_FMTBIT_S16_LE,
 530        },
 531        .capture = {
 532                .stream_name = "ssp1 Rx",
 533                .channels_min = SST_STEREO,
 534                .channels_max = SST_STEREO,
 535                .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000,
 536                .formats = SNDRV_PCM_FMTBIT_S16_LE,
 537        },
 538},
 539{
 540        .name = "ssp2-port",
 541        .ops = &sst_be_dai_ops,
 542        .playback = {
 543                .stream_name = "ssp2 Tx",
 544                .channels_min = SST_STEREO,
 545                .channels_max = SST_STEREO,
 546                .rates = SNDRV_PCM_RATE_48000,
 547                .formats = SNDRV_PCM_FMTBIT_S16_LE,
 548        },
 549        .capture = {
 550                .stream_name = "ssp2 Rx",
 551                .channels_min = SST_STEREO,
 552                .channels_max = SST_STEREO,
 553                .rates = SNDRV_PCM_RATE_48000,
 554                .formats = SNDRV_PCM_FMTBIT_S16_LE,
 555        },
 556},
 557};
 558
 559static int sst_platform_open(struct snd_pcm_substream *substream)
 560{
 561        struct snd_pcm_runtime *runtime;
 562
 563        if (substream->pcm->internal)
 564                return 0;
 565
 566        runtime = substream->runtime;
 567        runtime->hw = sst_platform_pcm_hw;
 568        return 0;
 569}
 570
 571static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream,
 572                                        int cmd)
 573{
 574        int ret_val = 0, str_id;
 575        struct sst_runtime_stream *stream;
 576        int status;
 577        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 578
 579        dev_dbg(rtd->dev, "sst_platform_pcm_trigger called\n");
 580        if (substream->pcm->internal)
 581                return 0;
 582        stream = substream->runtime->private_data;
 583        str_id = stream->stream_info.str_id;
 584        switch (cmd) {
 585        case SNDRV_PCM_TRIGGER_START:
 586                dev_dbg(rtd->dev, "sst: Trigger Start\n");
 587                status = SST_PLATFORM_RUNNING;
 588                stream->stream_info.arg = substream;
 589                ret_val = stream->ops->stream_start(sst->dev, str_id);
 590                break;
 591        case SNDRV_PCM_TRIGGER_STOP:
 592                dev_dbg(rtd->dev, "sst: in stop\n");
 593                status = SST_PLATFORM_DROPPED;
 594                ret_val = stream->ops->stream_drop(sst->dev, str_id);
 595                break;
 596        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 597                dev_dbg(rtd->dev, "sst: in pause\n");
 598                status = SST_PLATFORM_PAUSED;
 599                ret_val = stream->ops->stream_pause(sst->dev, str_id);
 600                break;
 601        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 602                dev_dbg(rtd->dev, "sst: in pause release\n");
 603                status = SST_PLATFORM_RUNNING;
 604                ret_val = stream->ops->stream_pause_release(sst->dev, str_id);
 605                break;
 606        default:
 607                return -EINVAL;
 608        }
 609
 610        if (!ret_val)
 611                sst_set_stream_status(stream, status);
 612
 613        return ret_val;
 614}
 615
 616
 617static snd_pcm_uframes_t sst_platform_pcm_pointer
 618                        (struct snd_pcm_substream *substream)
 619{
 620        struct sst_runtime_stream *stream;
 621        int ret_val, status;
 622        struct pcm_stream_info *str_info;
 623        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 624
 625        stream = substream->runtime->private_data;
 626        status = sst_get_stream_status(stream);
 627        if (status == SST_PLATFORM_INIT)
 628                return 0;
 629        str_info = &stream->stream_info;
 630        ret_val = stream->ops->stream_read_tstamp(sst->dev, str_info);
 631        if (ret_val) {
 632                dev_err(rtd->dev, "sst: error code = %d\n", ret_val);
 633                return ret_val;
 634        }
 635        substream->runtime->delay = str_info->pcm_delay;
 636        return str_info->buffer_ptr;
 637}
 638
 639static struct snd_pcm_ops sst_platform_ops = {
 640        .open = sst_platform_open,
 641        .ioctl = snd_pcm_lib_ioctl,
 642        .trigger = sst_platform_pcm_trigger,
 643        .pointer = sst_platform_pcm_pointer,
 644};
 645
 646static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
 647{
 648        struct snd_soc_dai *dai = rtd->cpu_dai;
 649        struct snd_pcm *pcm = rtd->pcm;
 650        int retval = 0;
 651
 652        if (dai->driver->playback.channels_min ||
 653                        dai->driver->capture.channels_min) {
 654                retval =  snd_pcm_lib_preallocate_pages_for_all(pcm,
 655                        SNDRV_DMA_TYPE_CONTINUOUS,
 656                        snd_dma_continuous_data(GFP_DMA),
 657                        SST_MIN_BUFFER, SST_MAX_BUFFER);
 658                if (retval) {
 659                        dev_err(rtd->dev, "dma buffer allocationf fail\n");
 660                        return retval;
 661                }
 662        }
 663        return retval;
 664}
 665
 666static int sst_soc_probe(struct snd_soc_platform *platform)
 667{
 668        return sst_dsp_init_v2_dpcm(platform);
 669}
 670
 671static struct snd_soc_platform_driver sst_soc_platform_drv  = {
 672        .probe          = sst_soc_probe,
 673        .ops            = &sst_platform_ops,
 674        .compr_ops      = &sst_platform_compr_ops,
 675        .pcm_new        = sst_pcm_new,
 676};
 677
 678static const struct snd_soc_component_driver sst_component = {
 679        .name           = "sst",
 680};
 681
 682
 683static int sst_platform_probe(struct platform_device *pdev)
 684{
 685        struct sst_data *drv;
 686        int ret;
 687        struct sst_platform_data *pdata;
 688
 689        drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
 690        if (drv == NULL) {
 691                return -ENOMEM;
 692        }
 693
 694        pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
 695        if (pdata == NULL) {
 696                return -ENOMEM;
 697        }
 698
 699        pdata->pdev_strm_map = dpcm_strm_map;
 700        pdata->strm_map_size = ARRAY_SIZE(dpcm_strm_map);
 701        drv->pdata = pdata;
 702        drv->pdev = pdev;
 703        mutex_init(&drv->lock);
 704        dev_set_drvdata(&pdev->dev, drv);
 705
 706        ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv);
 707        if (ret) {
 708                dev_err(&pdev->dev, "registering soc platform failed\n");
 709                return ret;
 710        }
 711
 712        ret = snd_soc_register_component(&pdev->dev, &sst_component,
 713                                sst_platform_dai, ARRAY_SIZE(sst_platform_dai));
 714        if (ret) {
 715                dev_err(&pdev->dev, "registering cpu dais failed\n");
 716                snd_soc_unregister_platform(&pdev->dev);
 717        }
 718        return ret;
 719}
 720
 721static int sst_platform_remove(struct platform_device *pdev)
 722{
 723
 724        snd_soc_unregister_component(&pdev->dev);
 725        snd_soc_unregister_platform(&pdev->dev);
 726        dev_dbg(&pdev->dev, "sst_platform_remove success\n");
 727        return 0;
 728}
 729
 730static struct platform_driver sst_platform_driver = {
 731        .driver         = {
 732                .name           = "sst-mfld-platform",
 733        },
 734        .probe          = sst_platform_probe,
 735        .remove         = sst_platform_remove,
 736};
 737
 738module_platform_driver(sst_platform_driver);
 739
 740MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver");
 741MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
 742MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
 743MODULE_LICENSE("GPL v2");
 744MODULE_ALIAS("platform:sst-mfld-platform");
 745