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
 104/* MFLD - MSIC */
 105static struct snd_soc_dai_driver sst_platform_dai[] = {
 106{
 107        .name = "Headset-cpu-dai",
 108        .id = 0,
 109        .playback = {
 110                .channels_min = SST_STEREO,
 111                .channels_max = SST_STEREO,
 112                .rates = SNDRV_PCM_RATE_48000,
 113                .formats = SNDRV_PCM_FMTBIT_S24_LE,
 114        },
 115        .capture = {
 116                .channels_min = 1,
 117                .channels_max = 5,
 118                .rates = SNDRV_PCM_RATE_48000,
 119                .formats = SNDRV_PCM_FMTBIT_S24_LE,
 120        },
 121},
 122{
 123        .name = "Compress-cpu-dai",
 124        .compress_dai = 1,
 125        .playback = {
 126                .channels_min = SST_STEREO,
 127                .channels_max = SST_STEREO,
 128                .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
 129                .formats = SNDRV_PCM_FMTBIT_S16_LE,
 130        },
 131},
 132};
 133
 134/* helper functions */
 135void sst_set_stream_status(struct sst_runtime_stream *stream,
 136                                        int state)
 137{
 138        unsigned long flags;
 139        spin_lock_irqsave(&stream->status_lock, flags);
 140        stream->stream_status = state;
 141        spin_unlock_irqrestore(&stream->status_lock, flags);
 142}
 143
 144static inline int sst_get_stream_status(struct sst_runtime_stream *stream)
 145{
 146        int state;
 147        unsigned long flags;
 148
 149        spin_lock_irqsave(&stream->status_lock, flags);
 150        state = stream->stream_status;
 151        spin_unlock_irqrestore(&stream->status_lock, flags);
 152        return state;
 153}
 154
 155static void sst_fill_alloc_params(struct snd_pcm_substream *substream,
 156                                struct snd_sst_alloc_params_ext *alloc_param)
 157{
 158        unsigned int channels;
 159        snd_pcm_uframes_t period_size;
 160        ssize_t periodbytes;
 161        ssize_t buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
 162        u32 buffer_addr = virt_to_phys(substream->dma_buffer.area);
 163
 164        channels = substream->runtime->channels;
 165        period_size = substream->runtime->period_size;
 166        periodbytes = samples_to_bytes(substream->runtime, period_size);
 167        alloc_param->ring_buf_info[0].addr = buffer_addr;
 168        alloc_param->ring_buf_info[0].size = buffer_bytes;
 169        alloc_param->sg_count = 1;
 170        alloc_param->reserved = 0;
 171        alloc_param->frag_size = periodbytes * channels;
 172
 173}
 174static void sst_fill_pcm_params(struct snd_pcm_substream *substream,
 175                                struct snd_sst_stream_params *param)
 176{
 177        param->uc.pcm_params.num_chan = (u8) substream->runtime->channels;
 178        param->uc.pcm_params.pcm_wd_sz = substream->runtime->sample_bits;
 179        param->uc.pcm_params.sfreq = substream->runtime->rate;
 180
 181        /* PCM stream via ALSA interface */
 182        param->uc.pcm_params.use_offload_path = 0;
 183        param->uc.pcm_params.reserved2 = 0;
 184        memset(param->uc.pcm_params.channel_map, 0, sizeof(u8));
 185
 186}
 187
 188static int sst_get_stream_mapping(int dev, int sdev, int dir,
 189        struct sst_dev_stream_map *map, int size)
 190{
 191        int i;
 192
 193        if (map == NULL)
 194                return -EINVAL;
 195
 196
 197        /* index 0 is not used in stream map */
 198        for (i = 1; i < size; i++) {
 199                if ((map[i].dev_num == dev) && (map[i].direction == dir))
 200                        return i;
 201        }
 202        return 0;
 203}
 204
 205int sst_fill_stream_params(void *substream,
 206        const struct sst_data *ctx, struct snd_sst_params *str_params, bool is_compress)
 207{
 208        int map_size;
 209        int index;
 210        struct sst_dev_stream_map *map;
 211        struct snd_pcm_substream *pstream = NULL;
 212        struct snd_compr_stream *cstream = NULL;
 213
 214        map = ctx->pdata->pdev_strm_map;
 215        map_size = ctx->pdata->strm_map_size;
 216
 217        if (is_compress == true)
 218                cstream = (struct snd_compr_stream *)substream;
 219        else
 220                pstream = (struct snd_pcm_substream *)substream;
 221
 222        str_params->stream_type = SST_STREAM_TYPE_MUSIC;
 223
 224        /* For pcm streams */
 225        if (pstream) {
 226                index = sst_get_stream_mapping(pstream->pcm->device,
 227                                          pstream->number, pstream->stream,
 228                                          map, map_size);
 229                if (index <= 0)
 230                        return -EINVAL;
 231
 232                str_params->stream_id = index;
 233                str_params->device_type = map[index].device_id;
 234                str_params->task = map[index].task_id;
 235
 236                str_params->ops = (u8)pstream->stream;
 237        }
 238
 239        if (cstream) {
 240                index = sst_get_stream_mapping(cstream->device->device,
 241                                               0, cstream->direction,
 242                                               map, map_size);
 243                if (index <= 0)
 244                        return -EINVAL;
 245                str_params->stream_id = index;
 246                str_params->device_type = map[index].device_id;
 247                str_params->task = map[index].task_id;
 248
 249                str_params->ops = (u8)cstream->direction;
 250        }
 251        return 0;
 252}
 253
 254static int sst_platform_alloc_stream(struct snd_pcm_substream *substream,
 255                struct snd_soc_dai *dai)
 256{
 257        struct sst_runtime_stream *stream =
 258                        substream->runtime->private_data;
 259        struct snd_sst_stream_params param = {{{0,},},};
 260        struct snd_sst_params str_params = {0};
 261        struct snd_sst_alloc_params_ext alloc_params = {0};
 262        int ret_val = 0;
 263        struct sst_data *ctx = snd_soc_dai_get_drvdata(dai);
 264
 265        /* set codec params and inform SST driver the same */
 266        sst_fill_pcm_params(substream, &param);
 267        sst_fill_alloc_params(substream, &alloc_params);
 268        substream->runtime->dma_area = substream->dma_buffer.area;
 269        str_params.sparams = param;
 270        str_params.aparams = alloc_params;
 271        str_params.codec = SST_CODEC_TYPE_PCM;
 272
 273        /* fill the device type and stream id to pass to SST driver */
 274        ret_val = sst_fill_stream_params(substream, ctx, &str_params, false);
 275        if (ret_val < 0)
 276                return ret_val;
 277
 278        stream->stream_info.str_id = str_params.stream_id;
 279
 280        ret_val = stream->ops->open(sst->dev, &str_params);
 281        if (ret_val <= 0)
 282                return ret_val;
 283
 284
 285        return ret_val;
 286}
 287
 288static void sst_period_elapsed(void *arg)
 289{
 290        struct snd_pcm_substream *substream = arg;
 291        struct sst_runtime_stream *stream;
 292        int status;
 293
 294        if (!substream || !substream->runtime)
 295                return;
 296        stream = substream->runtime->private_data;
 297        if (!stream)
 298                return;
 299        status = sst_get_stream_status(stream);
 300        if (status != SST_PLATFORM_RUNNING)
 301                return;
 302        snd_pcm_period_elapsed(substream);
 303}
 304
 305static int sst_platform_init_stream(struct snd_pcm_substream *substream)
 306{
 307        struct sst_runtime_stream *stream =
 308                        substream->runtime->private_data;
 309        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 310        int ret_val;
 311
 312        dev_dbg(rtd->dev, "setting buffer ptr param\n");
 313        sst_set_stream_status(stream, SST_PLATFORM_INIT);
 314        stream->stream_info.period_elapsed = sst_period_elapsed;
 315        stream->stream_info.arg = substream;
 316        stream->stream_info.buffer_ptr = 0;
 317        stream->stream_info.sfreq = substream->runtime->rate;
 318        ret_val = stream->ops->stream_init(sst->dev, &stream->stream_info);
 319        if (ret_val)
 320                dev_err(rtd->dev, "control_set ret error %d\n", ret_val);
 321        return ret_val;
 322
 323}
 324
 325static int power_up_sst(struct sst_runtime_stream *stream)
 326{
 327        return stream->ops->power(sst->dev, true);
 328}
 329
 330static void power_down_sst(struct sst_runtime_stream *stream)
 331{
 332        stream->ops->power(sst->dev, false);
 333}
 334
 335static int sst_media_open(struct snd_pcm_substream *substream,
 336                struct snd_soc_dai *dai)
 337{
 338        int ret_val = 0;
 339        struct snd_pcm_runtime *runtime = substream->runtime;
 340        struct sst_runtime_stream *stream;
 341
 342        stream = kzalloc(sizeof(*stream), GFP_KERNEL);
 343        if (!stream)
 344                return -ENOMEM;
 345        spin_lock_init(&stream->status_lock);
 346
 347        /* get the sst ops */
 348        mutex_lock(&sst_lock);
 349        if (!sst ||
 350            !try_module_get(sst->dev->driver->owner)) {
 351                dev_err(dai->dev, "no device available to run\n");
 352                ret_val = -ENODEV;
 353                goto out_ops;
 354        }
 355        stream->ops = sst->ops;
 356        mutex_unlock(&sst_lock);
 357
 358        stream->stream_info.str_id = 0;
 359
 360        stream->stream_info.arg = substream;
 361        /* allocate memory for SST API set */
 362        runtime->private_data = stream;
 363
 364        ret_val = power_up_sst(stream);
 365        if (ret_val < 0)
 366                return ret_val;
 367
 368        /* Make sure, that the period size is always even */
 369        snd_pcm_hw_constraint_step(substream->runtime, 0,
 370                           SNDRV_PCM_HW_PARAM_PERIODS, 2);
 371
 372        return snd_pcm_hw_constraint_integer(runtime,
 373                         SNDRV_PCM_HW_PARAM_PERIODS);
 374out_ops:
 375        kfree(stream);
 376        mutex_unlock(&sst_lock);
 377        return ret_val;
 378}
 379
 380static void sst_media_close(struct snd_pcm_substream *substream,
 381                struct snd_soc_dai *dai)
 382{
 383        struct sst_runtime_stream *stream;
 384        int ret_val = 0, str_id;
 385
 386        stream = substream->runtime->private_data;
 387        power_down_sst(stream);
 388
 389        str_id = stream->stream_info.str_id;
 390        if (str_id)
 391                ret_val = stream->ops->close(sst->dev, str_id);
 392        module_put(sst->dev->driver->owner);
 393        kfree(stream);
 394}
 395
 396static inline unsigned int get_current_pipe_id(struct snd_soc_dai *dai,
 397                                               struct snd_pcm_substream *substream)
 398{
 399        struct sst_data *sst = snd_soc_dai_get_drvdata(dai);
 400        struct sst_dev_stream_map *map = sst->pdata->pdev_strm_map;
 401        struct sst_runtime_stream *stream =
 402                        substream->runtime->private_data;
 403        u32 str_id = stream->stream_info.str_id;
 404        unsigned int pipe_id;
 405
 406        pipe_id = map[str_id].device_id;
 407
 408        dev_dbg(dai->dev, "got pipe_id = %#x for str_id = %d\n",
 409                        pipe_id, str_id);
 410        return pipe_id;
 411}
 412
 413static int sst_media_prepare(struct snd_pcm_substream *substream,
 414                struct snd_soc_dai *dai)
 415{
 416        struct sst_runtime_stream *stream;
 417        int ret_val = 0, str_id;
 418
 419        stream = substream->runtime->private_data;
 420        str_id = stream->stream_info.str_id;
 421        if (stream->stream_info.str_id) {
 422                ret_val = stream->ops->stream_drop(sst->dev, str_id);
 423                return ret_val;
 424        }
 425
 426        ret_val = sst_platform_alloc_stream(substream, dai);
 427        if (ret_val <= 0)
 428                return ret_val;
 429        snprintf(substream->pcm->id, sizeof(substream->pcm->id),
 430                        "%d", stream->stream_info.str_id);
 431
 432        ret_val = sst_platform_init_stream(substream);
 433        if (ret_val)
 434                return ret_val;
 435        substream->runtime->hw.info = SNDRV_PCM_INFO_BLOCK_TRANSFER;
 436        return ret_val;
 437}
 438
 439static int sst_media_hw_params(struct snd_pcm_substream *substream,
 440                                struct snd_pcm_hw_params *params,
 441                                struct snd_soc_dai *dai)
 442{
 443        snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
 444        memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
 445        return 0;
 446}
 447
 448static int sst_media_hw_free(struct snd_pcm_substream *substream,
 449                struct snd_soc_dai *dai)
 450{
 451        return snd_pcm_lib_free_pages(substream);
 452}
 453
 454static struct snd_soc_dai_ops sst_media_dai_ops = {
 455        .startup = sst_media_open,
 456        .shutdown = sst_media_close,
 457        .prepare = sst_media_prepare,
 458        .hw_params = sst_media_hw_params,
 459        .hw_free = sst_media_hw_free,
 460};
 461
 462static int sst_platform_open(struct snd_pcm_substream *substream)
 463{
 464        struct snd_pcm_runtime *runtime;
 465
 466        if (substream->pcm->internal)
 467                return 0;
 468
 469        runtime = substream->runtime;
 470        runtime->hw = sst_platform_pcm_hw;
 471        return 0;
 472}
 473
 474static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream,
 475                                        int cmd)
 476{
 477        int ret_val = 0, str_id;
 478        struct sst_runtime_stream *stream;
 479        int status;
 480        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 481
 482        dev_dbg(rtd->dev, "sst_platform_pcm_trigger called\n");
 483        if (substream->pcm->internal)
 484                return 0;
 485        stream = substream->runtime->private_data;
 486        str_id = stream->stream_info.str_id;
 487        switch (cmd) {
 488        case SNDRV_PCM_TRIGGER_START:
 489                dev_dbg(rtd->dev, "sst: Trigger Start\n");
 490                status = SST_PLATFORM_RUNNING;
 491                stream->stream_info.arg = substream;
 492                ret_val = stream->ops->stream_start(sst->dev, str_id);
 493                break;
 494        case SNDRV_PCM_TRIGGER_STOP:
 495                dev_dbg(rtd->dev, "sst: in stop\n");
 496                status = SST_PLATFORM_DROPPED;
 497                ret_val = stream->ops->stream_drop(sst->dev, str_id);
 498                break;
 499        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 500                dev_dbg(rtd->dev, "sst: in pause\n");
 501                status = SST_PLATFORM_PAUSED;
 502                ret_val = stream->ops->stream_pause(sst->dev, str_id);
 503                break;
 504        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 505                dev_dbg(rtd->dev, "sst: in pause release\n");
 506                status = SST_PLATFORM_RUNNING;
 507                ret_val = stream->ops->stream_pause_release(sst->dev, str_id);
 508                break;
 509        default:
 510                return -EINVAL;
 511        }
 512
 513        if (!ret_val)
 514                sst_set_stream_status(stream, status);
 515
 516        return ret_val;
 517}
 518
 519
 520static snd_pcm_uframes_t sst_platform_pcm_pointer
 521                        (struct snd_pcm_substream *substream)
 522{
 523        struct sst_runtime_stream *stream;
 524        int ret_val, status;
 525        struct pcm_stream_info *str_info;
 526        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 527
 528        stream = substream->runtime->private_data;
 529        status = sst_get_stream_status(stream);
 530        if (status == SST_PLATFORM_INIT)
 531                return 0;
 532        str_info = &stream->stream_info;
 533        ret_val = stream->ops->stream_read_tstamp(sst->dev, str_info);
 534        if (ret_val) {
 535                dev_err(rtd->dev, "sst: error code = %d\n", ret_val);
 536                return ret_val;
 537        }
 538        substream->runtime->delay = str_info->pcm_delay;
 539        return str_info->buffer_ptr;
 540}
 541
 542static struct snd_pcm_ops sst_platform_ops = {
 543        .open = sst_platform_open,
 544        .ioctl = snd_pcm_lib_ioctl,
 545        .trigger = sst_platform_pcm_trigger,
 546        .pointer = sst_platform_pcm_pointer,
 547};
 548
 549static void sst_pcm_free(struct snd_pcm *pcm)
 550{
 551        dev_dbg(pcm->dev, "sst_pcm_free called\n");
 552        snd_pcm_lib_preallocate_free_for_all(pcm);
 553}
 554
 555static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
 556{
 557        struct snd_soc_dai *dai = rtd->cpu_dai;
 558        struct snd_pcm *pcm = rtd->pcm;
 559        int retval = 0;
 560
 561        if (dai->driver->playback.channels_min ||
 562                        dai->driver->capture.channels_min) {
 563                retval =  snd_pcm_lib_preallocate_pages_for_all(pcm,
 564                        SNDRV_DMA_TYPE_CONTINUOUS,
 565                        snd_dma_continuous_data(GFP_DMA),
 566                        SST_MIN_BUFFER, SST_MAX_BUFFER);
 567                if (retval) {
 568                        dev_err(rtd->dev, "dma buffer allocationf fail\n");
 569                        return retval;
 570                }
 571        }
 572        return retval;
 573}
 574
 575static int sst_soc_probe(struct snd_soc_platform *platform)
 576{
 577        return sst_dsp_init_v2_dpcm(platform);
 578}
 579
 580static struct snd_soc_platform_driver sst_soc_platform_drv  = {
 581        .probe          = sst_soc_probe,
 582        .ops            = &sst_platform_ops,
 583        .compr_ops      = &sst_platform_compr_ops,
 584        .pcm_new        = sst_pcm_new,
 585        .pcm_free       = sst_pcm_free,
 586};
 587
 588static const struct snd_soc_component_driver sst_component = {
 589        .name           = "sst",
 590};
 591
 592
 593static int sst_platform_probe(struct platform_device *pdev)
 594{
 595        struct sst_data *drv;
 596        int ret;
 597        struct sst_platform_data *pdata;
 598
 599        drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
 600        if (drv == NULL) {
 601                return -ENOMEM;
 602        }
 603
 604        pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
 605        if (pdata == NULL) {
 606                return -ENOMEM;
 607        }
 608
 609        pdata->pdev_strm_map = dpcm_strm_map;
 610        pdata->strm_map_size = ARRAY_SIZE(dpcm_strm_map);
 611        drv->pdata = pdata;
 612        mutex_init(&drv->lock);
 613        dev_set_drvdata(&pdev->dev, drv);
 614
 615        ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv);
 616        if (ret) {
 617                dev_err(&pdev->dev, "registering soc platform failed\n");
 618                return ret;
 619        }
 620
 621        ret = snd_soc_register_component(&pdev->dev, &sst_component,
 622                                sst_platform_dai, ARRAY_SIZE(sst_platform_dai));
 623        if (ret) {
 624                dev_err(&pdev->dev, "registering cpu dais failed\n");
 625                snd_soc_unregister_platform(&pdev->dev);
 626        }
 627        return ret;
 628}
 629
 630static int sst_platform_remove(struct platform_device *pdev)
 631{
 632
 633        snd_soc_unregister_component(&pdev->dev);
 634        snd_soc_unregister_platform(&pdev->dev);
 635        dev_dbg(&pdev->dev, "sst_platform_remove success\n");
 636        return 0;
 637}
 638
 639static struct platform_driver sst_platform_driver = {
 640        .driver         = {
 641                .name           = "sst-mfld-platform",
 642                .owner          = THIS_MODULE,
 643        },
 644        .probe          = sst_platform_probe,
 645        .remove         = sst_platform_remove,
 646};
 647
 648module_platform_driver(sst_platform_driver);
 649
 650MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver");
 651MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
 652MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
 653MODULE_LICENSE("GPL v2");
 654MODULE_ALIAS("platform:sst-mfld-platform");
 655