linux/sound/soc/intel/baytrail/sst-baytrail-pcm.c
<<
>>
Prefs
   1/*
   2 * Intel Baytrail SST PCM Support
   3 * Copyright (c) 2014, Intel Corporation.
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms and conditions of the GNU General Public License,
   7 * version 2, as published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  12 * more details.
  13 */
  14
  15#include <linux/module.h>
  16#include <linux/dma-mapping.h>
  17#include <linux/slab.h>
  18#include <sound/core.h>
  19#include <sound/pcm.h>
  20#include <sound/pcm_params.h>
  21#include <sound/soc.h>
  22#include "sst-baytrail-ipc.h"
  23#include "../common/sst-dsp-priv.h"
  24#include "../common/sst-dsp.h"
  25
  26#define BYT_PCM_COUNT           2
  27
  28static const struct snd_pcm_hardware sst_byt_pcm_hardware = {
  29        .info                   = SNDRV_PCM_INFO_MMAP |
  30                                  SNDRV_PCM_INFO_MMAP_VALID |
  31                                  SNDRV_PCM_INFO_INTERLEAVED |
  32                                  SNDRV_PCM_INFO_PAUSE |
  33                                  SNDRV_PCM_INFO_RESUME,
  34        .formats                = SNDRV_PCM_FMTBIT_S16_LE |
  35                                  SNDRV_PCM_FMTBIT_S24_LE,
  36        .period_bytes_min       = 384,
  37        .period_bytes_max       = 48000,
  38        .periods_min            = 2,
  39        .periods_max            = 250,
  40        .buffer_bytes_max       = 96000,
  41};
  42
  43/* private data for each PCM DSP stream */
  44struct sst_byt_pcm_data {
  45        struct sst_byt_stream *stream;
  46        struct snd_pcm_substream *substream;
  47        struct mutex mutex;
  48
  49        /* latest DSP DMA hw pointer */
  50        u32 hw_ptr;
  51
  52        struct work_struct work;
  53};
  54
  55/* private data for the driver */
  56struct sst_byt_priv_data {
  57        /* runtime DSP */
  58        struct sst_byt *byt;
  59
  60        /* DAI data */
  61        struct sst_byt_pcm_data pcm[BYT_PCM_COUNT];
  62
  63        /* flag indicating is stream context restore needed after suspend */
  64        bool restore_stream;
  65};
  66
  67/* this may get called several times by oss emulation */
  68static int sst_byt_pcm_hw_params(struct snd_pcm_substream *substream,
  69                                 struct snd_pcm_hw_params *params)
  70{
  71        struct snd_soc_pcm_runtime *rtd = substream->private_data;
  72        struct sst_byt_priv_data *pdata =
  73                snd_soc_platform_get_drvdata(rtd->platform);
  74        struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
  75        struct sst_byt *byt = pdata->byt;
  76        u32 rate, bits;
  77        u8 channels;
  78        int ret, playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
  79
  80        dev_dbg(rtd->dev, "PCM: hw_params, pcm_data %p\n", pcm_data);
  81
  82        ret = sst_byt_stream_type(byt, pcm_data->stream,
  83                                  1, 1, !playback);
  84        if (ret < 0) {
  85                dev_err(rtd->dev, "failed to set stream format %d\n", ret);
  86                return ret;
  87        }
  88
  89        rate = params_rate(params);
  90        ret = sst_byt_stream_set_rate(byt, pcm_data->stream, rate);
  91        if (ret < 0) {
  92                dev_err(rtd->dev, "could not set rate %d\n", rate);
  93                return ret;
  94        }
  95
  96        bits = snd_pcm_format_width(params_format(params));
  97        ret = sst_byt_stream_set_bits(byt, pcm_data->stream, bits);
  98        if (ret < 0) {
  99                dev_err(rtd->dev, "could not set formats %d\n",
 100                        params_rate(params));
 101                return ret;
 102        }
 103
 104        channels = (u8)(params_channels(params) & 0xF);
 105        ret = sst_byt_stream_set_channels(byt, pcm_data->stream, channels);
 106        if (ret < 0) {
 107                dev_err(rtd->dev, "could not set channels %d\n",
 108                        params_rate(params));
 109                return ret;
 110        }
 111
 112        snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
 113
 114        ret = sst_byt_stream_buffer(byt, pcm_data->stream,
 115                                    substream->dma_buffer.addr,
 116                                    params_buffer_bytes(params));
 117        if (ret < 0) {
 118                dev_err(rtd->dev, "PCM: failed to set DMA buffer %d\n", ret);
 119                return ret;
 120        }
 121
 122        ret = sst_byt_stream_commit(byt, pcm_data->stream);
 123        if (ret < 0) {
 124                dev_err(rtd->dev, "PCM: failed stream commit %d\n", ret);
 125                return ret;
 126        }
 127
 128        return 0;
 129}
 130
 131static int sst_byt_pcm_hw_free(struct snd_pcm_substream *substream)
 132{
 133        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 134
 135        dev_dbg(rtd->dev, "PCM: hw_free\n");
 136        snd_pcm_lib_free_pages(substream);
 137
 138        return 0;
 139}
 140
 141static int sst_byt_pcm_restore_stream_context(struct snd_pcm_substream *substream)
 142{
 143        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 144        struct sst_byt_priv_data *pdata =
 145                snd_soc_platform_get_drvdata(rtd->platform);
 146        struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
 147        struct sst_byt *byt = pdata->byt;
 148        int ret;
 149
 150        /* commit stream using existing stream params */
 151        ret = sst_byt_stream_commit(byt, pcm_data->stream);
 152        if (ret < 0) {
 153                dev_err(rtd->dev, "PCM: failed stream commit %d\n", ret);
 154                return ret;
 155        }
 156
 157        sst_byt_stream_start(byt, pcm_data->stream, pcm_data->hw_ptr);
 158
 159        dev_dbg(rtd->dev, "stream context restored at offset %d\n",
 160                pcm_data->hw_ptr);
 161
 162        return 0;
 163}
 164
 165static void sst_byt_pcm_work(struct work_struct *work)
 166{
 167        struct sst_byt_pcm_data *pcm_data =
 168                container_of(work, struct sst_byt_pcm_data, work);
 169
 170        if (snd_pcm_running(pcm_data->substream))
 171                sst_byt_pcm_restore_stream_context(pcm_data->substream);
 172}
 173
 174static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 175{
 176        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 177        struct sst_byt_priv_data *pdata =
 178                snd_soc_platform_get_drvdata(rtd->platform);
 179        struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
 180        struct sst_byt *byt = pdata->byt;
 181
 182        dev_dbg(rtd->dev, "PCM: trigger %d\n", cmd);
 183
 184        switch (cmd) {
 185        case SNDRV_PCM_TRIGGER_START:
 186                pcm_data->hw_ptr = 0;
 187                sst_byt_stream_start(byt, pcm_data->stream, 0);
 188                break;
 189        case SNDRV_PCM_TRIGGER_RESUME:
 190                if (pdata->restore_stream == true)
 191                        schedule_work(&pcm_data->work);
 192                else
 193                        sst_byt_stream_resume(byt, pcm_data->stream);
 194                break;
 195        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 196                sst_byt_stream_resume(byt, pcm_data->stream);
 197                break;
 198        case SNDRV_PCM_TRIGGER_STOP:
 199                sst_byt_stream_stop(byt, pcm_data->stream);
 200                break;
 201        case SNDRV_PCM_TRIGGER_SUSPEND:
 202                pdata->restore_stream = false;
 203        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 204                sst_byt_stream_pause(byt, pcm_data->stream);
 205                break;
 206        default:
 207                break;
 208        }
 209
 210        return 0;
 211}
 212
 213static u32 byt_notify_pointer(struct sst_byt_stream *stream, void *data)
 214{
 215        struct sst_byt_pcm_data *pcm_data = data;
 216        struct snd_pcm_substream *substream = pcm_data->substream;
 217        struct snd_pcm_runtime *runtime = substream->runtime;
 218        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 219        struct sst_byt_priv_data *pdata =
 220                snd_soc_platform_get_drvdata(rtd->platform);
 221        struct sst_byt *byt = pdata->byt;
 222        u32 pos, hw_pos;
 223
 224        hw_pos = sst_byt_get_dsp_position(byt, pcm_data->stream,
 225                                          snd_pcm_lib_buffer_bytes(substream));
 226        pcm_data->hw_ptr = hw_pos;
 227        pos = frames_to_bytes(runtime,
 228                              (runtime->control->appl_ptr %
 229                               runtime->buffer_size));
 230
 231        dev_dbg(rtd->dev, "PCM: App/DMA pointer %u/%u bytes\n", pos, hw_pos);
 232
 233        snd_pcm_period_elapsed(substream);
 234        return pos;
 235}
 236
 237static snd_pcm_uframes_t sst_byt_pcm_pointer(struct snd_pcm_substream *substream)
 238{
 239        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 240        struct snd_pcm_runtime *runtime = substream->runtime;
 241        struct sst_byt_priv_data *pdata =
 242                snd_soc_platform_get_drvdata(rtd->platform);
 243        struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
 244
 245        dev_dbg(rtd->dev, "PCM: DMA pointer %u bytes\n", pcm_data->hw_ptr);
 246
 247        return bytes_to_frames(runtime, pcm_data->hw_ptr);
 248}
 249
 250static int sst_byt_pcm_open(struct snd_pcm_substream *substream)
 251{
 252        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 253        struct sst_byt_priv_data *pdata =
 254                snd_soc_platform_get_drvdata(rtd->platform);
 255        struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
 256        struct sst_byt *byt = pdata->byt;
 257
 258        dev_dbg(rtd->dev, "PCM: open\n");
 259
 260        mutex_lock(&pcm_data->mutex);
 261
 262        pcm_data->substream = substream;
 263
 264        snd_soc_set_runtime_hwparams(substream, &sst_byt_pcm_hardware);
 265
 266        pcm_data->stream = sst_byt_stream_new(byt, substream->stream + 1,
 267                                              byt_notify_pointer, pcm_data);
 268        if (pcm_data->stream == NULL) {
 269                dev_err(rtd->dev, "failed to create stream\n");
 270                mutex_unlock(&pcm_data->mutex);
 271                return -EINVAL;
 272        }
 273
 274        mutex_unlock(&pcm_data->mutex);
 275        return 0;
 276}
 277
 278static int sst_byt_pcm_close(struct snd_pcm_substream *substream)
 279{
 280        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 281        struct sst_byt_priv_data *pdata =
 282                snd_soc_platform_get_drvdata(rtd->platform);
 283        struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
 284        struct sst_byt *byt = pdata->byt;
 285        int ret;
 286
 287        dev_dbg(rtd->dev, "PCM: close\n");
 288
 289        cancel_work_sync(&pcm_data->work);
 290        mutex_lock(&pcm_data->mutex);
 291        ret = sst_byt_stream_free(byt, pcm_data->stream);
 292        if (ret < 0) {
 293                dev_dbg(rtd->dev, "Free stream fail\n");
 294                goto out;
 295        }
 296        pcm_data->stream = NULL;
 297
 298out:
 299        mutex_unlock(&pcm_data->mutex);
 300        return ret;
 301}
 302
 303static int sst_byt_pcm_mmap(struct snd_pcm_substream *substream,
 304                            struct vm_area_struct *vma)
 305{
 306        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 307
 308        dev_dbg(rtd->dev, "PCM: mmap\n");
 309        return snd_pcm_lib_default_mmap(substream, vma);
 310}
 311
 312static struct snd_pcm_ops sst_byt_pcm_ops = {
 313        .open           = sst_byt_pcm_open,
 314        .close          = sst_byt_pcm_close,
 315        .ioctl          = snd_pcm_lib_ioctl,
 316        .hw_params      = sst_byt_pcm_hw_params,
 317        .hw_free        = sst_byt_pcm_hw_free,
 318        .trigger        = sst_byt_pcm_trigger,
 319        .pointer        = sst_byt_pcm_pointer,
 320        .mmap           = sst_byt_pcm_mmap,
 321};
 322
 323static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd)
 324{
 325        struct snd_pcm *pcm = rtd->pcm;
 326        size_t size;
 327        struct snd_soc_platform *platform = rtd->platform;
 328        struct sst_pdata *pdata = dev_get_platdata(platform->dev);
 329        int ret = 0;
 330
 331        if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
 332            pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
 333                size = sst_byt_pcm_hardware.buffer_bytes_max;
 334                ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
 335                                                            SNDRV_DMA_TYPE_DEV,
 336                                                            pdata->dma_dev,
 337                                                            size, size);
 338                if (ret) {
 339                        dev_err(rtd->dev, "dma buffer allocation failed %d\n",
 340                                ret);
 341                        return ret;
 342                }
 343        }
 344
 345        return ret;
 346}
 347
 348static struct snd_soc_dai_driver byt_dais[] = {
 349        {
 350                .name  = "Baytrail PCM",
 351                .playback = {
 352                        .stream_name = "System Playback",
 353                        .channels_min = 2,
 354                        .channels_max = 2,
 355                        .rates = SNDRV_PCM_RATE_48000,
 356                        .formats = SNDRV_PCM_FMTBIT_S24_3LE |
 357                                   SNDRV_PCM_FMTBIT_S16_LE,
 358                },
 359                .capture = {
 360                        .stream_name = "Analog Capture",
 361                        .channels_min = 2,
 362                        .channels_max = 2,
 363                        .rates = SNDRV_PCM_RATE_48000,
 364                        .formats = SNDRV_PCM_FMTBIT_S16_LE,
 365                },
 366        },
 367};
 368
 369static int sst_byt_pcm_probe(struct snd_soc_platform *platform)
 370{
 371        struct sst_pdata *plat_data = dev_get_platdata(platform->dev);
 372        struct sst_byt_priv_data *priv_data;
 373        int i;
 374
 375        if (!plat_data)
 376                return -ENODEV;
 377
 378        priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data),
 379                                 GFP_KERNEL);
 380        if (!priv_data)
 381                return -ENOMEM;
 382        priv_data->byt = plat_data->dsp;
 383        snd_soc_platform_set_drvdata(platform, priv_data);
 384
 385        for (i = 0; i < BYT_PCM_COUNT; i++) {
 386                mutex_init(&priv_data->pcm[i].mutex);
 387                INIT_WORK(&priv_data->pcm[i].work, sst_byt_pcm_work);
 388        }
 389
 390        return 0;
 391}
 392
 393static int sst_byt_pcm_remove(struct snd_soc_platform *platform)
 394{
 395        return 0;
 396}
 397
 398static struct snd_soc_platform_driver byt_soc_platform = {
 399        .probe          = sst_byt_pcm_probe,
 400        .remove         = sst_byt_pcm_remove,
 401        .ops            = &sst_byt_pcm_ops,
 402        .pcm_new        = sst_byt_pcm_new,
 403};
 404
 405static const struct snd_soc_component_driver byt_dai_component = {
 406        .name           = "byt-dai",
 407};
 408
 409#ifdef CONFIG_PM
 410static int sst_byt_pcm_dev_suspend_late(struct device *dev)
 411{
 412        struct sst_pdata *sst_pdata = dev_get_platdata(dev);
 413        struct sst_byt_priv_data *priv_data = dev_get_drvdata(dev);
 414        int ret;
 415
 416        dev_dbg(dev, "suspending late\n");
 417
 418        ret = sst_byt_dsp_suspend_late(dev, sst_pdata);
 419        if (ret < 0) {
 420                dev_err(dev, "failed to suspend %d\n", ret);
 421                return ret;
 422        }
 423
 424        priv_data->restore_stream = true;
 425
 426        return ret;
 427}
 428
 429static int sst_byt_pcm_dev_resume_early(struct device *dev)
 430{
 431        struct sst_pdata *sst_pdata = dev_get_platdata(dev);
 432        int ret;
 433
 434        dev_dbg(dev, "resume early\n");
 435
 436        /* load fw and boot DSP */
 437        ret = sst_byt_dsp_boot(dev, sst_pdata);
 438        if (ret)
 439                return ret;
 440
 441        /* wait for FW to finish booting */
 442        return sst_byt_dsp_wait_for_ready(dev, sst_pdata);
 443}
 444
 445static const struct dev_pm_ops sst_byt_pm_ops = {
 446        .suspend_late = sst_byt_pcm_dev_suspend_late,
 447        .resume_early = sst_byt_pcm_dev_resume_early,
 448};
 449
 450#define SST_BYT_PM_OPS  (&sst_byt_pm_ops)
 451#else
 452#define SST_BYT_PM_OPS  NULL
 453#endif
 454
 455static int sst_byt_pcm_dev_probe(struct platform_device *pdev)
 456{
 457        struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
 458        int ret;
 459
 460        ret = sst_byt_dsp_init(&pdev->dev, sst_pdata);
 461        if (ret < 0)
 462                return -ENODEV;
 463
 464        ret = snd_soc_register_platform(&pdev->dev, &byt_soc_platform);
 465        if (ret < 0)
 466                goto err_plat;
 467
 468        ret = snd_soc_register_component(&pdev->dev, &byt_dai_component,
 469                                         byt_dais, ARRAY_SIZE(byt_dais));
 470        if (ret < 0)
 471                goto err_comp;
 472
 473        return 0;
 474
 475err_comp:
 476        snd_soc_unregister_platform(&pdev->dev);
 477err_plat:
 478        sst_byt_dsp_free(&pdev->dev, sst_pdata);
 479        return ret;
 480}
 481
 482static int sst_byt_pcm_dev_remove(struct platform_device *pdev)
 483{
 484        struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
 485
 486        snd_soc_unregister_platform(&pdev->dev);
 487        snd_soc_unregister_component(&pdev->dev);
 488        sst_byt_dsp_free(&pdev->dev, sst_pdata);
 489
 490        return 0;
 491}
 492
 493static struct platform_driver sst_byt_pcm_driver = {
 494        .driver = {
 495                .name = "baytrail-pcm-audio",
 496                .pm = SST_BYT_PM_OPS,
 497        },
 498
 499        .probe = sst_byt_pcm_dev_probe,
 500        .remove = sst_byt_pcm_dev_remove,
 501};
 502module_platform_driver(sst_byt_pcm_driver);
 503
 504MODULE_AUTHOR("Jarkko Nikula");
 505MODULE_DESCRIPTION("Baytrail PCM");
 506MODULE_LICENSE("GPL v2");
 507MODULE_ALIAS("platform:baytrail-pcm-audio");
 508