1a40e693cSJeeja KP /* 2a40e693cSJeeja KP * skl-pcm.c -ASoC HDA Platform driver file implementing PCM functionality 3a40e693cSJeeja KP * 4a40e693cSJeeja KP * Copyright (C) 2014-2015 Intel Corp 5a40e693cSJeeja KP * Author: Jeeja KP <jeeja.kp@intel.com> 6a40e693cSJeeja KP * 7a40e693cSJeeja KP * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8a40e693cSJeeja KP * 9a40e693cSJeeja KP * This program is free software; you can redistribute it and/or modify 10a40e693cSJeeja KP * it under the terms of the GNU General Public License as published by 11a40e693cSJeeja KP * the Free Software Foundation; version 2 of the License. 12a40e693cSJeeja KP * 13a40e693cSJeeja KP * This program is distributed in the hope that it will be useful, but 14a40e693cSJeeja KP * WITHOUT ANY WARRANTY; without even the implied warranty of 15a40e693cSJeeja KP * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16a40e693cSJeeja KP * General Public License for more details. 17a40e693cSJeeja KP * 18a40e693cSJeeja KP * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19a40e693cSJeeja KP * 20a40e693cSJeeja KP */ 21a40e693cSJeeja KP 22a40e693cSJeeja KP #include <linux/pci.h> 23a40e693cSJeeja KP #include <linux/pm_runtime.h> 24a40e693cSJeeja KP #include <sound/pcm_params.h> 25a40e693cSJeeja KP #include <sound/soc.h> 26a40e693cSJeeja KP #include "skl.h" 27b663a8c5SJeeja KP #include "skl-topology.h" 28721c3e36SDharageswari.R #include "skl-sst-dsp.h" 29721c3e36SDharageswari.R #include "skl-sst-ipc.h" 30a40e693cSJeeja KP 31a40e693cSJeeja KP #define HDA_MONO 1 32a40e693cSJeeja KP #define HDA_STEREO 2 338f35bf3fSJeeja KP #define HDA_QUAD 4 34a40e693cSJeeja KP 35a40e693cSJeeja KP static struct snd_pcm_hardware azx_pcm_hw = { 36a40e693cSJeeja KP .info = (SNDRV_PCM_INFO_MMAP | 37a40e693cSJeeja KP SNDRV_PCM_INFO_INTERLEAVED | 38a40e693cSJeeja KP SNDRV_PCM_INFO_BLOCK_TRANSFER | 39a40e693cSJeeja KP SNDRV_PCM_INFO_MMAP_VALID | 40a40e693cSJeeja KP SNDRV_PCM_INFO_PAUSE | 413637976bSJeeja KP SNDRV_PCM_INFO_RESUME | 42a40e693cSJeeja KP SNDRV_PCM_INFO_SYNC_START | 43a40e693cSJeeja KP SNDRV_PCM_INFO_HAS_WALL_CLOCK | /* legacy */ 44a40e693cSJeeja KP SNDRV_PCM_INFO_HAS_LINK_ATIME | 45a40e693cSJeeja KP SNDRV_PCM_INFO_NO_PERIOD_WAKEUP), 4606b23d93SJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE | 4706b23d93SJeeja KP SNDRV_PCM_FMTBIT_S32_LE | 4806b23d93SJeeja KP SNDRV_PCM_FMTBIT_S24_LE, 4906b23d93SJeeja KP .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | 5006b23d93SJeeja KP SNDRV_PCM_RATE_8000, 5106b23d93SJeeja KP .rate_min = 8000, 52a40e693cSJeeja KP .rate_max = 48000, 538f35bf3fSJeeja KP .channels_min = 1, 547e12dc87SSubhransu S. Prusty .channels_max = 8, 55a40e693cSJeeja KP .buffer_bytes_max = AZX_MAX_BUF_SIZE, 56a40e693cSJeeja KP .period_bytes_min = 128, 57a40e693cSJeeja KP .period_bytes_max = AZX_MAX_BUF_SIZE / 2, 58a40e693cSJeeja KP .periods_min = 2, 59a40e693cSJeeja KP .periods_max = AZX_MAX_FRAG, 60a40e693cSJeeja KP .fifo_size = 0, 61a40e693cSJeeja KP }; 62a40e693cSJeeja KP 63a40e693cSJeeja KP static inline 64a40e693cSJeeja KP struct hdac_ext_stream *get_hdac_ext_stream(struct snd_pcm_substream *substream) 65a40e693cSJeeja KP { 66a40e693cSJeeja KP return substream->runtime->private_data; 67a40e693cSJeeja KP } 68a40e693cSJeeja KP 69a40e693cSJeeja KP static struct hdac_ext_bus *get_bus_ctx(struct snd_pcm_substream *substream) 70a40e693cSJeeja KP { 71a40e693cSJeeja KP struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); 72a40e693cSJeeja KP struct hdac_stream *hstream = hdac_stream(stream); 73a40e693cSJeeja KP struct hdac_bus *bus = hstream->bus; 74a40e693cSJeeja KP 75a40e693cSJeeja KP return hbus_to_ebus(bus); 76a40e693cSJeeja KP } 77a40e693cSJeeja KP 78a40e693cSJeeja KP static int skl_substream_alloc_pages(struct hdac_ext_bus *ebus, 79a40e693cSJeeja KP struct snd_pcm_substream *substream, 80a40e693cSJeeja KP size_t size) 81a40e693cSJeeja KP { 82a40e693cSJeeja KP struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); 83a40e693cSJeeja KP 84a40e693cSJeeja KP hdac_stream(stream)->bufsize = 0; 85a40e693cSJeeja KP hdac_stream(stream)->period_bytes = 0; 86a40e693cSJeeja KP hdac_stream(stream)->format_val = 0; 87a40e693cSJeeja KP 88a40e693cSJeeja KP return snd_pcm_lib_malloc_pages(substream, size); 89a40e693cSJeeja KP } 90a40e693cSJeeja KP 91a40e693cSJeeja KP static int skl_substream_free_pages(struct hdac_bus *bus, 92a40e693cSJeeja KP struct snd_pcm_substream *substream) 93a40e693cSJeeja KP { 94a40e693cSJeeja KP return snd_pcm_lib_free_pages(substream); 95a40e693cSJeeja KP } 96a40e693cSJeeja KP 97a40e693cSJeeja KP static void skl_set_pcm_constrains(struct hdac_ext_bus *ebus, 98a40e693cSJeeja KP struct snd_pcm_runtime *runtime) 99a40e693cSJeeja KP { 100a40e693cSJeeja KP snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); 101a40e693cSJeeja KP 102a40e693cSJeeja KP /* avoid wrap-around with wall-clock */ 103a40e693cSJeeja KP snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME, 104a40e693cSJeeja KP 20, 178000000); 105a40e693cSJeeja KP } 106a40e693cSJeeja KP 10705057001SJeeja KP static enum hdac_ext_stream_type skl_get_host_stream_type(struct hdac_ext_bus *ebus) 10805057001SJeeja KP { 10905057001SJeeja KP if (ebus->ppcap) 11005057001SJeeja KP return HDAC_EXT_STREAM_TYPE_HOST; 11105057001SJeeja KP else 11205057001SJeeja KP return HDAC_EXT_STREAM_TYPE_COUPLED; 11305057001SJeeja KP } 11405057001SJeeja KP 1154557c305SJeeja KP /* 1164557c305SJeeja KP * check if the stream opened is marked as ignore_suspend by machine, if so 1174557c305SJeeja KP * then enable suspend_active refcount 1184557c305SJeeja KP * 1194557c305SJeeja KP * The count supend_active does not need lock as it is used in open/close 1204557c305SJeeja KP * and suspend context 1214557c305SJeeja KP */ 1224557c305SJeeja KP static void skl_set_suspend_active(struct snd_pcm_substream *substream, 1234557c305SJeeja KP struct snd_soc_dai *dai, bool enable) 1244557c305SJeeja KP { 1254557c305SJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); 1264557c305SJeeja KP struct snd_soc_dapm_widget *w; 1274557c305SJeeja KP struct skl *skl = ebus_to_skl(ebus); 1284557c305SJeeja KP 1294557c305SJeeja KP if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 1304557c305SJeeja KP w = dai->playback_widget; 1314557c305SJeeja KP else 1324557c305SJeeja KP w = dai->capture_widget; 1334557c305SJeeja KP 1344557c305SJeeja KP if (w->ignore_suspend && enable) 1354557c305SJeeja KP skl->supend_active++; 1364557c305SJeeja KP else if (w->ignore_suspend && !enable) 1374557c305SJeeja KP skl->supend_active--; 1384557c305SJeeja KP } 1394557c305SJeeja KP 140a40e693cSJeeja KP static int skl_pcm_open(struct snd_pcm_substream *substream, 141a40e693cSJeeja KP struct snd_soc_dai *dai) 142a40e693cSJeeja KP { 143a40e693cSJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); 144a40e693cSJeeja KP struct hdac_ext_stream *stream; 145a40e693cSJeeja KP struct snd_pcm_runtime *runtime = substream->runtime; 146a40e693cSJeeja KP struct skl_dma_params *dma_params; 147a40e693cSJeeja KP 148a40e693cSJeeja KP dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); 149a40e693cSJeeja KP 150a40e693cSJeeja KP stream = snd_hdac_ext_stream_assign(ebus, substream, 15105057001SJeeja KP skl_get_host_stream_type(ebus)); 152a40e693cSJeeja KP if (stream == NULL) 153a40e693cSJeeja KP return -EBUSY; 154a40e693cSJeeja KP 155a40e693cSJeeja KP skl_set_pcm_constrains(ebus, runtime); 156a40e693cSJeeja KP 157a40e693cSJeeja KP /* 158a40e693cSJeeja KP * disable WALLCLOCK timestamps for capture streams 159a40e693cSJeeja KP * until we figure out how to handle digital inputs 160a40e693cSJeeja KP */ 161a40e693cSJeeja KP if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 162a40e693cSJeeja KP runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_WALL_CLOCK; /* legacy */ 163a40e693cSJeeja KP runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_LINK_ATIME; 164a40e693cSJeeja KP } 165a40e693cSJeeja KP 166a40e693cSJeeja KP runtime->private_data = stream; 167a40e693cSJeeja KP 168a40e693cSJeeja KP dma_params = kzalloc(sizeof(*dma_params), GFP_KERNEL); 169a40e693cSJeeja KP if (!dma_params) 170a40e693cSJeeja KP return -ENOMEM; 171a40e693cSJeeja KP 172a40e693cSJeeja KP dma_params->stream_tag = hdac_stream(stream)->stream_tag; 173a40e693cSJeeja KP snd_soc_dai_set_dma_data(dai, substream, dma_params); 174a40e693cSJeeja KP 175a40e693cSJeeja KP dev_dbg(dai->dev, "stream tag set in dma params=%d\n", 176a40e693cSJeeja KP dma_params->stream_tag); 1774557c305SJeeja KP skl_set_suspend_active(substream, dai, true); 178a40e693cSJeeja KP snd_pcm_set_sync(substream); 179a40e693cSJeeja KP 180a40e693cSJeeja KP return 0; 181a40e693cSJeeja KP } 182a40e693cSJeeja KP 183a40e693cSJeeja KP static int skl_get_format(struct snd_pcm_substream *substream, 184a40e693cSJeeja KP struct snd_soc_dai *dai) 185a40e693cSJeeja KP { 186a40e693cSJeeja KP struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 187a40e693cSJeeja KP struct skl_dma_params *dma_params; 18805057001SJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); 189a40e693cSJeeja KP int format_val = 0; 19005057001SJeeja KP 19105057001SJeeja KP if (ebus->ppcap) { 19205057001SJeeja KP struct snd_pcm_runtime *runtime = substream->runtime; 19305057001SJeeja KP 19405057001SJeeja KP format_val = snd_hdac_calc_stream_format(runtime->rate, 19505057001SJeeja KP runtime->channels, 19605057001SJeeja KP runtime->format, 19705057001SJeeja KP 32, 0); 19805057001SJeeja KP } else { 199a40e693cSJeeja KP struct snd_soc_dai *codec_dai = rtd->codec_dai; 200a40e693cSJeeja KP 201a40e693cSJeeja KP dma_params = snd_soc_dai_get_dma_data(codec_dai, substream); 202a40e693cSJeeja KP if (dma_params) 203a40e693cSJeeja KP format_val = dma_params->format; 20405057001SJeeja KP } 205a40e693cSJeeja KP 206a40e693cSJeeja KP return format_val; 207a40e693cSJeeja KP } 208a40e693cSJeeja KP 209c115fa5eSDharageswari.R static int skl_be_prepare(struct snd_pcm_substream *substream, 210c115fa5eSDharageswari.R struct snd_soc_dai *dai) 211c115fa5eSDharageswari.R { 212c115fa5eSDharageswari.R struct skl *skl = get_skl_ctx(dai->dev); 213c115fa5eSDharageswari.R struct skl_sst *ctx = skl->skl_sst; 214c115fa5eSDharageswari.R struct skl_module_cfg *mconfig; 215c115fa5eSDharageswari.R 2161a13b1faSDharageswari.R if (dai->playback_widget->power || dai->capture_widget->power) 217c115fa5eSDharageswari.R return 0; 218c115fa5eSDharageswari.R 219c115fa5eSDharageswari.R mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream); 220c115fa5eSDharageswari.R if (mconfig == NULL) 221c115fa5eSDharageswari.R return -EINVAL; 222c115fa5eSDharageswari.R 223c115fa5eSDharageswari.R return skl_dsp_set_dma_control(ctx, mconfig); 224c115fa5eSDharageswari.R } 225c115fa5eSDharageswari.R 226a40e693cSJeeja KP static int skl_pcm_prepare(struct snd_pcm_substream *substream, 227a40e693cSJeeja KP struct snd_soc_dai *dai) 228a40e693cSJeeja KP { 229a40e693cSJeeja KP struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); 2302004432fSJeeja KP struct skl *skl = get_skl_ctx(dai->dev); 231a40e693cSJeeja KP unsigned int format_val; 232a40e693cSJeeja KP int err; 2332004432fSJeeja KP struct skl_module_cfg *mconfig; 234a40e693cSJeeja KP 235a40e693cSJeeja KP dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); 236a40e693cSJeeja KP 2372004432fSJeeja KP mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); 2382004432fSJeeja KP 239a40e693cSJeeja KP format_val = skl_get_format(substream, dai); 240a40e693cSJeeja KP dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d\n", 241a40e693cSJeeja KP hdac_stream(stream)->stream_tag, format_val); 242a40e693cSJeeja KP snd_hdac_stream_reset(hdac_stream(stream)); 243a40e693cSJeeja KP 2442004432fSJeeja KP /* In case of XRUN recovery, reset the FW pipe to clean state */ 2452004432fSJeeja KP if (mconfig && (substream->runtime->status->state == 2462004432fSJeeja KP SNDRV_PCM_STATE_XRUN)) 2472004432fSJeeja KP skl_reset_pipe(skl->skl_sst, mconfig->pipe); 2482004432fSJeeja KP 249a40e693cSJeeja KP err = snd_hdac_stream_set_params(hdac_stream(stream), format_val); 250a40e693cSJeeja KP if (err < 0) 251a40e693cSJeeja KP return err; 252a40e693cSJeeja KP 253a40e693cSJeeja KP err = snd_hdac_stream_setup(hdac_stream(stream)); 254a40e693cSJeeja KP if (err < 0) 255a40e693cSJeeja KP return err; 256a40e693cSJeeja KP 257a40e693cSJeeja KP hdac_stream(stream)->prepared = 1; 258a40e693cSJeeja KP 259a40e693cSJeeja KP return err; 260a40e693cSJeeja KP } 261a40e693cSJeeja KP 262a40e693cSJeeja KP static int skl_pcm_hw_params(struct snd_pcm_substream *substream, 263a40e693cSJeeja KP struct snd_pcm_hw_params *params, 264a40e693cSJeeja KP struct snd_soc_dai *dai) 265a40e693cSJeeja KP { 266a40e693cSJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); 26705057001SJeeja KP struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); 268a40e693cSJeeja KP struct snd_pcm_runtime *runtime = substream->runtime; 269b663a8c5SJeeja KP struct skl_pipe_params p_params = {0}; 270b663a8c5SJeeja KP struct skl_module_cfg *m_cfg; 27105057001SJeeja KP int ret, dma_id; 272a40e693cSJeeja KP 273a40e693cSJeeja KP dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); 274a40e693cSJeeja KP ret = skl_substream_alloc_pages(ebus, substream, 275a40e693cSJeeja KP params_buffer_bytes(params)); 276a40e693cSJeeja KP if (ret < 0) 277a40e693cSJeeja KP return ret; 278a40e693cSJeeja KP 279a40e693cSJeeja KP dev_dbg(dai->dev, "format_val, rate=%d, ch=%d, format=%d\n", 280a40e693cSJeeja KP runtime->rate, runtime->channels, runtime->format); 281a40e693cSJeeja KP 28205057001SJeeja KP dma_id = hdac_stream(stream)->stream_tag - 1; 28305057001SJeeja KP dev_dbg(dai->dev, "dma_id=%d\n", dma_id); 28405057001SJeeja KP 285b663a8c5SJeeja KP p_params.s_fmt = snd_pcm_format_width(params_format(params)); 286b663a8c5SJeeja KP p_params.ch = params_channels(params); 287b663a8c5SJeeja KP p_params.s_freq = params_rate(params); 288b663a8c5SJeeja KP p_params.host_dma_id = dma_id; 289b663a8c5SJeeja KP p_params.stream = substream->stream; 290b663a8c5SJeeja KP 291b663a8c5SJeeja KP m_cfg = skl_tplg_fe_get_cpr_module(dai, p_params.stream); 292b663a8c5SJeeja KP if (m_cfg) 293b663a8c5SJeeja KP skl_tplg_update_pipe_params(dai->dev, m_cfg, &p_params); 294b663a8c5SJeeja KP 295a40e693cSJeeja KP return 0; 296a40e693cSJeeja KP } 297a40e693cSJeeja KP 298a40e693cSJeeja KP static void skl_pcm_close(struct snd_pcm_substream *substream, 299a40e693cSJeeja KP struct snd_soc_dai *dai) 300a40e693cSJeeja KP { 301a40e693cSJeeja KP struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); 30205057001SJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); 303a40e693cSJeeja KP struct skl_dma_params *dma_params = NULL; 304721c3e36SDharageswari.R struct skl *skl = ebus_to_skl(ebus); 305a40e693cSJeeja KP 306a40e693cSJeeja KP dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); 30705057001SJeeja KP 30805057001SJeeja KP snd_hdac_ext_stream_release(stream, skl_get_host_stream_type(ebus)); 309a40e693cSJeeja KP 310a40e693cSJeeja KP dma_params = snd_soc_dai_get_dma_data(dai, substream); 311a40e693cSJeeja KP /* 312a40e693cSJeeja KP * now we should set this to NULL as we are freeing by the 313a40e693cSJeeja KP * dma_params 314a40e693cSJeeja KP */ 315a40e693cSJeeja KP snd_soc_dai_set_dma_data(dai, substream, NULL); 3164557c305SJeeja KP skl_set_suspend_active(substream, dai, false); 317a40e693cSJeeja KP 318721c3e36SDharageswari.R /* 319721c3e36SDharageswari.R * check if close is for "Reference Pin" and set back the 320721c3e36SDharageswari.R * CGCTL.MISCBDCGE if disabled by driver 321721c3e36SDharageswari.R */ 322721c3e36SDharageswari.R if (!strncmp(dai->name, "Reference Pin", 13) && 323721c3e36SDharageswari.R skl->skl_sst->miscbdcg_disabled) { 324721c3e36SDharageswari.R skl->skl_sst->enable_miscbdcge(dai->dev, true); 325721c3e36SDharageswari.R skl->skl_sst->miscbdcg_disabled = false; 326721c3e36SDharageswari.R } 327721c3e36SDharageswari.R 328a40e693cSJeeja KP kfree(dma_params); 329a40e693cSJeeja KP } 330a40e693cSJeeja KP 331a40e693cSJeeja KP static int skl_pcm_hw_free(struct snd_pcm_substream *substream, 332a40e693cSJeeja KP struct snd_soc_dai *dai) 333a40e693cSJeeja KP { 334a40e693cSJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); 335a40e693cSJeeja KP struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); 336a40e693cSJeeja KP 337a40e693cSJeeja KP dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); 338a40e693cSJeeja KP 339a40e693cSJeeja KP snd_hdac_stream_cleanup(hdac_stream(stream)); 340a40e693cSJeeja KP hdac_stream(stream)->prepared = 0; 341a40e693cSJeeja KP 342a40e693cSJeeja KP return skl_substream_free_pages(ebus_to_hbus(ebus), substream); 343a40e693cSJeeja KP } 344a40e693cSJeeja KP 345b663a8c5SJeeja KP static int skl_be_hw_params(struct snd_pcm_substream *substream, 346b663a8c5SJeeja KP struct snd_pcm_hw_params *params, 347b663a8c5SJeeja KP struct snd_soc_dai *dai) 348b663a8c5SJeeja KP { 349b663a8c5SJeeja KP struct skl_pipe_params p_params = {0}; 350b663a8c5SJeeja KP 351b663a8c5SJeeja KP p_params.s_fmt = snd_pcm_format_width(params_format(params)); 352b663a8c5SJeeja KP p_params.ch = params_channels(params); 353b663a8c5SJeeja KP p_params.s_freq = params_rate(params); 354b663a8c5SJeeja KP p_params.stream = substream->stream; 355b663a8c5SJeeja KP 3564bd073f9SJeeja KP return skl_tplg_be_update_params(dai, &p_params); 357b663a8c5SJeeja KP } 358b663a8c5SJeeja KP 359d1730c3dSJeeja KP static int skl_decoupled_trigger(struct snd_pcm_substream *substream, 360d1730c3dSJeeja KP int cmd) 361d1730c3dSJeeja KP { 362d1730c3dSJeeja KP struct hdac_ext_bus *ebus = get_bus_ctx(substream); 363d1730c3dSJeeja KP struct hdac_bus *bus = ebus_to_hbus(ebus); 364d1730c3dSJeeja KP struct hdac_ext_stream *stream; 365d1730c3dSJeeja KP int start; 366d1730c3dSJeeja KP unsigned long cookie; 367d1730c3dSJeeja KP struct hdac_stream *hstr; 368d1730c3dSJeeja KP 369d1730c3dSJeeja KP stream = get_hdac_ext_stream(substream); 370d1730c3dSJeeja KP hstr = hdac_stream(stream); 371d1730c3dSJeeja KP 372d1730c3dSJeeja KP if (!hstr->prepared) 373d1730c3dSJeeja KP return -EPIPE; 374d1730c3dSJeeja KP 375d1730c3dSJeeja KP switch (cmd) { 376d1730c3dSJeeja KP case SNDRV_PCM_TRIGGER_START: 377d1730c3dSJeeja KP case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 378d1730c3dSJeeja KP case SNDRV_PCM_TRIGGER_RESUME: 379d1730c3dSJeeja KP start = 1; 380d1730c3dSJeeja KP break; 381d1730c3dSJeeja KP 382d1730c3dSJeeja KP case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 383d1730c3dSJeeja KP case SNDRV_PCM_TRIGGER_SUSPEND: 384d1730c3dSJeeja KP case SNDRV_PCM_TRIGGER_STOP: 385d1730c3dSJeeja KP start = 0; 386d1730c3dSJeeja KP break; 387d1730c3dSJeeja KP 388d1730c3dSJeeja KP default: 389d1730c3dSJeeja KP return -EINVAL; 390d1730c3dSJeeja KP } 391d1730c3dSJeeja KP 392d1730c3dSJeeja KP spin_lock_irqsave(&bus->reg_lock, cookie); 393d1730c3dSJeeja KP 394d1730c3dSJeeja KP if (start) { 395d1730c3dSJeeja KP snd_hdac_stream_start(hdac_stream(stream), true); 396d1730c3dSJeeja KP snd_hdac_stream_timecounter_init(hstr, 0); 397d1730c3dSJeeja KP } else { 398d1730c3dSJeeja KP snd_hdac_stream_stop(hdac_stream(stream)); 399d1730c3dSJeeja KP } 400d1730c3dSJeeja KP 401d1730c3dSJeeja KP spin_unlock_irqrestore(&bus->reg_lock, cookie); 402d1730c3dSJeeja KP 403d1730c3dSJeeja KP return 0; 404d1730c3dSJeeja KP } 405d1730c3dSJeeja KP 406b663a8c5SJeeja KP static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, 407b663a8c5SJeeja KP struct snd_soc_dai *dai) 408b663a8c5SJeeja KP { 409b663a8c5SJeeja KP struct skl *skl = get_skl_ctx(dai->dev); 410b663a8c5SJeeja KP struct skl_sst *ctx = skl->skl_sst; 411b663a8c5SJeeja KP struct skl_module_cfg *mconfig; 4127e3a17d3SJeeja KP struct hdac_ext_bus *ebus = get_bus_ctx(substream); 4137e3a17d3SJeeja KP struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); 4149a655db0SJeeja KP struct snd_soc_dapm_widget *w; 415d1730c3dSJeeja KP int ret; 416b663a8c5SJeeja KP 417b663a8c5SJeeja KP mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); 418b663a8c5SJeeja KP if (!mconfig) 419b663a8c5SJeeja KP return -EIO; 420b663a8c5SJeeja KP 4219a655db0SJeeja KP if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 4229a655db0SJeeja KP w = dai->playback_widget; 4239a655db0SJeeja KP else 4249a655db0SJeeja KP w = dai->capture_widget; 4259a655db0SJeeja KP 426b663a8c5SJeeja KP switch (cmd) { 4277e3a17d3SJeeja KP case SNDRV_PCM_TRIGGER_RESUME: 4289a655db0SJeeja KP if (!w->ignore_suspend) { 4297e3a17d3SJeeja KP skl_pcm_prepare(substream, dai); 430748a1d5aSJeeja KP /* 4319a655db0SJeeja KP * enable DMA Resume enable bit for the stream, set the 4329a655db0SJeeja KP * dpib & lpib position to resume before starting the 4339a655db0SJeeja KP * DMA 434748a1d5aSJeeja KP */ 435748a1d5aSJeeja KP snd_hdac_ext_stream_drsm_enable(ebus, true, 436748a1d5aSJeeja KP hdac_stream(stream)->index); 4379a655db0SJeeja KP snd_hdac_ext_stream_set_dpibr(ebus, stream, 4389a655db0SJeeja KP stream->dpib); 439748a1d5aSJeeja KP snd_hdac_ext_stream_set_lpib(stream, stream->lpib); 4409a655db0SJeeja KP } 441748a1d5aSJeeja KP 442d1730c3dSJeeja KP case SNDRV_PCM_TRIGGER_START: 443b663a8c5SJeeja KP case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 444d1730c3dSJeeja KP /* 445d1730c3dSJeeja KP * Start HOST DMA and Start FE Pipe.This is to make sure that 446d1730c3dSJeeja KP * there are no underrun/overrun in the case when the FE 447d1730c3dSJeeja KP * pipeline is started but there is a delay in starting the 448d1730c3dSJeeja KP * DMA channel on the host. 449d1730c3dSJeeja KP */ 4507e3a17d3SJeeja KP snd_hdac_ext_stream_decouple(ebus, stream, true); 451d1730c3dSJeeja KP ret = skl_decoupled_trigger(substream, cmd); 452d1730c3dSJeeja KP if (ret < 0) 453d1730c3dSJeeja KP return ret; 454b663a8c5SJeeja KP return skl_run_pipe(ctx, mconfig->pipe); 455d1730c3dSJeeja KP break; 456b663a8c5SJeeja KP 457b663a8c5SJeeja KP case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 458b663a8c5SJeeja KP case SNDRV_PCM_TRIGGER_SUSPEND: 459d1730c3dSJeeja KP case SNDRV_PCM_TRIGGER_STOP: 460d1730c3dSJeeja KP /* 461d1730c3dSJeeja KP * Stop FE Pipe first and stop DMA. This is to make sure that 462d1730c3dSJeeja KP * there are no underrun/overrun in the case if there is a delay 463d1730c3dSJeeja KP * between the two operations. 464d1730c3dSJeeja KP */ 465d1730c3dSJeeja KP ret = skl_stop_pipe(ctx, mconfig->pipe); 466d1730c3dSJeeja KP if (ret < 0) 467d1730c3dSJeeja KP return ret; 468d1730c3dSJeeja KP 469d1730c3dSJeeja KP ret = skl_decoupled_trigger(substream, cmd); 4709a655db0SJeeja KP if ((cmd == SNDRV_PCM_TRIGGER_SUSPEND) && !w->ignore_suspend) { 471748a1d5aSJeeja KP /* save the dpib and lpib positions */ 472748a1d5aSJeeja KP stream->dpib = readl(ebus->bus.remap_addr + 473748a1d5aSJeeja KP AZX_REG_VS_SDXDPIB_XBASE + 474748a1d5aSJeeja KP (AZX_REG_VS_SDXDPIB_XINTERVAL * 475748a1d5aSJeeja KP hdac_stream(stream)->index)); 476748a1d5aSJeeja KP 477748a1d5aSJeeja KP stream->lpib = snd_hdac_stream_get_pos_lpib( 478748a1d5aSJeeja KP hdac_stream(stream)); 4797e3a17d3SJeeja KP snd_hdac_ext_stream_decouple(ebus, stream, false); 480748a1d5aSJeeja KP } 481d1730c3dSJeeja KP break; 482b663a8c5SJeeja KP 483b663a8c5SJeeja KP default: 484d1730c3dSJeeja KP return -EINVAL; 485b663a8c5SJeeja KP } 486d1730c3dSJeeja KP 487d1730c3dSJeeja KP return 0; 488b663a8c5SJeeja KP } 489b663a8c5SJeeja KP 49005057001SJeeja KP static int skl_link_hw_params(struct snd_pcm_substream *substream, 49105057001SJeeja KP struct snd_pcm_hw_params *params, 49205057001SJeeja KP struct snd_soc_dai *dai) 49305057001SJeeja KP { 49405057001SJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); 49505057001SJeeja KP struct hdac_ext_stream *link_dev; 49605057001SJeeja KP struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 497aceb5d20SSubhransu S. Prusty struct hdac_ext_dma_params *dma_params; 49805057001SJeeja KP struct snd_soc_dai *codec_dai = rtd->codec_dai; 499b663a8c5SJeeja KP struct skl_pipe_params p_params = {0}; 50005057001SJeeja KP 50105057001SJeeja KP link_dev = snd_hdac_ext_stream_assign(ebus, substream, 50205057001SJeeja KP HDAC_EXT_STREAM_TYPE_LINK); 50305057001SJeeja KP if (!link_dev) 50405057001SJeeja KP return -EBUSY; 50505057001SJeeja KP 50605057001SJeeja KP snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev); 50705057001SJeeja KP 50805057001SJeeja KP /* set the stream tag in the codec dai dma params */ 509aceb5d20SSubhransu S. Prusty dma_params = snd_soc_dai_get_dma_data(codec_dai, substream); 51005057001SJeeja KP if (dma_params) 51105057001SJeeja KP dma_params->stream_tag = hdac_stream(link_dev)->stream_tag; 512b663a8c5SJeeja KP 513b663a8c5SJeeja KP p_params.s_fmt = snd_pcm_format_width(params_format(params)); 514b663a8c5SJeeja KP p_params.ch = params_channels(params); 515b663a8c5SJeeja KP p_params.s_freq = params_rate(params); 516b663a8c5SJeeja KP p_params.stream = substream->stream; 517b663a8c5SJeeja KP p_params.link_dma_id = hdac_stream(link_dev)->stream_tag - 1; 518b663a8c5SJeeja KP 5194bd073f9SJeeja KP return skl_tplg_be_update_params(dai, &p_params); 52005057001SJeeja KP } 52105057001SJeeja KP 52205057001SJeeja KP static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, 52305057001SJeeja KP struct snd_soc_dai *dai) 52405057001SJeeja KP { 52505057001SJeeja KP struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 52605057001SJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); 52705057001SJeeja KP struct hdac_ext_stream *link_dev = 52805057001SJeeja KP snd_soc_dai_get_dma_data(dai, substream); 52905057001SJeeja KP unsigned int format_val = 0; 53005057001SJeeja KP struct skl_dma_params *dma_params; 53105057001SJeeja KP struct snd_soc_dai *codec_dai = rtd->codec_dai; 53205057001SJeeja KP struct hdac_ext_link *link; 5332004432fSJeeja KP struct skl *skl = get_skl_ctx(dai->dev); 5342004432fSJeeja KP struct skl_module_cfg *mconfig = NULL; 53505057001SJeeja KP 53605057001SJeeja KP dma_params = (struct skl_dma_params *) 53705057001SJeeja KP snd_soc_dai_get_dma_data(codec_dai, substream); 53805057001SJeeja KP if (dma_params) 53905057001SJeeja KP format_val = dma_params->format; 54005057001SJeeja KP dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d codec_dai_name=%s\n", 54105057001SJeeja KP hdac_stream(link_dev)->stream_tag, format_val, codec_dai->name); 54205057001SJeeja KP 54305057001SJeeja KP link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name); 54405057001SJeeja KP if (!link) 54505057001SJeeja KP return -EINVAL; 54605057001SJeeja KP 547920982c9SJeeja KP snd_hdac_ext_link_stream_reset(link_dev); 548920982c9SJeeja KP 5492004432fSJeeja KP /* In case of XRUN recovery, reset the FW pipe to clean state */ 5502004432fSJeeja KP mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream); 5512004432fSJeeja KP if (mconfig && (substream->runtime->status->state == 5522004432fSJeeja KP SNDRV_PCM_STATE_XRUN)) 5532004432fSJeeja KP skl_reset_pipe(skl->skl_sst, mconfig->pipe); 5542004432fSJeeja KP 555920982c9SJeeja KP snd_hdac_ext_link_stream_setup(link_dev, format_val); 556920982c9SJeeja KP 55705057001SJeeja KP snd_hdac_ext_link_set_stream_id(link, hdac_stream(link_dev)->stream_tag); 55805057001SJeeja KP link_dev->link_prepared = 1; 55905057001SJeeja KP 56005057001SJeeja KP return 0; 56105057001SJeeja KP } 56205057001SJeeja KP 56305057001SJeeja KP static int skl_link_pcm_trigger(struct snd_pcm_substream *substream, 56405057001SJeeja KP int cmd, struct snd_soc_dai *dai) 56505057001SJeeja KP { 56605057001SJeeja KP struct hdac_ext_stream *link_dev = 56705057001SJeeja KP snd_soc_dai_get_dma_data(dai, substream); 568920982c9SJeeja KP struct hdac_ext_bus *ebus = get_bus_ctx(substream); 569920982c9SJeeja KP struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); 57005057001SJeeja KP 57105057001SJeeja KP dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd); 57205057001SJeeja KP switch (cmd) { 573920982c9SJeeja KP case SNDRV_PCM_TRIGGER_RESUME: 574920982c9SJeeja KP skl_link_pcm_prepare(substream, dai); 57505057001SJeeja KP case SNDRV_PCM_TRIGGER_START: 57605057001SJeeja KP case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 577920982c9SJeeja KP snd_hdac_ext_stream_decouple(ebus, stream, true); 57805057001SJeeja KP snd_hdac_ext_link_stream_start(link_dev); 57905057001SJeeja KP break; 58005057001SJeeja KP 58105057001SJeeja KP case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 58205057001SJeeja KP case SNDRV_PCM_TRIGGER_SUSPEND: 58305057001SJeeja KP case SNDRV_PCM_TRIGGER_STOP: 58405057001SJeeja KP snd_hdac_ext_link_stream_clear(link_dev); 585920982c9SJeeja KP if (cmd == SNDRV_PCM_TRIGGER_SUSPEND) 586920982c9SJeeja KP snd_hdac_ext_stream_decouple(ebus, stream, false); 58705057001SJeeja KP break; 58805057001SJeeja KP 58905057001SJeeja KP default: 59005057001SJeeja KP return -EINVAL; 59105057001SJeeja KP } 59205057001SJeeja KP return 0; 59305057001SJeeja KP } 59405057001SJeeja KP 59505057001SJeeja KP static int skl_link_hw_free(struct snd_pcm_substream *substream, 59605057001SJeeja KP struct snd_soc_dai *dai) 59705057001SJeeja KP { 59805057001SJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); 59905057001SJeeja KP struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 60005057001SJeeja KP struct hdac_ext_stream *link_dev = 60105057001SJeeja KP snd_soc_dai_get_dma_data(dai, substream); 60205057001SJeeja KP struct hdac_ext_link *link; 60305057001SJeeja KP 60405057001SJeeja KP dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); 60505057001SJeeja KP 60605057001SJeeja KP link_dev->link_prepared = 0; 60705057001SJeeja KP 60805057001SJeeja KP link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name); 60905057001SJeeja KP if (!link) 61005057001SJeeja KP return -EINVAL; 61105057001SJeeja KP 61205057001SJeeja KP snd_hdac_ext_link_clear_stream_id(link, hdac_stream(link_dev)->stream_tag); 61305057001SJeeja KP snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK); 61405057001SJeeja KP return 0; 61505057001SJeeja KP } 61605057001SJeeja KP 617a40e693cSJeeja KP static struct snd_soc_dai_ops skl_pcm_dai_ops = { 618a40e693cSJeeja KP .startup = skl_pcm_open, 619a40e693cSJeeja KP .shutdown = skl_pcm_close, 620a40e693cSJeeja KP .prepare = skl_pcm_prepare, 621a40e693cSJeeja KP .hw_params = skl_pcm_hw_params, 622a40e693cSJeeja KP .hw_free = skl_pcm_hw_free, 623b663a8c5SJeeja KP .trigger = skl_pcm_trigger, 624a40e693cSJeeja KP }; 625a40e693cSJeeja KP 62605057001SJeeja KP static struct snd_soc_dai_ops skl_dmic_dai_ops = { 627b663a8c5SJeeja KP .hw_params = skl_be_hw_params, 628b663a8c5SJeeja KP }; 629b663a8c5SJeeja KP 630b663a8c5SJeeja KP static struct snd_soc_dai_ops skl_be_ssp_dai_ops = { 631b663a8c5SJeeja KP .hw_params = skl_be_hw_params, 632c115fa5eSDharageswari.R .prepare = skl_be_prepare, 63305057001SJeeja KP }; 63405057001SJeeja KP 63505057001SJeeja KP static struct snd_soc_dai_ops skl_link_dai_ops = { 63605057001SJeeja KP .prepare = skl_link_pcm_prepare, 63705057001SJeeja KP .hw_params = skl_link_hw_params, 63805057001SJeeja KP .hw_free = skl_link_hw_free, 63905057001SJeeja KP .trigger = skl_link_pcm_trigger, 64005057001SJeeja KP }; 64105057001SJeeja KP 642a40e693cSJeeja KP static struct snd_soc_dai_driver skl_platform_dai[] = { 643a40e693cSJeeja KP { 644a40e693cSJeeja KP .name = "System Pin", 645a40e693cSJeeja KP .ops = &skl_pcm_dai_ops, 646a40e693cSJeeja KP .playback = { 647a40e693cSJeeja KP .stream_name = "System Playback", 648a40e693cSJeeja KP .channels_min = HDA_MONO, 649a40e693cSJeeja KP .channels_max = HDA_STEREO, 650a40e693cSJeeja KP .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_8000, 651a40e693cSJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 652a40e693cSJeeja KP }, 653a40e693cSJeeja KP .capture = { 654a40e693cSJeeja KP .stream_name = "System Capture", 655a40e693cSJeeja KP .channels_min = HDA_MONO, 656a40e693cSJeeja KP .channels_max = HDA_STEREO, 657a40e693cSJeeja KP .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, 658a40e693cSJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 659a40e693cSJeeja KP }, 660a40e693cSJeeja KP }, 661a40e693cSJeeja KP { 66205057001SJeeja KP .name = "Reference Pin", 66305057001SJeeja KP .ops = &skl_pcm_dai_ops, 66405057001SJeeja KP .capture = { 66505057001SJeeja KP .stream_name = "Reference Capture", 66605057001SJeeja KP .channels_min = HDA_MONO, 6678f35bf3fSJeeja KP .channels_max = HDA_QUAD, 66805057001SJeeja KP .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, 66905057001SJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 67005057001SJeeja KP }, 67105057001SJeeja KP }, 67205057001SJeeja KP { 673a40e693cSJeeja KP .name = "Deepbuffer Pin", 674a40e693cSJeeja KP .ops = &skl_pcm_dai_ops, 675a40e693cSJeeja KP .playback = { 676a40e693cSJeeja KP .stream_name = "Deepbuffer Playback", 677a40e693cSJeeja KP .channels_min = HDA_STEREO, 678a40e693cSJeeja KP .channels_max = HDA_STEREO, 679a40e693cSJeeja KP .rates = SNDRV_PCM_RATE_48000, 680a40e693cSJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 681a40e693cSJeeja KP }, 682a40e693cSJeeja KP }, 683a40e693cSJeeja KP { 684a40e693cSJeeja KP .name = "LowLatency Pin", 685a40e693cSJeeja KP .ops = &skl_pcm_dai_ops, 686a40e693cSJeeja KP .playback = { 687a40e693cSJeeja KP .stream_name = "Low Latency Playback", 688a40e693cSJeeja KP .channels_min = HDA_STEREO, 689a40e693cSJeeja KP .channels_max = HDA_STEREO, 690a40e693cSJeeja KP .rates = SNDRV_PCM_RATE_48000, 691a40e693cSJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 692a40e693cSJeeja KP }, 693a40e693cSJeeja KP }, 6948f35bf3fSJeeja KP { 6958f35bf3fSJeeja KP .name = "DMIC Pin", 6968f35bf3fSJeeja KP .ops = &skl_pcm_dai_ops, 6978f35bf3fSJeeja KP .capture = { 6988f35bf3fSJeeja KP .stream_name = "DMIC Capture", 6998f35bf3fSJeeja KP .channels_min = HDA_MONO, 7008f35bf3fSJeeja KP .channels_max = HDA_QUAD, 7018f35bf3fSJeeja KP .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, 7028f35bf3fSJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 7038f35bf3fSJeeja KP }, 7048f35bf3fSJeeja KP }, 7058cca87c0SSubhransu S. Prusty { 7068cca87c0SSubhransu S. Prusty .name = "HDMI1 Pin", 7078cca87c0SSubhransu S. Prusty .ops = &skl_pcm_dai_ops, 7088cca87c0SSubhransu S. Prusty .playback = { 7098cca87c0SSubhransu S. Prusty .stream_name = "HDMI1 Playback", 7108cca87c0SSubhransu S. Prusty .channels_min = HDA_STEREO, 7117e12dc87SSubhransu S. Prusty .channels_max = 8, 7128cca87c0SSubhransu S. Prusty .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | 7138cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | 7148cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | 7158cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_192000, 7168cca87c0SSubhransu S. Prusty .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | 7178cca87c0SSubhransu S. Prusty SNDRV_PCM_FMTBIT_S32_LE, 7188cca87c0SSubhransu S. Prusty }, 7198cca87c0SSubhransu S. Prusty }, 7208cca87c0SSubhransu S. Prusty { 7218cca87c0SSubhransu S. Prusty .name = "HDMI2 Pin", 7228cca87c0SSubhransu S. Prusty .ops = &skl_pcm_dai_ops, 7238cca87c0SSubhransu S. Prusty .playback = { 7248cca87c0SSubhransu S. Prusty .stream_name = "HDMI2 Playback", 7258cca87c0SSubhransu S. Prusty .channels_min = HDA_STEREO, 7267e12dc87SSubhransu S. Prusty .channels_max = 8, 7278cca87c0SSubhransu S. Prusty .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | 7288cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | 7298cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | 7308cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_192000, 7318cca87c0SSubhransu S. Prusty .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | 7328cca87c0SSubhransu S. Prusty SNDRV_PCM_FMTBIT_S32_LE, 7338cca87c0SSubhransu S. Prusty }, 7348cca87c0SSubhransu S. Prusty }, 7358cca87c0SSubhransu S. Prusty { 7368cca87c0SSubhransu S. Prusty .name = "HDMI3 Pin", 7378cca87c0SSubhransu S. Prusty .ops = &skl_pcm_dai_ops, 7388cca87c0SSubhransu S. Prusty .playback = { 7398cca87c0SSubhransu S. Prusty .stream_name = "HDMI3 Playback", 7408cca87c0SSubhransu S. Prusty .channels_min = HDA_STEREO, 7417e12dc87SSubhransu S. Prusty .channels_max = 8, 7428cca87c0SSubhransu S. Prusty .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | 7438cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | 7448cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | 7458cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_192000, 7468cca87c0SSubhransu S. Prusty .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | 7478cca87c0SSubhransu S. Prusty SNDRV_PCM_FMTBIT_S32_LE, 7488cca87c0SSubhransu S. Prusty }, 7498cca87c0SSubhransu S. Prusty }, 7508f35bf3fSJeeja KP 75105057001SJeeja KP /* BE CPU Dais */ 75205057001SJeeja KP { 753b663a8c5SJeeja KP .name = "SSP0 Pin", 754b663a8c5SJeeja KP .ops = &skl_be_ssp_dai_ops, 755b663a8c5SJeeja KP .playback = { 756b663a8c5SJeeja KP .stream_name = "ssp0 Tx", 757b663a8c5SJeeja KP .channels_min = HDA_STEREO, 758b663a8c5SJeeja KP .channels_max = HDA_STEREO, 759b663a8c5SJeeja KP .rates = SNDRV_PCM_RATE_48000, 760b663a8c5SJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE, 761b663a8c5SJeeja KP }, 762b663a8c5SJeeja KP .capture = { 763b663a8c5SJeeja KP .stream_name = "ssp0 Rx", 764b663a8c5SJeeja KP .channels_min = HDA_STEREO, 765b663a8c5SJeeja KP .channels_max = HDA_STEREO, 766b663a8c5SJeeja KP .rates = SNDRV_PCM_RATE_48000, 767b663a8c5SJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE, 768b663a8c5SJeeja KP }, 769b663a8c5SJeeja KP }, 770b663a8c5SJeeja KP { 771c80fd4daSJeeja KP .name = "SSP1 Pin", 772c80fd4daSJeeja KP .ops = &skl_be_ssp_dai_ops, 773c80fd4daSJeeja KP .playback = { 774c80fd4daSJeeja KP .stream_name = "ssp1 Tx", 775c80fd4daSJeeja KP .channels_min = HDA_STEREO, 776c80fd4daSJeeja KP .channels_max = HDA_STEREO, 777c80fd4daSJeeja KP .rates = SNDRV_PCM_RATE_48000, 778c80fd4daSJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE, 779c80fd4daSJeeja KP }, 780c80fd4daSJeeja KP .capture = { 781c80fd4daSJeeja KP .stream_name = "ssp1 Rx", 782c80fd4daSJeeja KP .channels_min = HDA_STEREO, 783c80fd4daSJeeja KP .channels_max = HDA_STEREO, 784c80fd4daSJeeja KP .rates = SNDRV_PCM_RATE_48000, 785c80fd4daSJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE, 786c80fd4daSJeeja KP }, 787c80fd4daSJeeja KP }, 788c80fd4daSJeeja KP { 789fcc494afSPardha Saradhi K .name = "SSP2 Pin", 790fcc494afSPardha Saradhi K .ops = &skl_be_ssp_dai_ops, 791fcc494afSPardha Saradhi K .playback = { 792fcc494afSPardha Saradhi K .stream_name = "ssp2 Tx", 793fcc494afSPardha Saradhi K .channels_min = HDA_STEREO, 794fcc494afSPardha Saradhi K .channels_max = HDA_STEREO, 795fcc494afSPardha Saradhi K .rates = SNDRV_PCM_RATE_48000, 796fcc494afSPardha Saradhi K .formats = SNDRV_PCM_FMTBIT_S16_LE, 797fcc494afSPardha Saradhi K }, 798fcc494afSPardha Saradhi K .capture = { 799fcc494afSPardha Saradhi K .stream_name = "ssp2 Rx", 800fcc494afSPardha Saradhi K .channels_min = HDA_STEREO, 801fcc494afSPardha Saradhi K .channels_max = HDA_STEREO, 802fcc494afSPardha Saradhi K .rates = SNDRV_PCM_RATE_48000, 803fcc494afSPardha Saradhi K .formats = SNDRV_PCM_FMTBIT_S16_LE, 804fcc494afSPardha Saradhi K }, 805fcc494afSPardha Saradhi K }, 806fcc494afSPardha Saradhi K { 807fcc494afSPardha Saradhi K .name = "SSP3 Pin", 808fcc494afSPardha Saradhi K .ops = &skl_be_ssp_dai_ops, 809fcc494afSPardha Saradhi K .playback = { 810fcc494afSPardha Saradhi K .stream_name = "ssp3 Tx", 811fcc494afSPardha Saradhi K .channels_min = HDA_STEREO, 812fcc494afSPardha Saradhi K .channels_max = HDA_STEREO, 813fcc494afSPardha Saradhi K .rates = SNDRV_PCM_RATE_48000, 814fcc494afSPardha Saradhi K .formats = SNDRV_PCM_FMTBIT_S16_LE, 815fcc494afSPardha Saradhi K }, 816fcc494afSPardha Saradhi K .capture = { 817fcc494afSPardha Saradhi K .stream_name = "ssp3 Rx", 818fcc494afSPardha Saradhi K .channels_min = HDA_STEREO, 819fcc494afSPardha Saradhi K .channels_max = HDA_STEREO, 820fcc494afSPardha Saradhi K .rates = SNDRV_PCM_RATE_48000, 821fcc494afSPardha Saradhi K .formats = SNDRV_PCM_FMTBIT_S16_LE, 822fcc494afSPardha Saradhi K }, 823fcc494afSPardha Saradhi K }, 824fcc494afSPardha Saradhi K { 825fcc494afSPardha Saradhi K .name = "SSP4 Pin", 826fcc494afSPardha Saradhi K .ops = &skl_be_ssp_dai_ops, 827fcc494afSPardha Saradhi K .playback = { 828fcc494afSPardha Saradhi K .stream_name = "ssp4 Tx", 829fcc494afSPardha Saradhi K .channels_min = HDA_STEREO, 830fcc494afSPardha Saradhi K .channels_max = HDA_STEREO, 831fcc494afSPardha Saradhi K .rates = SNDRV_PCM_RATE_48000, 832fcc494afSPardha Saradhi K .formats = SNDRV_PCM_FMTBIT_S16_LE, 833fcc494afSPardha Saradhi K }, 834fcc494afSPardha Saradhi K .capture = { 835fcc494afSPardha Saradhi K .stream_name = "ssp4 Rx", 836fcc494afSPardha Saradhi K .channels_min = HDA_STEREO, 837fcc494afSPardha Saradhi K .channels_max = HDA_STEREO, 838fcc494afSPardha Saradhi K .rates = SNDRV_PCM_RATE_48000, 839fcc494afSPardha Saradhi K .formats = SNDRV_PCM_FMTBIT_S16_LE, 840fcc494afSPardha Saradhi K }, 841fcc494afSPardha Saradhi K }, 842fcc494afSPardha Saradhi K { 843fcc494afSPardha Saradhi K .name = "SSP5 Pin", 844fcc494afSPardha Saradhi K .ops = &skl_be_ssp_dai_ops, 845fcc494afSPardha Saradhi K .playback = { 846fcc494afSPardha Saradhi K .stream_name = "ssp5 Tx", 847fcc494afSPardha Saradhi K .channels_min = HDA_STEREO, 848fcc494afSPardha Saradhi K .channels_max = HDA_STEREO, 849fcc494afSPardha Saradhi K .rates = SNDRV_PCM_RATE_48000, 850fcc494afSPardha Saradhi K .formats = SNDRV_PCM_FMTBIT_S16_LE, 851fcc494afSPardha Saradhi K }, 852fcc494afSPardha Saradhi K .capture = { 853fcc494afSPardha Saradhi K .stream_name = "ssp5 Rx", 854fcc494afSPardha Saradhi K .channels_min = HDA_STEREO, 855fcc494afSPardha Saradhi K .channels_max = HDA_STEREO, 856fcc494afSPardha Saradhi K .rates = SNDRV_PCM_RATE_48000, 857fcc494afSPardha Saradhi K .formats = SNDRV_PCM_FMTBIT_S16_LE, 858fcc494afSPardha Saradhi K }, 859fcc494afSPardha Saradhi K }, 860fcc494afSPardha Saradhi K { 8618cca87c0SSubhransu S. Prusty .name = "iDisp1 Pin", 86205057001SJeeja KP .ops = &skl_link_dai_ops, 86305057001SJeeja KP .playback = { 8648cca87c0SSubhransu S. Prusty .stream_name = "iDisp1 Tx", 86505057001SJeeja KP .channels_min = HDA_STEREO, 8667e12dc87SSubhransu S. Prusty .channels_max = 8, 86705057001SJeeja KP .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000, 8688cca87c0SSubhransu S. Prusty .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | 8698cca87c0SSubhransu S. Prusty SNDRV_PCM_FMTBIT_S24_LE, 8708cca87c0SSubhransu S. Prusty }, 8718cca87c0SSubhransu S. Prusty }, 8728cca87c0SSubhransu S. Prusty { 8738cca87c0SSubhransu S. Prusty .name = "iDisp2 Pin", 8748cca87c0SSubhransu S. Prusty .ops = &skl_link_dai_ops, 8758cca87c0SSubhransu S. Prusty .playback = { 8768cca87c0SSubhransu S. Prusty .stream_name = "iDisp2 Tx", 8778cca87c0SSubhransu S. Prusty .channels_min = HDA_STEREO, 8787e12dc87SSubhransu S. Prusty .channels_max = 8, 8798cca87c0SSubhransu S. Prusty .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000| 8808cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_48000, 8818cca87c0SSubhransu S. Prusty .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | 8828cca87c0SSubhransu S. Prusty SNDRV_PCM_FMTBIT_S24_LE, 8838cca87c0SSubhransu S. Prusty }, 8848cca87c0SSubhransu S. Prusty }, 8858cca87c0SSubhransu S. Prusty { 8868cca87c0SSubhransu S. Prusty .name = "iDisp3 Pin", 8878cca87c0SSubhransu S. Prusty .ops = &skl_link_dai_ops, 8888cca87c0SSubhransu S. Prusty .playback = { 8898cca87c0SSubhransu S. Prusty .stream_name = "iDisp3 Tx", 8908cca87c0SSubhransu S. Prusty .channels_min = HDA_STEREO, 8917e12dc87SSubhransu S. Prusty .channels_max = 8, 8928cca87c0SSubhransu S. Prusty .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000| 8938cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_48000, 8948cca87c0SSubhransu S. Prusty .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | 8958cca87c0SSubhransu S. Prusty SNDRV_PCM_FMTBIT_S24_LE, 89605057001SJeeja KP }, 89705057001SJeeja KP }, 89805057001SJeeja KP { 89905057001SJeeja KP .name = "DMIC01 Pin", 90005057001SJeeja KP .ops = &skl_dmic_dai_ops, 90105057001SJeeja KP .capture = { 90205057001SJeeja KP .stream_name = "DMIC01 Rx", 9038f35bf3fSJeeja KP .channels_min = HDA_MONO, 9048f35bf3fSJeeja KP .channels_max = HDA_QUAD, 90505057001SJeeja KP .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, 90605057001SJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 90705057001SJeeja KP }, 90805057001SJeeja KP }, 90905057001SJeeja KP { 91005057001SJeeja KP .name = "HD-Codec Pin", 91105057001SJeeja KP .ops = &skl_link_dai_ops, 91205057001SJeeja KP .playback = { 91305057001SJeeja KP .stream_name = "HD-Codec Tx", 91405057001SJeeja KP .channels_min = HDA_STEREO, 91505057001SJeeja KP .channels_max = HDA_STEREO, 91605057001SJeeja KP .rates = SNDRV_PCM_RATE_48000, 91705057001SJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE, 91805057001SJeeja KP }, 91905057001SJeeja KP .capture = { 92005057001SJeeja KP .stream_name = "HD-Codec Rx", 92105057001SJeeja KP .channels_min = HDA_STEREO, 92205057001SJeeja KP .channels_max = HDA_STEREO, 92305057001SJeeja KP .rates = SNDRV_PCM_RATE_48000, 92405057001SJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE, 92505057001SJeeja KP }, 92605057001SJeeja KP }, 927a40e693cSJeeja KP }; 928a40e693cSJeeja KP 929a40e693cSJeeja KP static int skl_platform_open(struct snd_pcm_substream *substream) 930a40e693cSJeeja KP { 931a40e693cSJeeja KP struct snd_pcm_runtime *runtime; 932a40e693cSJeeja KP struct snd_soc_pcm_runtime *rtd = substream->private_data; 933a40e693cSJeeja KP struct snd_soc_dai_link *dai_link = rtd->dai_link; 934a40e693cSJeeja KP 935a40e693cSJeeja KP dev_dbg(rtd->cpu_dai->dev, "In %s:%s\n", __func__, 936a40e693cSJeeja KP dai_link->cpu_dai_name); 937a40e693cSJeeja KP 938a40e693cSJeeja KP runtime = substream->runtime; 939a40e693cSJeeja KP snd_soc_set_runtime_hwparams(substream, &azx_pcm_hw); 940a40e693cSJeeja KP 941a40e693cSJeeja KP return 0; 942a40e693cSJeeja KP } 943a40e693cSJeeja KP 944b663a8c5SJeeja KP static int skl_coupled_trigger(struct snd_pcm_substream *substream, 945a40e693cSJeeja KP int cmd) 946a40e693cSJeeja KP { 947a40e693cSJeeja KP struct hdac_ext_bus *ebus = get_bus_ctx(substream); 948a40e693cSJeeja KP struct hdac_bus *bus = ebus_to_hbus(ebus); 949a40e693cSJeeja KP struct hdac_ext_stream *stream; 950a40e693cSJeeja KP struct snd_pcm_substream *s; 951a40e693cSJeeja KP bool start; 952a40e693cSJeeja KP int sbits = 0; 953a40e693cSJeeja KP unsigned long cookie; 954a40e693cSJeeja KP struct hdac_stream *hstr; 955a40e693cSJeeja KP 956a40e693cSJeeja KP stream = get_hdac_ext_stream(substream); 957a40e693cSJeeja KP hstr = hdac_stream(stream); 958a40e693cSJeeja KP 959a40e693cSJeeja KP dev_dbg(bus->dev, "In %s cmd=%d\n", __func__, cmd); 960a40e693cSJeeja KP 961a40e693cSJeeja KP if (!hstr->prepared) 962a40e693cSJeeja KP return -EPIPE; 963a40e693cSJeeja KP 964a40e693cSJeeja KP switch (cmd) { 965a40e693cSJeeja KP case SNDRV_PCM_TRIGGER_START: 966a40e693cSJeeja KP case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 967a40e693cSJeeja KP case SNDRV_PCM_TRIGGER_RESUME: 968a40e693cSJeeja KP start = true; 969a40e693cSJeeja KP break; 970a40e693cSJeeja KP 971a40e693cSJeeja KP case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 972a40e693cSJeeja KP case SNDRV_PCM_TRIGGER_SUSPEND: 973a40e693cSJeeja KP case SNDRV_PCM_TRIGGER_STOP: 974a40e693cSJeeja KP start = false; 975a40e693cSJeeja KP break; 976a40e693cSJeeja KP 977a40e693cSJeeja KP default: 978a40e693cSJeeja KP return -EINVAL; 979a40e693cSJeeja KP } 980a40e693cSJeeja KP 981a40e693cSJeeja KP snd_pcm_group_for_each_entry(s, substream) { 982a40e693cSJeeja KP if (s->pcm->card != substream->pcm->card) 983a40e693cSJeeja KP continue; 984a40e693cSJeeja KP stream = get_hdac_ext_stream(s); 985a40e693cSJeeja KP sbits |= 1 << hdac_stream(stream)->index; 986a40e693cSJeeja KP snd_pcm_trigger_done(s, substream); 987a40e693cSJeeja KP } 988a40e693cSJeeja KP 989a40e693cSJeeja KP spin_lock_irqsave(&bus->reg_lock, cookie); 990a40e693cSJeeja KP 991a40e693cSJeeja KP /* first, set SYNC bits of corresponding streams */ 992a40e693cSJeeja KP snd_hdac_stream_sync_trigger(hstr, true, sbits, AZX_REG_SSYNC); 993a40e693cSJeeja KP 994a40e693cSJeeja KP snd_pcm_group_for_each_entry(s, substream) { 995a40e693cSJeeja KP if (s->pcm->card != substream->pcm->card) 996a40e693cSJeeja KP continue; 997a40e693cSJeeja KP stream = get_hdac_ext_stream(s); 998a40e693cSJeeja KP if (start) 999a40e693cSJeeja KP snd_hdac_stream_start(hdac_stream(stream), true); 1000a40e693cSJeeja KP else 1001a40e693cSJeeja KP snd_hdac_stream_stop(hdac_stream(stream)); 1002a40e693cSJeeja KP } 1003a40e693cSJeeja KP spin_unlock_irqrestore(&bus->reg_lock, cookie); 1004a40e693cSJeeja KP 1005a40e693cSJeeja KP snd_hdac_stream_sync(hstr, start, sbits); 1006a40e693cSJeeja KP 1007a40e693cSJeeja KP spin_lock_irqsave(&bus->reg_lock, cookie); 1008a40e693cSJeeja KP 1009a40e693cSJeeja KP /* reset SYNC bits */ 1010a40e693cSJeeja KP snd_hdac_stream_sync_trigger(hstr, false, sbits, AZX_REG_SSYNC); 1011a40e693cSJeeja KP if (start) 1012a40e693cSJeeja KP snd_hdac_stream_timecounter_init(hstr, sbits); 1013a40e693cSJeeja KP spin_unlock_irqrestore(&bus->reg_lock, cookie); 1014a40e693cSJeeja KP 1015a40e693cSJeeja KP return 0; 1016a40e693cSJeeja KP } 1017a40e693cSJeeja KP 101805057001SJeeja KP static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream, 101905057001SJeeja KP int cmd) 102005057001SJeeja KP { 102105057001SJeeja KP struct hdac_ext_bus *ebus = get_bus_ctx(substream); 102205057001SJeeja KP 1023d1730c3dSJeeja KP if (!ebus->ppcap) 1024b663a8c5SJeeja KP return skl_coupled_trigger(substream, cmd); 1025d1730c3dSJeeja KP 1026d1730c3dSJeeja KP return 0; 102705057001SJeeja KP } 102805057001SJeeja KP 10297b96144dSJeeja KP static snd_pcm_uframes_t skl_platform_pcm_pointer 10307b96144dSJeeja KP (struct snd_pcm_substream *substream) 1031a40e693cSJeeja KP { 10327b96144dSJeeja KP struct hdac_ext_stream *hstream = get_hdac_ext_stream(substream); 1033a40e693cSJeeja KP unsigned int pos; 1034a40e693cSJeeja KP 1035a40e693cSJeeja KP /* use the position buffer as default */ 1036a40e693cSJeeja KP pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream)); 1037a40e693cSJeeja KP 1038a40e693cSJeeja KP if (pos >= hdac_stream(hstream)->bufsize) 1039a40e693cSJeeja KP pos = 0; 1040a40e693cSJeeja KP 10417b96144dSJeeja KP return bytes_to_frames(substream->runtime, pos); 1042a40e693cSJeeja KP } 1043a40e693cSJeeja KP 1044a40e693cSJeeja KP static u64 skl_adjust_codec_delay(struct snd_pcm_substream *substream, 1045a40e693cSJeeja KP u64 nsec) 1046a40e693cSJeeja KP { 1047a40e693cSJeeja KP struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 1048a40e693cSJeeja KP struct snd_soc_dai *codec_dai = rtd->codec_dai; 1049a40e693cSJeeja KP u64 codec_frames, codec_nsecs; 1050a40e693cSJeeja KP 1051a40e693cSJeeja KP if (!codec_dai->driver->ops->delay) 1052a40e693cSJeeja KP return nsec; 1053a40e693cSJeeja KP 1054a40e693cSJeeja KP codec_frames = codec_dai->driver->ops->delay(substream, codec_dai); 1055a40e693cSJeeja KP codec_nsecs = div_u64(codec_frames * 1000000000LL, 1056a40e693cSJeeja KP substream->runtime->rate); 1057a40e693cSJeeja KP 1058a40e693cSJeeja KP if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 1059a40e693cSJeeja KP return nsec + codec_nsecs; 1060a40e693cSJeeja KP 1061a40e693cSJeeja KP return (nsec > codec_nsecs) ? nsec - codec_nsecs : 0; 1062a40e693cSJeeja KP } 1063a40e693cSJeeja KP 1064a40e693cSJeeja KP static int skl_get_time_info(struct snd_pcm_substream *substream, 1065a40e693cSJeeja KP struct timespec *system_ts, struct timespec *audio_ts, 1066a40e693cSJeeja KP struct snd_pcm_audio_tstamp_config *audio_tstamp_config, 1067a40e693cSJeeja KP struct snd_pcm_audio_tstamp_report *audio_tstamp_report) 1068a40e693cSJeeja KP { 1069a40e693cSJeeja KP struct hdac_ext_stream *sstream = get_hdac_ext_stream(substream); 1070a40e693cSJeeja KP struct hdac_stream *hstr = hdac_stream(sstream); 1071a40e693cSJeeja KP u64 nsec; 1072a40e693cSJeeja KP 1073a40e693cSJeeja KP if ((substream->runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_ATIME) && 1074a40e693cSJeeja KP (audio_tstamp_config->type_requested == SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK)) { 1075a40e693cSJeeja KP 1076a40e693cSJeeja KP snd_pcm_gettime(substream->runtime, system_ts); 1077a40e693cSJeeja KP 1078a40e693cSJeeja KP nsec = timecounter_read(&hstr->tc); 1079a40e693cSJeeja KP nsec = div_u64(nsec, 3); /* can be optimized */ 1080a40e693cSJeeja KP if (audio_tstamp_config->report_delay) 1081a40e693cSJeeja KP nsec = skl_adjust_codec_delay(substream, nsec); 1082a40e693cSJeeja KP 1083a40e693cSJeeja KP *audio_ts = ns_to_timespec(nsec); 1084a40e693cSJeeja KP 1085a40e693cSJeeja KP audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK; 1086a40e693cSJeeja KP audio_tstamp_report->accuracy_report = 1; /* rest of struct is valid */ 1087a40e693cSJeeja KP audio_tstamp_report->accuracy = 42; /* 24MHzWallClk == 42ns resolution */ 1088a40e693cSJeeja KP 1089a40e693cSJeeja KP } else { 1090a40e693cSJeeja KP audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT; 1091a40e693cSJeeja KP } 1092a40e693cSJeeja KP 1093a40e693cSJeeja KP return 0; 1094a40e693cSJeeja KP } 1095a40e693cSJeeja KP 1096115c7254SJulia Lawall static const struct snd_pcm_ops skl_platform_ops = { 1097a40e693cSJeeja KP .open = skl_platform_open, 1098a40e693cSJeeja KP .ioctl = snd_pcm_lib_ioctl, 1099a40e693cSJeeja KP .trigger = skl_platform_pcm_trigger, 1100a40e693cSJeeja KP .pointer = skl_platform_pcm_pointer, 1101a40e693cSJeeja KP .get_time_info = skl_get_time_info, 1102a40e693cSJeeja KP .mmap = snd_pcm_lib_default_mmap, 1103a40e693cSJeeja KP .page = snd_pcm_sgbuf_ops_page, 1104a40e693cSJeeja KP }; 1105a40e693cSJeeja KP 1106a40e693cSJeeja KP static void skl_pcm_free(struct snd_pcm *pcm) 1107a40e693cSJeeja KP { 1108a40e693cSJeeja KP snd_pcm_lib_preallocate_free_for_all(pcm); 1109a40e693cSJeeja KP } 1110a40e693cSJeeja KP 1111a40e693cSJeeja KP #define MAX_PREALLOC_SIZE (32 * 1024 * 1024) 1112a40e693cSJeeja KP 1113a40e693cSJeeja KP static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd) 1114a40e693cSJeeja KP { 1115a40e693cSJeeja KP struct snd_soc_dai *dai = rtd->cpu_dai; 1116a40e693cSJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); 1117a40e693cSJeeja KP struct snd_pcm *pcm = rtd->pcm; 1118a40e693cSJeeja KP unsigned int size; 1119a40e693cSJeeja KP int retval = 0; 1120a40e693cSJeeja KP struct skl *skl = ebus_to_skl(ebus); 1121a40e693cSJeeja KP 1122a40e693cSJeeja KP if (dai->driver->playback.channels_min || 1123a40e693cSJeeja KP dai->driver->capture.channels_min) { 1124a40e693cSJeeja KP /* buffer pre-allocation */ 1125a40e693cSJeeja KP size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024; 1126a40e693cSJeeja KP if (size > MAX_PREALLOC_SIZE) 1127a40e693cSJeeja KP size = MAX_PREALLOC_SIZE; 1128a40e693cSJeeja KP retval = snd_pcm_lib_preallocate_pages_for_all(pcm, 1129a40e693cSJeeja KP SNDRV_DMA_TYPE_DEV_SG, 1130a40e693cSJeeja KP snd_dma_pci_data(skl->pci), 1131a40e693cSJeeja KP size, MAX_PREALLOC_SIZE); 1132a40e693cSJeeja KP if (retval) { 1133a40e693cSJeeja KP dev_err(dai->dev, "dma buffer allocationf fail\n"); 1134a40e693cSJeeja KP return retval; 1135a40e693cSJeeja KP } 1136a40e693cSJeeja KP } 1137a40e693cSJeeja KP 1138a40e693cSJeeja KP return retval; 1139a40e693cSJeeja KP } 1140a40e693cSJeeja KP 1141b663a8c5SJeeja KP static int skl_platform_soc_probe(struct snd_soc_platform *platform) 1142b663a8c5SJeeja KP { 1143b663a8c5SJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(platform->dev); 1144fe3f4442SDharageswari R struct skl *skl = ebus_to_skl(ebus); 1145fe3f4442SDharageswari R int ret; 1146b663a8c5SJeeja KP 1147fe3f4442SDharageswari R if (ebus->ppcap) { 1148fe3f4442SDharageswari R ret = skl_tplg_init(platform, ebus); 1149fe3f4442SDharageswari R if (ret < 0) { 1150fe3f4442SDharageswari R dev_err(platform->dev, "Failed to init topology!\n"); 1151fe3f4442SDharageswari R return ret; 1152fe3f4442SDharageswari R } 1153fe3f4442SDharageswari R skl->platform = platform; 1154fe3f4442SDharageswari R } 1155b663a8c5SJeeja KP 1156b663a8c5SJeeja KP return 0; 1157b663a8c5SJeeja KP } 1158a40e693cSJeeja KP static struct snd_soc_platform_driver skl_platform_drv = { 1159b663a8c5SJeeja KP .probe = skl_platform_soc_probe, 1160a40e693cSJeeja KP .ops = &skl_platform_ops, 1161a40e693cSJeeja KP .pcm_new = skl_pcm_new, 1162a40e693cSJeeja KP .pcm_free = skl_pcm_free, 1163a40e693cSJeeja KP }; 1164a40e693cSJeeja KP 1165a40e693cSJeeja KP static const struct snd_soc_component_driver skl_component = { 1166a40e693cSJeeja KP .name = "pcm", 1167a40e693cSJeeja KP }; 1168a40e693cSJeeja KP 1169a40e693cSJeeja KP int skl_platform_register(struct device *dev) 1170a40e693cSJeeja KP { 1171a40e693cSJeeja KP int ret; 1172b663a8c5SJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dev); 1173b663a8c5SJeeja KP struct skl *skl = ebus_to_skl(ebus); 1174b663a8c5SJeeja KP 1175b663a8c5SJeeja KP INIT_LIST_HEAD(&skl->ppl_list); 1176a40e693cSJeeja KP 1177a40e693cSJeeja KP ret = snd_soc_register_platform(dev, &skl_platform_drv); 1178a40e693cSJeeja KP if (ret) { 1179a40e693cSJeeja KP dev_err(dev, "soc platform registration failed %d\n", ret); 1180a40e693cSJeeja KP return ret; 1181a40e693cSJeeja KP } 1182a40e693cSJeeja KP ret = snd_soc_register_component(dev, &skl_component, 1183a40e693cSJeeja KP skl_platform_dai, 1184a40e693cSJeeja KP ARRAY_SIZE(skl_platform_dai)); 1185a40e693cSJeeja KP if (ret) { 1186a40e693cSJeeja KP dev_err(dev, "soc component registration failed %d\n", ret); 1187a40e693cSJeeja KP snd_soc_unregister_platform(dev); 1188a40e693cSJeeja KP } 1189a40e693cSJeeja KP 1190a40e693cSJeeja KP return ret; 1191a40e693cSJeeja KP 1192a40e693cSJeeja KP } 1193a40e693cSJeeja KP 1194a40e693cSJeeja KP int skl_platform_unregister(struct device *dev) 1195a40e693cSJeeja KP { 1196a40e693cSJeeja KP snd_soc_unregister_component(dev); 1197a40e693cSJeeja KP snd_soc_unregister_platform(dev); 1198a40e693cSJeeja KP return 0; 1199a40e693cSJeeja KP } 1200