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