linux/sound/soc/intel/atom/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);
  36
  37int sst_register_dsp(struct sst_device *dev)
  38{
  39        if (WARN_ON(!dev))
  40                return -EINVAL;
  41        if (!try_module_get(dev->dev->driver->owner))
  42                return -ENODEV;
  43        mutex_lock(&sst_lock);
  44        if (sst) {
  45                dev_err(dev->dev, "we already have a device %s\n", sst->name);
  46                module_put(dev->dev->driver->owner);
  47                mutex_unlock(&sst_lock);
  48                return -EEXIST;
  49        }
  50        dev_dbg(dev->dev, "registering device %s\n", dev->name);
  51        sst = dev;
  52        mutex_unlock(&sst_lock);
  53        return 0;
  54}
  55EXPORT_SYMBOL_GPL(sst_register_dsp);
  56
  57int sst_unregister_dsp(struct sst_device *dev)
  58{
  59        if (WARN_ON(!dev))
  60                return -EINVAL;
  61        if (dev != sst)
  62                return -EINVAL;
  63
  64        mutex_lock(&sst_lock);
  65
  66        if (!sst) {
  67                mutex_unlock(&sst_lock);
  68                return -EIO;
  69        }
  70
  71        module_put(sst->dev->driver->owner);
  72        dev_dbg(dev->dev, "unreg %s\n", sst->name);
  73        sst = NULL;
  74        mutex_unlock(&sst_lock);
  75        return 0;
  76}
  77EXPORT_SYMBOL_GPL(sst_unregister_dsp);
  78
  79static struct snd_pcm_hardware sst_platform_pcm_hw = {
  80        .info = (SNDRV_PCM_INFO_INTERLEAVED |
  81                        SNDRV_PCM_INFO_DOUBLE |
  82                        SNDRV_PCM_INFO_PAUSE |
  83                        SNDRV_PCM_INFO_RESUME |
  84                        SNDRV_PCM_INFO_MMAP|
  85                        SNDRV_PCM_INFO_MMAP_VALID |
  86                        SNDRV_PCM_INFO_BLOCK_TRANSFER |
  87                        SNDRV_PCM_INFO_SYNC_START),
  88        .buffer_bytes_max = SST_MAX_BUFFER,
  89        .period_bytes_min = SST_MIN_PERIOD_BYTES,
  90        .period_bytes_max = SST_MAX_PERIOD_BYTES,
  91        .periods_min = SST_MIN_PERIODS,
  92        .periods_max = SST_MAX_PERIODS,
  93        .fifo_size = SST_FIFO_SIZE,
  94};
  95
  96static struct sst_dev_stream_map dpcm_strm_map[] = {
  97        {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, /* Reserved, not in use */
  98        {MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA1_IN, SST_TASK_ID_MEDIA, 0},
  99        {MERR_DPCM_COMPR, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA0_IN, SST_TASK_ID_MEDIA, 0},
 100        {MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_CAPTURE, PIPE_PCM1_OUT, SST_TASK_ID_MEDIA, 0},
 101        {MERR_DPCM_DEEP_BUFFER, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA3_IN, 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 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                stream->ops->close(sst->dev, str_id);
 368        module_put(sst->dev->driver->owner);
 369        kfree(stream);
 370}
 371
 372static int sst_media_prepare(struct snd_pcm_substream *substream,
 373                struct snd_soc_dai *dai)
 374{
 375        struct sst_runtime_stream *stream;
 376        int ret_val = 0, str_id;
 377
 378        stream = substream->runtime->private_data;
 379        str_id = stream->stream_info.str_id;
 380        if (stream->stream_info.str_id) {
 381                ret_val = stream->ops->stream_drop(sst->dev, str_id);
 382                return ret_val;
 383        }
 384
 385        ret_val = sst_platform_alloc_stream(substream, dai);
 386        if (ret_val <= 0)
 387                return ret_val;
 388        snprintf(substream->pcm->id, sizeof(substream->pcm->id),
 389                        "%d", stream->stream_info.str_id);
 390
 391        ret_val = sst_platform_init_stream(substream);
 392        if (ret_val)
 393                return ret_val;
 394        substream->runtime->hw.info = SNDRV_PCM_INFO_BLOCK_TRANSFER;
 395        return ret_val;
 396}
 397
 398static int sst_media_hw_params(struct snd_pcm_substream *substream,
 399                                struct snd_pcm_hw_params *params,
 400                                struct snd_soc_dai *dai)
 401{
 402        snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
 403        memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
 404        return 0;
 405}
 406
 407static int sst_media_hw_free(struct snd_pcm_substream *substream,
 408                struct snd_soc_dai *dai)
 409{
 410        return snd_pcm_lib_free_pages(substream);
 411}
 412
 413static int sst_enable_ssp(struct snd_pcm_substream *substream,
 414                        struct snd_soc_dai *dai)
 415{
 416        int ret = 0;
 417
 418        if (!dai->active) {
 419                ret = sst_handle_vb_timer(dai, true);
 420                sst_fill_ssp_defaults(dai);
 421        }
 422        return ret;
 423}
 424
 425static int sst_be_hw_params(struct snd_pcm_substream *substream,
 426                                struct snd_pcm_hw_params *params,
 427                                struct snd_soc_dai *dai)
 428{
 429        int ret = 0;
 430
 431        if (dai->active == 1)
 432                ret = send_ssp_cmd(dai, dai->name, 1);
 433        return ret;
 434}
 435
 436static int sst_set_format(struct snd_soc_dai *dai, unsigned int fmt)
 437{
 438        int ret = 0;
 439
 440        if (!dai->active)
 441                return 0;
 442
 443        ret = sst_fill_ssp_config(dai, fmt);
 444        if (ret < 0)
 445                dev_err(dai->dev, "sst_set_format failed..\n");
 446
 447        return ret;
 448}
 449
 450static int sst_platform_set_ssp_slot(struct snd_soc_dai *dai,
 451                        unsigned int tx_mask, unsigned int rx_mask,
 452                        int slots, int slot_width) {
 453        int ret = 0;
 454
 455        if (!dai->active)
 456                return ret;
 457
 458        ret = sst_fill_ssp_slot(dai, tx_mask, rx_mask, slots, slot_width);
 459        if (ret < 0)
 460                dev_err(dai->dev, "sst_fill_ssp_slot failed..%d\n", ret);
 461
 462        return ret;
 463}
 464
 465static void sst_disable_ssp(struct snd_pcm_substream *substream,
 466                        struct snd_soc_dai *dai)
 467{
 468        if (!dai->active) {
 469                send_ssp_cmd(dai, dai->name, 0);
 470                sst_handle_vb_timer(dai, false);
 471        }
 472}
 473
 474static struct snd_soc_dai_ops sst_media_dai_ops = {
 475        .startup = sst_media_open,
 476        .shutdown = sst_media_close,
 477        .prepare = sst_media_prepare,
 478        .hw_params = sst_media_hw_params,
 479        .hw_free = sst_media_hw_free,
 480        .mute_stream = sst_media_digital_mute,
 481};
 482
 483static struct snd_soc_dai_ops sst_compr_dai_ops = {
 484        .mute_stream = sst_media_digital_mute,
 485};
 486
 487static struct snd_soc_dai_ops sst_be_dai_ops = {
 488        .startup = sst_enable_ssp,
 489        .hw_params = sst_be_hw_params,
 490        .set_fmt = sst_set_format,
 491        .set_tdm_slot = sst_platform_set_ssp_slot,
 492        .shutdown = sst_disable_ssp,
 493};
 494
 495static struct snd_soc_dai_driver sst_platform_dai[] = {
 496{
 497        .name = "media-cpu-dai",
 498        .ops = &sst_media_dai_ops,
 499        .playback = {
 500                .stream_name = "Headset Playback",
 501                .channels_min = SST_STEREO,
 502                .channels_max = SST_STEREO,
 503                .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
 504                .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
 505        },
 506        .capture = {
 507                .stream_name = "Headset Capture",
 508                .channels_min = 1,
 509                .channels_max = 2,
 510                .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
 511                .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
 512        },
 513},
 514{
 515        .name = "deepbuffer-cpu-dai",
 516        .ops = &sst_media_dai_ops,
 517        .playback = {
 518                .stream_name = "Deepbuffer Playback",
 519                .channels_min = SST_STEREO,
 520                .channels_max = SST_STEREO,
 521                .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
 522                .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
 523        },
 524},
 525{
 526        .name = "compress-cpu-dai",
 527        .compress_new = snd_soc_new_compress,
 528        .ops = &sst_compr_dai_ops,
 529        .playback = {
 530                .stream_name = "Compress Playback",
 531                .channels_min = 1,
 532        },
 533},
 534/* BE CPU  Dais */
 535{
 536        .name = "ssp0-port",
 537        .ops = &sst_be_dai_ops,
 538        .playback = {
 539                .stream_name = "ssp0 Tx",
 540                .channels_min = SST_STEREO,
 541                .channels_max = SST_STEREO,
 542                .rates = SNDRV_PCM_RATE_48000,
 543                .formats = SNDRV_PCM_FMTBIT_S16_LE,
 544        },
 545        .capture = {
 546                .stream_name = "ssp0 Rx",
 547                .channels_min = SST_STEREO,
 548                .channels_max = SST_STEREO,
 549                .rates = SNDRV_PCM_RATE_48000,
 550                .formats = SNDRV_PCM_FMTBIT_S16_LE,
 551        },
 552},
 553{
 554        .name = "ssp1-port",
 555        .ops = &sst_be_dai_ops,
 556        .playback = {
 557                .stream_name = "ssp1 Tx",
 558                .channels_min = SST_STEREO,
 559                .channels_max = SST_STEREO,
 560                .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000,
 561                .formats = SNDRV_PCM_FMTBIT_S16_LE,
 562        },
 563        .capture = {
 564                .stream_name = "ssp1 Rx",
 565                .channels_min = SST_STEREO,
 566                .channels_max = SST_STEREO,
 567                .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000,
 568                .formats = SNDRV_PCM_FMTBIT_S16_LE,
 569        },
 570},
 571{
 572        .name = "ssp2-port",
 573        .ops = &sst_be_dai_ops,
 574        .playback = {
 575                .stream_name = "ssp2 Tx",
 576                .channels_min = SST_STEREO,
 577                .channels_max = SST_STEREO,
 578                .rates = SNDRV_PCM_RATE_48000,
 579                .formats = SNDRV_PCM_FMTBIT_S16_LE,
 580        },
 581        .capture = {
 582                .stream_name = "ssp2 Rx",
 583                .channels_min = SST_STEREO,
 584                .channels_max = SST_STEREO,
 585                .rates = SNDRV_PCM_RATE_48000,
 586                .formats = SNDRV_PCM_FMTBIT_S16_LE,
 587        },
 588},
 589};
 590
 591static int sst_platform_open(struct snd_pcm_substream *substream)
 592{
 593        struct snd_pcm_runtime *runtime;
 594
 595        if (substream->pcm->internal)
 596                return 0;
 597
 598        runtime = substream->runtime;
 599        runtime->hw = sst_platform_pcm_hw;
 600        return 0;
 601}
 602
 603static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream,
 604                                        int cmd)
 605{
 606        int ret_val = 0, str_id;
 607        struct sst_runtime_stream *stream;
 608        int status;
 609        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 610
 611        dev_dbg(rtd->dev, "sst_platform_pcm_trigger called\n");
 612        if (substream->pcm->internal)
 613                return 0;
 614        stream = substream->runtime->private_data;
 615        str_id = stream->stream_info.str_id;
 616        switch (cmd) {
 617        case SNDRV_PCM_TRIGGER_START:
 618                dev_dbg(rtd->dev, "sst: Trigger Start\n");
 619                status = SST_PLATFORM_RUNNING;
 620                stream->stream_info.arg = substream;
 621                ret_val = stream->ops->stream_start(sst->dev, str_id);
 622                break;
 623        case SNDRV_PCM_TRIGGER_STOP:
 624                dev_dbg(rtd->dev, "sst: in stop\n");
 625                status = SST_PLATFORM_DROPPED;
 626                ret_val = stream->ops->stream_drop(sst->dev, str_id);
 627                break;
 628        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 629        case SNDRV_PCM_TRIGGER_SUSPEND:
 630                dev_dbg(rtd->dev, "sst: in pause\n");
 631                status = SST_PLATFORM_PAUSED;
 632                ret_val = stream->ops->stream_pause(sst->dev, str_id);
 633                break;
 634        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 635        case SNDRV_PCM_TRIGGER_RESUME:
 636                dev_dbg(rtd->dev, "sst: in pause release\n");
 637                status = SST_PLATFORM_RUNNING;
 638                ret_val = stream->ops->stream_pause_release(sst->dev, str_id);
 639                break;
 640        default:
 641                return -EINVAL;
 642        }
 643
 644        if (!ret_val)
 645                sst_set_stream_status(stream, status);
 646
 647        return ret_val;
 648}
 649
 650
 651static snd_pcm_uframes_t sst_platform_pcm_pointer
 652                        (struct snd_pcm_substream *substream)
 653{
 654        struct sst_runtime_stream *stream;
 655        int ret_val, status;
 656        struct pcm_stream_info *str_info;
 657        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 658
 659        stream = substream->runtime->private_data;
 660        status = sst_get_stream_status(stream);
 661        if (status == SST_PLATFORM_INIT)
 662                return 0;
 663        str_info = &stream->stream_info;
 664        ret_val = stream->ops->stream_read_tstamp(sst->dev, str_info);
 665        if (ret_val) {
 666                dev_err(rtd->dev, "sst: error code = %d\n", ret_val);
 667                return ret_val;
 668        }
 669        substream->runtime->delay = str_info->pcm_delay;
 670        return str_info->buffer_ptr;
 671}
 672
 673static const struct snd_pcm_ops sst_platform_ops = {
 674        .open = sst_platform_open,
 675        .ioctl = snd_pcm_lib_ioctl,
 676        .trigger = sst_platform_pcm_trigger,
 677        .pointer = sst_platform_pcm_pointer,
 678};
 679
 680static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
 681{
 682        struct snd_soc_dai *dai = rtd->cpu_dai;
 683        struct snd_pcm *pcm = rtd->pcm;
 684        int retval = 0;
 685
 686        if (dai->driver->playback.channels_min ||
 687                        dai->driver->capture.channels_min) {
 688                retval =  snd_pcm_lib_preallocate_pages_for_all(pcm,
 689                        SNDRV_DMA_TYPE_CONTINUOUS,
 690                        snd_dma_continuous_data(GFP_DMA),
 691                        SST_MIN_BUFFER, SST_MAX_BUFFER);
 692                if (retval) {
 693                        dev_err(rtd->dev, "dma buffer allocation failure\n");
 694                        return retval;
 695                }
 696        }
 697        return retval;
 698}
 699
 700static int sst_soc_probe(struct snd_soc_platform *platform)
 701{
 702        struct sst_data *drv = dev_get_drvdata(platform->dev);
 703
 704        drv->soc_card = platform->component.card;
 705        return sst_dsp_init_v2_dpcm(platform);
 706}
 707
 708static struct snd_soc_platform_driver sst_soc_platform_drv  = {
 709        .probe          = sst_soc_probe,
 710        .ops            = &sst_platform_ops,
 711        .compr_ops      = &sst_platform_compr_ops,
 712        .pcm_new        = sst_pcm_new,
 713};
 714
 715static const struct snd_soc_component_driver sst_component = {
 716        .name           = "sst",
 717};
 718
 719
 720static int sst_platform_probe(struct platform_device *pdev)
 721{
 722        struct sst_data *drv;
 723        int ret;
 724        struct sst_platform_data *pdata;
 725
 726        drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
 727        if (drv == NULL) {
 728                return -ENOMEM;
 729        }
 730
 731        pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
 732        if (pdata == NULL) {
 733                return -ENOMEM;
 734        }
 735
 736        pdata->pdev_strm_map = dpcm_strm_map;
 737        pdata->strm_map_size = ARRAY_SIZE(dpcm_strm_map);
 738        drv->pdata = pdata;
 739        drv->pdev = pdev;
 740        mutex_init(&drv->lock);
 741        dev_set_drvdata(&pdev->dev, drv);
 742
 743        ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv);
 744        if (ret) {
 745                dev_err(&pdev->dev, "registering soc platform failed\n");
 746                return ret;
 747        }
 748
 749        ret = snd_soc_register_component(&pdev->dev, &sst_component,
 750                                sst_platform_dai, ARRAY_SIZE(sst_platform_dai));
 751        if (ret) {
 752                dev_err(&pdev->dev, "registering cpu dais failed\n");
 753                snd_soc_unregister_platform(&pdev->dev);
 754        }
 755        return ret;
 756}
 757
 758static int sst_platform_remove(struct platform_device *pdev)
 759{
 760
 761        snd_soc_unregister_component(&pdev->dev);
 762        snd_soc_unregister_platform(&pdev->dev);
 763        dev_dbg(&pdev->dev, "sst_platform_remove success\n");
 764        return 0;
 765}
 766
 767#ifdef CONFIG_PM_SLEEP
 768
 769static int sst_soc_prepare(struct device *dev)
 770{
 771        struct sst_data *drv = dev_get_drvdata(dev);
 772        struct snd_soc_pcm_runtime *rtd;
 773
 774        if (!drv->soc_card)
 775                return 0;
 776
 777        /* suspend all pcms first */
 778        snd_soc_suspend(drv->soc_card->dev);
 779        snd_soc_poweroff(drv->soc_card->dev);
 780
 781        /* set the SSPs to idle */
 782        list_for_each_entry(rtd, &drv->soc_card->rtd_list, list) {
 783                struct snd_soc_dai *dai = rtd->cpu_dai;
 784
 785                if (dai->active) {
 786                        send_ssp_cmd(dai, dai->name, 0);
 787                        sst_handle_vb_timer(dai, false);
 788                }
 789        }
 790
 791        return 0;
 792}
 793
 794static void sst_soc_complete(struct device *dev)
 795{
 796        struct sst_data *drv = dev_get_drvdata(dev);
 797        struct snd_soc_pcm_runtime *rtd;
 798
 799        if (!drv->soc_card)
 800                return;
 801
 802        /* restart SSPs */
 803        list_for_each_entry(rtd, &drv->soc_card->rtd_list, list) {
 804                struct snd_soc_dai *dai = rtd->cpu_dai;
 805
 806                if (dai->active) {
 807                        sst_handle_vb_timer(dai, true);
 808                        send_ssp_cmd(dai, dai->name, 1);
 809                }
 810        }
 811        snd_soc_resume(drv->soc_card->dev);
 812}
 813
 814#else
 815
 816#define sst_soc_prepare NULL
 817#define sst_soc_complete NULL
 818
 819#endif
 820
 821
 822static const struct dev_pm_ops sst_platform_pm = {
 823        .prepare        = sst_soc_prepare,
 824        .complete       = sst_soc_complete,
 825};
 826
 827static struct platform_driver sst_platform_driver = {
 828        .driver         = {
 829                .name           = "sst-mfld-platform",
 830                .pm             = &sst_platform_pm,
 831        },
 832        .probe          = sst_platform_probe,
 833        .remove         = sst_platform_remove,
 834};
 835
 836module_platform_driver(sst_platform_driver);
 837
 838MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver");
 839MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
 840MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
 841MODULE_LICENSE("GPL v2");
 842MODULE_ALIAS("platform:sst-atom-hifi2-platform");
 843MODULE_ALIAS("platform:sst-mfld-platform");
 844