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> 24fdd85a05SHardik T Shah #include <linux/delay.h> 25a40e693cSJeeja KP #include <sound/pcm_params.h> 26a40e693cSJeeja KP #include <sound/soc.h> 27a40e693cSJeeja KP #include "skl.h" 28b663a8c5SJeeja KP #include "skl-topology.h" 29721c3e36SDharageswari.R #include "skl-sst-dsp.h" 30721c3e36SDharageswari.R #include "skl-sst-ipc.h" 31a40e693cSJeeja KP 32a40e693cSJeeja KP #define HDA_MONO 1 33a40e693cSJeeja KP #define HDA_STEREO 2 348f35bf3fSJeeja KP #define HDA_QUAD 4 35a40e693cSJeeja KP 368df397ffSBhumika Goyal static const struct snd_pcm_hardware azx_pcm_hw = { 37a40e693cSJeeja KP .info = (SNDRV_PCM_INFO_MMAP | 38a40e693cSJeeja KP SNDRV_PCM_INFO_INTERLEAVED | 39a40e693cSJeeja KP SNDRV_PCM_INFO_BLOCK_TRANSFER | 40a40e693cSJeeja KP SNDRV_PCM_INFO_MMAP_VALID | 41a40e693cSJeeja KP SNDRV_PCM_INFO_PAUSE | 423637976bSJeeja KP SNDRV_PCM_INFO_RESUME | 43a40e693cSJeeja KP SNDRV_PCM_INFO_SYNC_START | 44a40e693cSJeeja KP SNDRV_PCM_INFO_HAS_WALL_CLOCK | /* legacy */ 45a40e693cSJeeja KP SNDRV_PCM_INFO_HAS_LINK_ATIME | 46a40e693cSJeeja KP SNDRV_PCM_INFO_NO_PERIOD_WAKEUP), 4706b23d93SJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE | 4806b23d93SJeeja KP SNDRV_PCM_FMTBIT_S32_LE | 4906b23d93SJeeja KP SNDRV_PCM_FMTBIT_S24_LE, 5006b23d93SJeeja KP .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | 5106b23d93SJeeja KP SNDRV_PCM_RATE_8000, 5206b23d93SJeeja KP .rate_min = 8000, 53a40e693cSJeeja KP .rate_max = 48000, 548f35bf3fSJeeja KP .channels_min = 1, 557e12dc87SSubhransu S. Prusty .channels_max = 8, 56a40e693cSJeeja KP .buffer_bytes_max = AZX_MAX_BUF_SIZE, 57a40e693cSJeeja KP .period_bytes_min = 128, 58a40e693cSJeeja KP .period_bytes_max = AZX_MAX_BUF_SIZE / 2, 59a40e693cSJeeja KP .periods_min = 2, 60a40e693cSJeeja KP .periods_max = AZX_MAX_FRAG, 61a40e693cSJeeja KP .fifo_size = 0, 62a40e693cSJeeja KP }; 63a40e693cSJeeja KP 64a40e693cSJeeja KP static inline 65a40e693cSJeeja KP struct hdac_ext_stream *get_hdac_ext_stream(struct snd_pcm_substream *substream) 66a40e693cSJeeja KP { 67a40e693cSJeeja KP return substream->runtime->private_data; 68a40e693cSJeeja KP } 69a40e693cSJeeja KP 70a40e693cSJeeja KP static struct hdac_ext_bus *get_bus_ctx(struct snd_pcm_substream *substream) 71a40e693cSJeeja KP { 72a40e693cSJeeja KP struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); 73a40e693cSJeeja KP struct hdac_stream *hstream = hdac_stream(stream); 74a40e693cSJeeja KP struct hdac_bus *bus = hstream->bus; 75a40e693cSJeeja KP 76a40e693cSJeeja KP return hbus_to_ebus(bus); 77a40e693cSJeeja KP } 78a40e693cSJeeja KP 79a40e693cSJeeja KP static int skl_substream_alloc_pages(struct hdac_ext_bus *ebus, 80a40e693cSJeeja KP struct snd_pcm_substream *substream, 81a40e693cSJeeja KP size_t size) 82a40e693cSJeeja KP { 83a40e693cSJeeja KP struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); 84a40e693cSJeeja KP 85a40e693cSJeeja KP hdac_stream(stream)->bufsize = 0; 86a40e693cSJeeja KP hdac_stream(stream)->period_bytes = 0; 87a40e693cSJeeja KP hdac_stream(stream)->format_val = 0; 88a40e693cSJeeja KP 89a40e693cSJeeja KP return snd_pcm_lib_malloc_pages(substream, size); 90a40e693cSJeeja KP } 91a40e693cSJeeja KP 92a40e693cSJeeja KP static int skl_substream_free_pages(struct hdac_bus *bus, 93a40e693cSJeeja KP struct snd_pcm_substream *substream) 94a40e693cSJeeja KP { 95a40e693cSJeeja KP return snd_pcm_lib_free_pages(substream); 96a40e693cSJeeja KP } 97a40e693cSJeeja KP 98a40e693cSJeeja KP static void skl_set_pcm_constrains(struct hdac_ext_bus *ebus, 99a40e693cSJeeja KP struct snd_pcm_runtime *runtime) 100a40e693cSJeeja KP { 101a40e693cSJeeja KP snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); 102a40e693cSJeeja KP 103a40e693cSJeeja KP /* avoid wrap-around with wall-clock */ 104a40e693cSJeeja KP snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME, 105a40e693cSJeeja KP 20, 178000000); 106a40e693cSJeeja KP } 107a40e693cSJeeja KP 10805057001SJeeja KP static enum hdac_ext_stream_type skl_get_host_stream_type(struct hdac_ext_bus *ebus) 10905057001SJeeja KP { 110ec8ae570SVinod Koul if ((ebus_to_hbus(ebus))->ppcap) 11105057001SJeeja KP return HDAC_EXT_STREAM_TYPE_HOST; 11205057001SJeeja KP else 11305057001SJeeja KP return HDAC_EXT_STREAM_TYPE_COUPLED; 11405057001SJeeja KP } 11505057001SJeeja KP 1164557c305SJeeja KP /* 1174557c305SJeeja KP * check if the stream opened is marked as ignore_suspend by machine, if so 1184557c305SJeeja KP * then enable suspend_active refcount 1194557c305SJeeja KP * 1204557c305SJeeja KP * The count supend_active does not need lock as it is used in open/close 1214557c305SJeeja KP * and suspend context 1224557c305SJeeja KP */ 1234557c305SJeeja KP static void skl_set_suspend_active(struct snd_pcm_substream *substream, 1244557c305SJeeja KP struct snd_soc_dai *dai, bool enable) 1254557c305SJeeja KP { 1264557c305SJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); 1274557c305SJeeja KP struct snd_soc_dapm_widget *w; 1284557c305SJeeja KP struct skl *skl = ebus_to_skl(ebus); 1294557c305SJeeja KP 1304557c305SJeeja KP if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 1314557c305SJeeja KP w = dai->playback_widget; 1324557c305SJeeja KP else 1334557c305SJeeja KP w = dai->capture_widget; 1344557c305SJeeja KP 1354557c305SJeeja KP if (w->ignore_suspend && enable) 1364557c305SJeeja KP skl->supend_active++; 1374557c305SJeeja KP else if (w->ignore_suspend && !enable) 1384557c305SJeeja KP skl->supend_active--; 1394557c305SJeeja KP } 1404557c305SJeeja KP 141ad036bdeSJeeja KP int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params) 142ad036bdeSJeeja KP { 143ad036bdeSJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dev); 144ad036bdeSJeeja KP struct hdac_bus *bus = ebus_to_hbus(ebus); 145ad036bdeSJeeja KP unsigned int format_val; 146ad036bdeSJeeja KP struct hdac_stream *hstream; 147ad036bdeSJeeja KP struct hdac_ext_stream *stream; 148ad036bdeSJeeja KP int err; 149ad036bdeSJeeja KP 150ad036bdeSJeeja KP hstream = snd_hdac_get_stream(bus, params->stream, 151ad036bdeSJeeja KP params->host_dma_id + 1); 152ad036bdeSJeeja KP if (!hstream) 153ad036bdeSJeeja KP return -EINVAL; 154ad036bdeSJeeja KP 155ad036bdeSJeeja KP stream = stream_to_hdac_ext_stream(hstream); 156ad036bdeSJeeja KP snd_hdac_ext_stream_decouple(ebus, stream, true); 157ad036bdeSJeeja KP 158ad036bdeSJeeja KP format_val = snd_hdac_calc_stream_format(params->s_freq, 1597f975a38SJeeja KP params->ch, params->format, params->host_bps, 0); 160ad036bdeSJeeja KP 161ad036bdeSJeeja KP dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n", 162ad036bdeSJeeja KP format_val, params->s_freq, params->ch, params->format); 163ad036bdeSJeeja KP 164ad036bdeSJeeja KP snd_hdac_stream_reset(hdac_stream(stream)); 165ad036bdeSJeeja KP err = snd_hdac_stream_set_params(hdac_stream(stream), format_val); 166ad036bdeSJeeja KP if (err < 0) 167ad036bdeSJeeja KP return err; 168ad036bdeSJeeja KP 169ad036bdeSJeeja KP err = snd_hdac_stream_setup(hdac_stream(stream)); 170ad036bdeSJeeja KP if (err < 0) 171ad036bdeSJeeja KP return err; 172ad036bdeSJeeja KP 173ad036bdeSJeeja KP hdac_stream(stream)->prepared = 1; 174ad036bdeSJeeja KP 175ad036bdeSJeeja KP return 0; 176ad036bdeSJeeja KP } 177ad036bdeSJeeja KP 178ad036bdeSJeeja KP int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params) 179ad036bdeSJeeja KP { 180ad036bdeSJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dev); 181ad036bdeSJeeja KP struct hdac_bus *bus = ebus_to_hbus(ebus); 182ad036bdeSJeeja KP unsigned int format_val; 183ad036bdeSJeeja KP struct hdac_stream *hstream; 184ad036bdeSJeeja KP struct hdac_ext_stream *stream; 185ad036bdeSJeeja KP struct hdac_ext_link *link; 186ad036bdeSJeeja KP 187ad036bdeSJeeja KP hstream = snd_hdac_get_stream(bus, params->stream, 188ad036bdeSJeeja KP params->link_dma_id + 1); 189ad036bdeSJeeja KP if (!hstream) 190ad036bdeSJeeja KP return -EINVAL; 191ad036bdeSJeeja KP 192ad036bdeSJeeja KP stream = stream_to_hdac_ext_stream(hstream); 193ad036bdeSJeeja KP snd_hdac_ext_stream_decouple(ebus, stream, true); 1947f975a38SJeeja KP format_val = snd_hdac_calc_stream_format(params->s_freq, params->ch, 1957f975a38SJeeja KP params->format, params->link_bps, 0); 196ad036bdeSJeeja KP 197ad036bdeSJeeja KP dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n", 198ad036bdeSJeeja KP format_val, params->s_freq, params->ch, params->format); 199ad036bdeSJeeja KP 200ad036bdeSJeeja KP snd_hdac_ext_link_stream_reset(stream); 201ad036bdeSJeeja KP 202ad036bdeSJeeja KP snd_hdac_ext_link_stream_setup(stream, format_val); 203ad036bdeSJeeja KP 204ad036bdeSJeeja KP list_for_each_entry(link, &ebus->hlink_list, list) { 205ad036bdeSJeeja KP if (link->index == params->link_index) 206ad036bdeSJeeja KP snd_hdac_ext_link_set_stream_id(link, 207ad036bdeSJeeja KP hstream->stream_tag); 208ad036bdeSJeeja KP } 209ad036bdeSJeeja KP 210ad036bdeSJeeja KP stream->link_prepared = 1; 211ad036bdeSJeeja KP 212ad036bdeSJeeja KP return 0; 213ad036bdeSJeeja KP } 214ad036bdeSJeeja KP 215a40e693cSJeeja KP static int skl_pcm_open(struct snd_pcm_substream *substream, 216a40e693cSJeeja KP struct snd_soc_dai *dai) 217a40e693cSJeeja KP { 218a40e693cSJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); 219a40e693cSJeeja KP struct hdac_ext_stream *stream; 220a40e693cSJeeja KP struct snd_pcm_runtime *runtime = substream->runtime; 221a40e693cSJeeja KP struct skl_dma_params *dma_params; 222a83e3b4cSVinod Koul struct skl *skl = get_skl_ctx(dai->dev); 223a83e3b4cSVinod Koul struct skl_module_cfg *mconfig; 224a40e693cSJeeja KP 225a40e693cSJeeja KP dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); 226a40e693cSJeeja KP 227a40e693cSJeeja KP stream = snd_hdac_ext_stream_assign(ebus, substream, 22805057001SJeeja KP skl_get_host_stream_type(ebus)); 229a40e693cSJeeja KP if (stream == NULL) 230a40e693cSJeeja KP return -EBUSY; 231a40e693cSJeeja KP 232a40e693cSJeeja KP skl_set_pcm_constrains(ebus, runtime); 233a40e693cSJeeja KP 234a40e693cSJeeja KP /* 235a40e693cSJeeja KP * disable WALLCLOCK timestamps for capture streams 236a40e693cSJeeja KP * until we figure out how to handle digital inputs 237a40e693cSJeeja KP */ 238a40e693cSJeeja KP if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 239a40e693cSJeeja KP runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_WALL_CLOCK; /* legacy */ 240a40e693cSJeeja KP runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_LINK_ATIME; 241a40e693cSJeeja KP } 242a40e693cSJeeja KP 243a40e693cSJeeja KP runtime->private_data = stream; 244a40e693cSJeeja KP 245a40e693cSJeeja KP dma_params = kzalloc(sizeof(*dma_params), GFP_KERNEL); 246a40e693cSJeeja KP if (!dma_params) 247a40e693cSJeeja KP return -ENOMEM; 248a40e693cSJeeja KP 249a40e693cSJeeja KP dma_params->stream_tag = hdac_stream(stream)->stream_tag; 250a40e693cSJeeja KP snd_soc_dai_set_dma_data(dai, substream, dma_params); 251a40e693cSJeeja KP 252a40e693cSJeeja KP dev_dbg(dai->dev, "stream tag set in dma params=%d\n", 253a40e693cSJeeja KP dma_params->stream_tag); 2544557c305SJeeja KP skl_set_suspend_active(substream, dai, true); 255a40e693cSJeeja KP snd_pcm_set_sync(substream); 256a40e693cSJeeja KP 257a83e3b4cSVinod Koul mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); 25891ce5497SG Kranthi if (!mconfig) 25991ce5497SG Kranthi return -EINVAL; 26091ce5497SG Kranthi 261a83e3b4cSVinod Koul skl_tplg_d0i3_get(skl, mconfig->d0i3_caps); 262a83e3b4cSVinod Koul 263a40e693cSJeeja KP return 0; 264a40e693cSJeeja KP } 265a40e693cSJeeja KP 266a40e693cSJeeja KP static int skl_pcm_prepare(struct snd_pcm_substream *substream, 267a40e693cSJeeja KP struct snd_soc_dai *dai) 268a40e693cSJeeja KP { 2692004432fSJeeja KP struct skl *skl = get_skl_ctx(dai->dev); 2702004432fSJeeja KP struct skl_module_cfg *mconfig; 271a40e693cSJeeja KP 272a40e693cSJeeja KP dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); 273a40e693cSJeeja KP 2742004432fSJeeja KP mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); 2752004432fSJeeja KP 2762004432fSJeeja KP /* In case of XRUN recovery, reset the FW pipe to clean state */ 2772004432fSJeeja KP if (mconfig && (substream->runtime->status->state == 2782004432fSJeeja KP SNDRV_PCM_STATE_XRUN)) 2792004432fSJeeja KP skl_reset_pipe(skl->skl_sst, mconfig->pipe); 2802004432fSJeeja KP 281bb704a73SJeeja KP return 0; 282a40e693cSJeeja KP } 283a40e693cSJeeja KP 284a40e693cSJeeja KP static int skl_pcm_hw_params(struct snd_pcm_substream *substream, 285a40e693cSJeeja KP struct snd_pcm_hw_params *params, 286a40e693cSJeeja KP struct snd_soc_dai *dai) 287a40e693cSJeeja KP { 288a40e693cSJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); 28905057001SJeeja KP struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); 290a40e693cSJeeja KP struct snd_pcm_runtime *runtime = substream->runtime; 291b663a8c5SJeeja KP struct skl_pipe_params p_params = {0}; 292b663a8c5SJeeja KP struct skl_module_cfg *m_cfg; 29305057001SJeeja KP int ret, dma_id; 294a40e693cSJeeja KP 295a40e693cSJeeja KP dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); 296a40e693cSJeeja KP ret = skl_substream_alloc_pages(ebus, substream, 297a40e693cSJeeja KP params_buffer_bytes(params)); 298a40e693cSJeeja KP if (ret < 0) 299a40e693cSJeeja KP return ret; 300a40e693cSJeeja KP 301a40e693cSJeeja KP dev_dbg(dai->dev, "format_val, rate=%d, ch=%d, format=%d\n", 302a40e693cSJeeja KP runtime->rate, runtime->channels, runtime->format); 303a40e693cSJeeja KP 30405057001SJeeja KP dma_id = hdac_stream(stream)->stream_tag - 1; 30505057001SJeeja KP dev_dbg(dai->dev, "dma_id=%d\n", dma_id); 30605057001SJeeja KP 307b663a8c5SJeeja KP p_params.s_fmt = snd_pcm_format_width(params_format(params)); 308b663a8c5SJeeja KP p_params.ch = params_channels(params); 309b663a8c5SJeeja KP p_params.s_freq = params_rate(params); 310b663a8c5SJeeja KP p_params.host_dma_id = dma_id; 311b663a8c5SJeeja KP p_params.stream = substream->stream; 31212c3be0eSJeeja KP p_params.format = params_format(params); 3137f975a38SJeeja KP if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 3147f975a38SJeeja KP p_params.host_bps = dai->driver->playback.sig_bits; 3157f975a38SJeeja KP else 3167f975a38SJeeja KP p_params.host_bps = dai->driver->capture.sig_bits; 3177f975a38SJeeja KP 318b663a8c5SJeeja KP 319b663a8c5SJeeja KP m_cfg = skl_tplg_fe_get_cpr_module(dai, p_params.stream); 320b663a8c5SJeeja KP if (m_cfg) 321b663a8c5SJeeja KP skl_tplg_update_pipe_params(dai->dev, m_cfg, &p_params); 322b663a8c5SJeeja KP 323a40e693cSJeeja KP return 0; 324a40e693cSJeeja KP } 325a40e693cSJeeja KP 326a40e693cSJeeja KP static void skl_pcm_close(struct snd_pcm_substream *substream, 327a40e693cSJeeja KP struct snd_soc_dai *dai) 328a40e693cSJeeja KP { 329a40e693cSJeeja KP struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); 33005057001SJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); 331a40e693cSJeeja KP struct skl_dma_params *dma_params = NULL; 332721c3e36SDharageswari.R struct skl *skl = ebus_to_skl(ebus); 333a83e3b4cSVinod Koul struct skl_module_cfg *mconfig; 334a40e693cSJeeja KP 335a40e693cSJeeja KP dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); 33605057001SJeeja KP 33705057001SJeeja KP snd_hdac_ext_stream_release(stream, skl_get_host_stream_type(ebus)); 338a40e693cSJeeja KP 339a40e693cSJeeja KP dma_params = snd_soc_dai_get_dma_data(dai, substream); 340a40e693cSJeeja KP /* 341a40e693cSJeeja KP * now we should set this to NULL as we are freeing by the 342a40e693cSJeeja KP * dma_params 343a40e693cSJeeja KP */ 344a40e693cSJeeja KP snd_soc_dai_set_dma_data(dai, substream, NULL); 3454557c305SJeeja KP skl_set_suspend_active(substream, dai, false); 346a40e693cSJeeja KP 347721c3e36SDharageswari.R /* 348721c3e36SDharageswari.R * check if close is for "Reference Pin" and set back the 349721c3e36SDharageswari.R * CGCTL.MISCBDCGE if disabled by driver 350721c3e36SDharageswari.R */ 351721c3e36SDharageswari.R if (!strncmp(dai->name, "Reference Pin", 13) && 352721c3e36SDharageswari.R skl->skl_sst->miscbdcg_disabled) { 353721c3e36SDharageswari.R skl->skl_sst->enable_miscbdcge(dai->dev, true); 354721c3e36SDharageswari.R skl->skl_sst->miscbdcg_disabled = false; 355721c3e36SDharageswari.R } 356721c3e36SDharageswari.R 357a83e3b4cSVinod Koul mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); 358a83e3b4cSVinod Koul skl_tplg_d0i3_put(skl, mconfig->d0i3_caps); 359a83e3b4cSVinod Koul 360a40e693cSJeeja KP kfree(dma_params); 361a40e693cSJeeja KP } 362a40e693cSJeeja KP 363a40e693cSJeeja KP static int skl_pcm_hw_free(struct snd_pcm_substream *substream, 364a40e693cSJeeja KP struct snd_soc_dai *dai) 365a40e693cSJeeja KP { 366a40e693cSJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); 367a40e693cSJeeja KP struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); 368a40e693cSJeeja KP 369a40e693cSJeeja KP dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); 370a40e693cSJeeja KP 371a40e693cSJeeja KP snd_hdac_stream_cleanup(hdac_stream(stream)); 372a40e693cSJeeja KP hdac_stream(stream)->prepared = 0; 373a40e693cSJeeja KP 374a40e693cSJeeja KP return skl_substream_free_pages(ebus_to_hbus(ebus), substream); 375a40e693cSJeeja KP } 376a40e693cSJeeja KP 377b663a8c5SJeeja KP static int skl_be_hw_params(struct snd_pcm_substream *substream, 378b663a8c5SJeeja KP struct snd_pcm_hw_params *params, 379b663a8c5SJeeja KP struct snd_soc_dai *dai) 380b663a8c5SJeeja KP { 381b663a8c5SJeeja KP struct skl_pipe_params p_params = {0}; 382b663a8c5SJeeja KP 383b663a8c5SJeeja KP p_params.s_fmt = snd_pcm_format_width(params_format(params)); 384b663a8c5SJeeja KP p_params.ch = params_channels(params); 385b663a8c5SJeeja KP p_params.s_freq = params_rate(params); 386b663a8c5SJeeja KP p_params.stream = substream->stream; 387b663a8c5SJeeja KP 3884bd073f9SJeeja KP return skl_tplg_be_update_params(dai, &p_params); 389b663a8c5SJeeja KP } 390b663a8c5SJeeja KP 391d1730c3dSJeeja KP static int skl_decoupled_trigger(struct snd_pcm_substream *substream, 392d1730c3dSJeeja KP int cmd) 393d1730c3dSJeeja KP { 394d1730c3dSJeeja KP struct hdac_ext_bus *ebus = get_bus_ctx(substream); 395d1730c3dSJeeja KP struct hdac_bus *bus = ebus_to_hbus(ebus); 396d1730c3dSJeeja KP struct hdac_ext_stream *stream; 397d1730c3dSJeeja KP int start; 398d1730c3dSJeeja KP unsigned long cookie; 399d1730c3dSJeeja KP struct hdac_stream *hstr; 400d1730c3dSJeeja KP 401d1730c3dSJeeja KP stream = get_hdac_ext_stream(substream); 402d1730c3dSJeeja KP hstr = hdac_stream(stream); 403d1730c3dSJeeja KP 404d1730c3dSJeeja KP if (!hstr->prepared) 405d1730c3dSJeeja KP return -EPIPE; 406d1730c3dSJeeja KP 407d1730c3dSJeeja KP switch (cmd) { 408d1730c3dSJeeja KP case SNDRV_PCM_TRIGGER_START: 409d1730c3dSJeeja KP case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 410d1730c3dSJeeja KP case SNDRV_PCM_TRIGGER_RESUME: 411d1730c3dSJeeja KP start = 1; 412d1730c3dSJeeja KP break; 413d1730c3dSJeeja KP 414d1730c3dSJeeja KP case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 415d1730c3dSJeeja KP case SNDRV_PCM_TRIGGER_SUSPEND: 416d1730c3dSJeeja KP case SNDRV_PCM_TRIGGER_STOP: 417d1730c3dSJeeja KP start = 0; 418d1730c3dSJeeja KP break; 419d1730c3dSJeeja KP 420d1730c3dSJeeja KP default: 421d1730c3dSJeeja KP return -EINVAL; 422d1730c3dSJeeja KP } 423d1730c3dSJeeja KP 424d1730c3dSJeeja KP spin_lock_irqsave(&bus->reg_lock, cookie); 425d1730c3dSJeeja KP 426d1730c3dSJeeja KP if (start) { 427d1730c3dSJeeja KP snd_hdac_stream_start(hdac_stream(stream), true); 428d1730c3dSJeeja KP snd_hdac_stream_timecounter_init(hstr, 0); 429d1730c3dSJeeja KP } else { 430d1730c3dSJeeja KP snd_hdac_stream_stop(hdac_stream(stream)); 431d1730c3dSJeeja KP } 432d1730c3dSJeeja KP 433d1730c3dSJeeja KP spin_unlock_irqrestore(&bus->reg_lock, cookie); 434d1730c3dSJeeja KP 435d1730c3dSJeeja KP return 0; 436d1730c3dSJeeja KP } 437d1730c3dSJeeja KP 438b663a8c5SJeeja KP static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, 439b663a8c5SJeeja KP struct snd_soc_dai *dai) 440b663a8c5SJeeja KP { 441b663a8c5SJeeja KP struct skl *skl = get_skl_ctx(dai->dev); 442b663a8c5SJeeja KP struct skl_sst *ctx = skl->skl_sst; 443b663a8c5SJeeja KP struct skl_module_cfg *mconfig; 4447e3a17d3SJeeja KP struct hdac_ext_bus *ebus = get_bus_ctx(substream); 4457e3a17d3SJeeja KP struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); 4469a655db0SJeeja KP struct snd_soc_dapm_widget *w; 447d1730c3dSJeeja KP int ret; 448b663a8c5SJeeja KP 449b663a8c5SJeeja KP mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); 450b663a8c5SJeeja KP if (!mconfig) 451b663a8c5SJeeja KP return -EIO; 452b663a8c5SJeeja KP 4539a655db0SJeeja KP if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 4549a655db0SJeeja KP w = dai->playback_widget; 4559a655db0SJeeja KP else 4569a655db0SJeeja KP w = dai->capture_widget; 4579a655db0SJeeja KP 458b663a8c5SJeeja KP switch (cmd) { 4597e3a17d3SJeeja KP case SNDRV_PCM_TRIGGER_RESUME: 4609a655db0SJeeja KP if (!w->ignore_suspend) { 461748a1d5aSJeeja KP /* 4629a655db0SJeeja KP * enable DMA Resume enable bit for the stream, set the 4639a655db0SJeeja KP * dpib & lpib position to resume before starting the 4649a655db0SJeeja KP * DMA 465748a1d5aSJeeja KP */ 466748a1d5aSJeeja KP snd_hdac_ext_stream_drsm_enable(ebus, true, 467748a1d5aSJeeja KP hdac_stream(stream)->index); 4689a655db0SJeeja KP snd_hdac_ext_stream_set_dpibr(ebus, stream, 469a700a1e6SJeeja KP stream->lpib); 470748a1d5aSJeeja KP snd_hdac_ext_stream_set_lpib(stream, stream->lpib); 4719a655db0SJeeja KP } 472748a1d5aSJeeja KP 473d1730c3dSJeeja KP case SNDRV_PCM_TRIGGER_START: 474b663a8c5SJeeja KP case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 475d1730c3dSJeeja KP /* 476d1730c3dSJeeja KP * Start HOST DMA and Start FE Pipe.This is to make sure that 477d1730c3dSJeeja KP * there are no underrun/overrun in the case when the FE 478d1730c3dSJeeja KP * pipeline is started but there is a delay in starting the 479d1730c3dSJeeja KP * DMA channel on the host. 480d1730c3dSJeeja KP */ 481d1730c3dSJeeja KP ret = skl_decoupled_trigger(substream, cmd); 482d1730c3dSJeeja KP if (ret < 0) 483d1730c3dSJeeja KP return ret; 484b663a8c5SJeeja KP return skl_run_pipe(ctx, mconfig->pipe); 485d1730c3dSJeeja KP break; 486b663a8c5SJeeja KP 487b663a8c5SJeeja KP case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 488b663a8c5SJeeja KP case SNDRV_PCM_TRIGGER_SUSPEND: 489d1730c3dSJeeja KP case SNDRV_PCM_TRIGGER_STOP: 490d1730c3dSJeeja KP /* 491d1730c3dSJeeja KP * Stop FE Pipe first and stop DMA. This is to make sure that 492d1730c3dSJeeja KP * there are no underrun/overrun in the case if there is a delay 493d1730c3dSJeeja KP * between the two operations. 494d1730c3dSJeeja KP */ 495d1730c3dSJeeja KP ret = skl_stop_pipe(ctx, mconfig->pipe); 496d1730c3dSJeeja KP if (ret < 0) 497d1730c3dSJeeja KP return ret; 498d1730c3dSJeeja KP 499d1730c3dSJeeja KP ret = skl_decoupled_trigger(substream, cmd); 5009a655db0SJeeja KP if ((cmd == SNDRV_PCM_TRIGGER_SUSPEND) && !w->ignore_suspend) { 501748a1d5aSJeeja KP /* save the dpib and lpib positions */ 502748a1d5aSJeeja KP stream->dpib = readl(ebus->bus.remap_addr + 503748a1d5aSJeeja KP AZX_REG_VS_SDXDPIB_XBASE + 504748a1d5aSJeeja KP (AZX_REG_VS_SDXDPIB_XINTERVAL * 505748a1d5aSJeeja KP hdac_stream(stream)->index)); 506748a1d5aSJeeja KP 507748a1d5aSJeeja KP stream->lpib = snd_hdac_stream_get_pos_lpib( 508748a1d5aSJeeja KP hdac_stream(stream)); 5097e3a17d3SJeeja KP snd_hdac_ext_stream_decouple(ebus, stream, false); 510748a1d5aSJeeja KP } 511d1730c3dSJeeja KP break; 512b663a8c5SJeeja KP 513b663a8c5SJeeja KP default: 514d1730c3dSJeeja KP return -EINVAL; 515b663a8c5SJeeja KP } 516d1730c3dSJeeja KP 517d1730c3dSJeeja KP return 0; 518b663a8c5SJeeja KP } 519b663a8c5SJeeja KP 52005057001SJeeja KP static int skl_link_hw_params(struct snd_pcm_substream *substream, 52105057001SJeeja KP struct snd_pcm_hw_params *params, 52205057001SJeeja KP struct snd_soc_dai *dai) 52305057001SJeeja KP { 52405057001SJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); 52505057001SJeeja KP struct hdac_ext_stream *link_dev; 52605057001SJeeja KP struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 52705057001SJeeja KP struct snd_soc_dai *codec_dai = rtd->codec_dai; 528b663a8c5SJeeja KP struct skl_pipe_params p_params = {0}; 52912c3be0eSJeeja KP struct hdac_ext_link *link; 5301011509dSJeeja KP int stream_tag; 53105057001SJeeja KP 53205057001SJeeja KP link_dev = snd_hdac_ext_stream_assign(ebus, substream, 53305057001SJeeja KP HDAC_EXT_STREAM_TYPE_LINK); 53405057001SJeeja KP if (!link_dev) 53505057001SJeeja KP return -EBUSY; 53605057001SJeeja KP 53705057001SJeeja KP snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev); 53805057001SJeeja KP 539356a383bSKuninori Morimoto link = snd_hdac_ext_bus_get_link(ebus, codec_dai->component->name); 54012c3be0eSJeeja KP if (!link) 54112c3be0eSJeeja KP return -EINVAL; 54212c3be0eSJeeja KP 5431011509dSJeeja KP stream_tag = hdac_stream(link_dev)->stream_tag; 5441011509dSJeeja KP 54505057001SJeeja KP /* set the stream tag in the codec dai dma params */ 5461011509dSJeeja KP snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0); 547b663a8c5SJeeja KP 548b663a8c5SJeeja KP p_params.s_fmt = snd_pcm_format_width(params_format(params)); 549b663a8c5SJeeja KP p_params.ch = params_channels(params); 550b663a8c5SJeeja KP p_params.s_freq = params_rate(params); 551b663a8c5SJeeja KP p_params.stream = substream->stream; 5521011509dSJeeja KP p_params.link_dma_id = stream_tag - 1; 55312c3be0eSJeeja KP p_params.link_index = link->index; 55412c3be0eSJeeja KP p_params.format = params_format(params); 555b663a8c5SJeeja KP 5567f975a38SJeeja KP if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 5577f975a38SJeeja KP p_params.link_bps = codec_dai->driver->playback.sig_bits; 5587f975a38SJeeja KP else 5597f975a38SJeeja KP p_params.link_bps = codec_dai->driver->capture.sig_bits; 5607f975a38SJeeja KP 5614bd073f9SJeeja KP return skl_tplg_be_update_params(dai, &p_params); 56205057001SJeeja KP } 56305057001SJeeja KP 56405057001SJeeja KP static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, 56505057001SJeeja KP struct snd_soc_dai *dai) 56605057001SJeeja KP { 5672004432fSJeeja KP struct skl *skl = get_skl_ctx(dai->dev); 5682004432fSJeeja KP struct skl_module_cfg *mconfig = NULL; 56905057001SJeeja KP 5702004432fSJeeja KP /* In case of XRUN recovery, reset the FW pipe to clean state */ 5712004432fSJeeja KP mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream); 5727cbfdf87SJeeja KP if (mconfig && !mconfig->pipe->passthru && 5737cbfdf87SJeeja KP (substream->runtime->status->state == SNDRV_PCM_STATE_XRUN)) 5742004432fSJeeja KP skl_reset_pipe(skl->skl_sst, mconfig->pipe); 5752004432fSJeeja KP 57605057001SJeeja KP return 0; 57705057001SJeeja KP } 57805057001SJeeja KP 57905057001SJeeja KP static int skl_link_pcm_trigger(struct snd_pcm_substream *substream, 58005057001SJeeja KP int cmd, struct snd_soc_dai *dai) 58105057001SJeeja KP { 58205057001SJeeja KP struct hdac_ext_stream *link_dev = 58305057001SJeeja KP snd_soc_dai_get_dma_data(dai, substream); 584920982c9SJeeja KP struct hdac_ext_bus *ebus = get_bus_ctx(substream); 585920982c9SJeeja KP struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); 58605057001SJeeja KP 58705057001SJeeja KP dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd); 58805057001SJeeja KP switch (cmd) { 589920982c9SJeeja KP case SNDRV_PCM_TRIGGER_RESUME: 59005057001SJeeja KP case SNDRV_PCM_TRIGGER_START: 59105057001SJeeja KP case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 59205057001SJeeja KP snd_hdac_ext_link_stream_start(link_dev); 59305057001SJeeja KP break; 59405057001SJeeja KP 59505057001SJeeja KP case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 59605057001SJeeja KP case SNDRV_PCM_TRIGGER_SUSPEND: 59705057001SJeeja KP case SNDRV_PCM_TRIGGER_STOP: 59805057001SJeeja KP snd_hdac_ext_link_stream_clear(link_dev); 599920982c9SJeeja KP if (cmd == SNDRV_PCM_TRIGGER_SUSPEND) 600920982c9SJeeja KP snd_hdac_ext_stream_decouple(ebus, stream, false); 60105057001SJeeja KP break; 60205057001SJeeja KP 60305057001SJeeja KP default: 60405057001SJeeja KP return -EINVAL; 60505057001SJeeja KP } 60605057001SJeeja KP return 0; 60705057001SJeeja KP } 60805057001SJeeja KP 60905057001SJeeja KP static int skl_link_hw_free(struct snd_pcm_substream *substream, 61005057001SJeeja KP struct snd_soc_dai *dai) 61105057001SJeeja KP { 61205057001SJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); 61305057001SJeeja KP struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 61405057001SJeeja KP struct hdac_ext_stream *link_dev = 61505057001SJeeja KP snd_soc_dai_get_dma_data(dai, substream); 61605057001SJeeja KP struct hdac_ext_link *link; 61705057001SJeeja KP 61805057001SJeeja KP dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); 61905057001SJeeja KP 62005057001SJeeja KP link_dev->link_prepared = 0; 62105057001SJeeja KP 622356a383bSKuninori Morimoto link = snd_hdac_ext_bus_get_link(ebus, rtd->codec_dai->component->name); 62305057001SJeeja KP if (!link) 62405057001SJeeja KP return -EINVAL; 62505057001SJeeja KP 62605057001SJeeja KP snd_hdac_ext_link_clear_stream_id(link, hdac_stream(link_dev)->stream_tag); 62705057001SJeeja KP snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK); 62805057001SJeeja KP return 0; 62905057001SJeeja KP } 63005057001SJeeja KP 63182e2b1e0SGustavo A. R. Silva static const struct snd_soc_dai_ops skl_pcm_dai_ops = { 632a40e693cSJeeja KP .startup = skl_pcm_open, 633a40e693cSJeeja KP .shutdown = skl_pcm_close, 634a40e693cSJeeja KP .prepare = skl_pcm_prepare, 635a40e693cSJeeja KP .hw_params = skl_pcm_hw_params, 636a40e693cSJeeja KP .hw_free = skl_pcm_hw_free, 637b663a8c5SJeeja KP .trigger = skl_pcm_trigger, 638a40e693cSJeeja KP }; 639a40e693cSJeeja KP 64082e2b1e0SGustavo A. R. Silva static const struct snd_soc_dai_ops skl_dmic_dai_ops = { 641b663a8c5SJeeja KP .hw_params = skl_be_hw_params, 642b663a8c5SJeeja KP }; 643b663a8c5SJeeja KP 64482e2b1e0SGustavo A. R. Silva static const struct snd_soc_dai_ops skl_be_ssp_dai_ops = { 645b663a8c5SJeeja KP .hw_params = skl_be_hw_params, 64605057001SJeeja KP }; 64705057001SJeeja KP 64882e2b1e0SGustavo A. R. Silva static const struct snd_soc_dai_ops skl_link_dai_ops = { 64905057001SJeeja KP .prepare = skl_link_pcm_prepare, 65005057001SJeeja KP .hw_params = skl_link_hw_params, 65105057001SJeeja KP .hw_free = skl_link_hw_free, 65205057001SJeeja KP .trigger = skl_link_pcm_trigger, 65305057001SJeeja KP }; 65405057001SJeeja KP 655c3ae22e3SGuneshwor Singh static struct snd_soc_dai_driver skl_fe_dai[] = { 656a40e693cSJeeja KP { 657a40e693cSJeeja KP .name = "System Pin", 658a40e693cSJeeja KP .ops = &skl_pcm_dai_ops, 659a40e693cSJeeja KP .playback = { 660a40e693cSJeeja KP .stream_name = "System Playback", 661a40e693cSJeeja KP .channels_min = HDA_MONO, 662a40e693cSJeeja KP .channels_max = HDA_STEREO, 663a40e693cSJeeja KP .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_8000, 664dde53bccSSamaga Krishna .formats = SNDRV_PCM_FMTBIT_S16_LE | 665dde53bccSSamaga Krishna SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, 6667f975a38SJeeja KP .sig_bits = 32, 667a40e693cSJeeja KP }, 668a40e693cSJeeja KP .capture = { 669a40e693cSJeeja KP .stream_name = "System Capture", 670a40e693cSJeeja KP .channels_min = HDA_MONO, 671a40e693cSJeeja KP .channels_max = HDA_STEREO, 672a40e693cSJeeja KP .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, 673a40e693cSJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 6747f975a38SJeeja KP .sig_bits = 32, 675a40e693cSJeeja KP }, 676a40e693cSJeeja KP }, 677a40e693cSJeeja KP { 678da3cbb40SNaveen Manohar .name = "System Pin2", 679da3cbb40SNaveen Manohar .ops = &skl_pcm_dai_ops, 680da3cbb40SNaveen Manohar .playback = { 681da3cbb40SNaveen Manohar .stream_name = "Headset Playback", 682da3cbb40SNaveen Manohar .channels_min = HDA_MONO, 683da3cbb40SNaveen Manohar .channels_max = HDA_STEREO, 684da3cbb40SNaveen Manohar .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | 685da3cbb40SNaveen Manohar SNDRV_PCM_RATE_8000, 686da3cbb40SNaveen Manohar .formats = SNDRV_PCM_FMTBIT_S16_LE | 687da3cbb40SNaveen Manohar SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, 688da3cbb40SNaveen Manohar }, 689da3cbb40SNaveen Manohar }, 690da3cbb40SNaveen Manohar { 691da3cbb40SNaveen Manohar .name = "Echoref Pin", 692da3cbb40SNaveen Manohar .ops = &skl_pcm_dai_ops, 693da3cbb40SNaveen Manohar .capture = { 694da3cbb40SNaveen Manohar .stream_name = "Echoreference Capture", 695da3cbb40SNaveen Manohar .channels_min = HDA_STEREO, 696da3cbb40SNaveen Manohar .channels_max = HDA_STEREO, 697da3cbb40SNaveen Manohar .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | 698da3cbb40SNaveen Manohar SNDRV_PCM_RATE_8000, 699da3cbb40SNaveen Manohar .formats = SNDRV_PCM_FMTBIT_S16_LE | 700da3cbb40SNaveen Manohar SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, 701da3cbb40SNaveen Manohar }, 702da3cbb40SNaveen Manohar }, 703da3cbb40SNaveen Manohar { 70405057001SJeeja KP .name = "Reference Pin", 70505057001SJeeja KP .ops = &skl_pcm_dai_ops, 70605057001SJeeja KP .capture = { 70705057001SJeeja KP .stream_name = "Reference Capture", 70805057001SJeeja KP .channels_min = HDA_MONO, 7098f35bf3fSJeeja KP .channels_max = HDA_QUAD, 71005057001SJeeja KP .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, 71105057001SJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 7127f975a38SJeeja KP .sig_bits = 32, 71305057001SJeeja KP }, 71405057001SJeeja KP }, 71505057001SJeeja KP { 716a40e693cSJeeja KP .name = "Deepbuffer Pin", 717a40e693cSJeeja KP .ops = &skl_pcm_dai_ops, 718a40e693cSJeeja KP .playback = { 719a40e693cSJeeja KP .stream_name = "Deepbuffer Playback", 720a40e693cSJeeja KP .channels_min = HDA_STEREO, 721a40e693cSJeeja KP .channels_max = HDA_STEREO, 722a40e693cSJeeja KP .rates = SNDRV_PCM_RATE_48000, 723a40e693cSJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 7247f975a38SJeeja KP .sig_bits = 32, 725a40e693cSJeeja KP }, 726a40e693cSJeeja KP }, 727a40e693cSJeeja KP { 728a40e693cSJeeja KP .name = "LowLatency Pin", 729a40e693cSJeeja KP .ops = &skl_pcm_dai_ops, 730a40e693cSJeeja KP .playback = { 731a40e693cSJeeja KP .stream_name = "Low Latency Playback", 732a40e693cSJeeja KP .channels_min = HDA_STEREO, 733a40e693cSJeeja KP .channels_max = HDA_STEREO, 734a40e693cSJeeja KP .rates = SNDRV_PCM_RATE_48000, 735a40e693cSJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 7367f975a38SJeeja KP .sig_bits = 32, 737a40e693cSJeeja KP }, 738a40e693cSJeeja KP }, 7398f35bf3fSJeeja KP { 7408f35bf3fSJeeja KP .name = "DMIC Pin", 7418f35bf3fSJeeja KP .ops = &skl_pcm_dai_ops, 7428f35bf3fSJeeja KP .capture = { 7438f35bf3fSJeeja KP .stream_name = "DMIC Capture", 7448f35bf3fSJeeja KP .channels_min = HDA_MONO, 7458f35bf3fSJeeja KP .channels_max = HDA_QUAD, 7468f35bf3fSJeeja KP .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, 7478f35bf3fSJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 7487f975a38SJeeja KP .sig_bits = 32, 7498f35bf3fSJeeja KP }, 7508f35bf3fSJeeja KP }, 7518cca87c0SSubhransu S. Prusty { 7528cca87c0SSubhransu S. Prusty .name = "HDMI1 Pin", 7538cca87c0SSubhransu S. Prusty .ops = &skl_pcm_dai_ops, 7548cca87c0SSubhransu S. Prusty .playback = { 7558cca87c0SSubhransu S. Prusty .stream_name = "HDMI1 Playback", 7568cca87c0SSubhransu S. Prusty .channels_min = HDA_STEREO, 7577e12dc87SSubhransu S. Prusty .channels_max = 8, 7588cca87c0SSubhransu S. Prusty .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | 7598cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | 7608cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | 7618cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_192000, 7628cca87c0SSubhransu S. Prusty .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | 7638cca87c0SSubhransu S. Prusty SNDRV_PCM_FMTBIT_S32_LE, 7647f975a38SJeeja KP .sig_bits = 32, 7658cca87c0SSubhransu S. Prusty }, 7668cca87c0SSubhransu S. Prusty }, 7678cca87c0SSubhransu S. Prusty { 7688cca87c0SSubhransu S. Prusty .name = "HDMI2 Pin", 7698cca87c0SSubhransu S. Prusty .ops = &skl_pcm_dai_ops, 7708cca87c0SSubhransu S. Prusty .playback = { 7718cca87c0SSubhransu S. Prusty .stream_name = "HDMI2 Playback", 7728cca87c0SSubhransu S. Prusty .channels_min = HDA_STEREO, 7737e12dc87SSubhransu S. Prusty .channels_max = 8, 7748cca87c0SSubhransu S. Prusty .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | 7758cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | 7768cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | 7778cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_192000, 7788cca87c0SSubhransu S. Prusty .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | 7798cca87c0SSubhransu S. Prusty SNDRV_PCM_FMTBIT_S32_LE, 7807f975a38SJeeja KP .sig_bits = 32, 7818cca87c0SSubhransu S. Prusty }, 7828cca87c0SSubhransu S. Prusty }, 7838cca87c0SSubhransu S. Prusty { 7848cca87c0SSubhransu S. Prusty .name = "HDMI3 Pin", 7858cca87c0SSubhransu S. Prusty .ops = &skl_pcm_dai_ops, 7868cca87c0SSubhransu S. Prusty .playback = { 7878cca87c0SSubhransu S. Prusty .stream_name = "HDMI3 Playback", 7888cca87c0SSubhransu S. Prusty .channels_min = HDA_STEREO, 7897e12dc87SSubhransu S. Prusty .channels_max = 8, 7908cca87c0SSubhransu S. Prusty .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | 7918cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | 7928cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | 7938cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_192000, 7948cca87c0SSubhransu S. Prusty .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | 7958cca87c0SSubhransu S. Prusty SNDRV_PCM_FMTBIT_S32_LE, 7967f975a38SJeeja KP .sig_bits = 32, 7978cca87c0SSubhransu S. Prusty }, 7988cca87c0SSubhransu S. Prusty }, 799c3ae22e3SGuneshwor Singh }; 8008f35bf3fSJeeja KP 80105057001SJeeja KP /* BE CPU Dais */ 802c3ae22e3SGuneshwor Singh static struct snd_soc_dai_driver skl_platform_dai[] = { 80305057001SJeeja KP { 804b663a8c5SJeeja KP .name = "SSP0 Pin", 805b663a8c5SJeeja KP .ops = &skl_be_ssp_dai_ops, 806b663a8c5SJeeja KP .playback = { 807b663a8c5SJeeja KP .stream_name = "ssp0 Tx", 808b663a8c5SJeeja KP .channels_min = HDA_STEREO, 809b663a8c5SJeeja KP .channels_max = HDA_STEREO, 810b663a8c5SJeeja KP .rates = SNDRV_PCM_RATE_48000, 811b663a8c5SJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE, 812b663a8c5SJeeja KP }, 813b663a8c5SJeeja KP .capture = { 814b663a8c5SJeeja KP .stream_name = "ssp0 Rx", 815b663a8c5SJeeja KP .channels_min = HDA_STEREO, 816b663a8c5SJeeja KP .channels_max = HDA_STEREO, 817b663a8c5SJeeja KP .rates = SNDRV_PCM_RATE_48000, 818b663a8c5SJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE, 819b663a8c5SJeeja KP }, 820b663a8c5SJeeja KP }, 821b663a8c5SJeeja KP { 822c80fd4daSJeeja KP .name = "SSP1 Pin", 823c80fd4daSJeeja KP .ops = &skl_be_ssp_dai_ops, 824c80fd4daSJeeja KP .playback = { 825c80fd4daSJeeja KP .stream_name = "ssp1 Tx", 826c80fd4daSJeeja KP .channels_min = HDA_STEREO, 827c80fd4daSJeeja KP .channels_max = HDA_STEREO, 828c80fd4daSJeeja KP .rates = SNDRV_PCM_RATE_48000, 829c80fd4daSJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE, 830c80fd4daSJeeja KP }, 831c80fd4daSJeeja KP .capture = { 832c80fd4daSJeeja KP .stream_name = "ssp1 Rx", 833c80fd4daSJeeja KP .channels_min = HDA_STEREO, 834c80fd4daSJeeja KP .channels_max = HDA_STEREO, 835c80fd4daSJeeja KP .rates = SNDRV_PCM_RATE_48000, 836c80fd4daSJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE, 837c80fd4daSJeeja KP }, 838c80fd4daSJeeja KP }, 839c80fd4daSJeeja KP { 840fcc494afSPardha Saradhi K .name = "SSP2 Pin", 841fcc494afSPardha Saradhi K .ops = &skl_be_ssp_dai_ops, 842fcc494afSPardha Saradhi K .playback = { 843fcc494afSPardha Saradhi K .stream_name = "ssp2 Tx", 844fcc494afSPardha Saradhi K .channels_min = HDA_STEREO, 845fcc494afSPardha Saradhi K .channels_max = HDA_STEREO, 846fcc494afSPardha Saradhi K .rates = SNDRV_PCM_RATE_48000, 847fcc494afSPardha Saradhi K .formats = SNDRV_PCM_FMTBIT_S16_LE, 848fcc494afSPardha Saradhi K }, 849fcc494afSPardha Saradhi K .capture = { 850fcc494afSPardha Saradhi K .stream_name = "ssp2 Rx", 851fcc494afSPardha Saradhi K .channels_min = HDA_STEREO, 852fcc494afSPardha Saradhi K .channels_max = HDA_STEREO, 853fcc494afSPardha Saradhi K .rates = SNDRV_PCM_RATE_48000, 854fcc494afSPardha Saradhi K .formats = SNDRV_PCM_FMTBIT_S16_LE, 855fcc494afSPardha Saradhi K }, 856fcc494afSPardha Saradhi K }, 857fcc494afSPardha Saradhi K { 858fcc494afSPardha Saradhi K .name = "SSP3 Pin", 859fcc494afSPardha Saradhi K .ops = &skl_be_ssp_dai_ops, 860fcc494afSPardha Saradhi K .playback = { 861fcc494afSPardha Saradhi K .stream_name = "ssp3 Tx", 862fcc494afSPardha Saradhi K .channels_min = HDA_STEREO, 863fcc494afSPardha Saradhi K .channels_max = HDA_STEREO, 864fcc494afSPardha Saradhi K .rates = SNDRV_PCM_RATE_48000, 865fcc494afSPardha Saradhi K .formats = SNDRV_PCM_FMTBIT_S16_LE, 866fcc494afSPardha Saradhi K }, 867fcc494afSPardha Saradhi K .capture = { 868fcc494afSPardha Saradhi K .stream_name = "ssp3 Rx", 869fcc494afSPardha Saradhi K .channels_min = HDA_STEREO, 870fcc494afSPardha Saradhi K .channels_max = HDA_STEREO, 871fcc494afSPardha Saradhi K .rates = SNDRV_PCM_RATE_48000, 872fcc494afSPardha Saradhi K .formats = SNDRV_PCM_FMTBIT_S16_LE, 873fcc494afSPardha Saradhi K }, 874fcc494afSPardha Saradhi K }, 875fcc494afSPardha Saradhi K { 876fcc494afSPardha Saradhi K .name = "SSP4 Pin", 877fcc494afSPardha Saradhi K .ops = &skl_be_ssp_dai_ops, 878fcc494afSPardha Saradhi K .playback = { 879fcc494afSPardha Saradhi K .stream_name = "ssp4 Tx", 880fcc494afSPardha Saradhi K .channels_min = HDA_STEREO, 881fcc494afSPardha Saradhi K .channels_max = HDA_STEREO, 882fcc494afSPardha Saradhi K .rates = SNDRV_PCM_RATE_48000, 883fcc494afSPardha Saradhi K .formats = SNDRV_PCM_FMTBIT_S16_LE, 884fcc494afSPardha Saradhi K }, 885fcc494afSPardha Saradhi K .capture = { 886fcc494afSPardha Saradhi K .stream_name = "ssp4 Rx", 887fcc494afSPardha Saradhi K .channels_min = HDA_STEREO, 888fcc494afSPardha Saradhi K .channels_max = HDA_STEREO, 889fcc494afSPardha Saradhi K .rates = SNDRV_PCM_RATE_48000, 890fcc494afSPardha Saradhi K .formats = SNDRV_PCM_FMTBIT_S16_LE, 891fcc494afSPardha Saradhi K }, 892fcc494afSPardha Saradhi K }, 893fcc494afSPardha Saradhi K { 894fcc494afSPardha Saradhi K .name = "SSP5 Pin", 895fcc494afSPardha Saradhi K .ops = &skl_be_ssp_dai_ops, 896fcc494afSPardha Saradhi K .playback = { 897fcc494afSPardha Saradhi K .stream_name = "ssp5 Tx", 898fcc494afSPardha Saradhi K .channels_min = HDA_STEREO, 899fcc494afSPardha Saradhi K .channels_max = HDA_STEREO, 900fcc494afSPardha Saradhi K .rates = SNDRV_PCM_RATE_48000, 901fcc494afSPardha Saradhi K .formats = SNDRV_PCM_FMTBIT_S16_LE, 902fcc494afSPardha Saradhi K }, 903fcc494afSPardha Saradhi K .capture = { 904fcc494afSPardha Saradhi K .stream_name = "ssp5 Rx", 905fcc494afSPardha Saradhi K .channels_min = HDA_STEREO, 906fcc494afSPardha Saradhi K .channels_max = HDA_STEREO, 907fcc494afSPardha Saradhi K .rates = SNDRV_PCM_RATE_48000, 908fcc494afSPardha Saradhi K .formats = SNDRV_PCM_FMTBIT_S16_LE, 909fcc494afSPardha Saradhi K }, 910fcc494afSPardha Saradhi K }, 911fcc494afSPardha Saradhi K { 9128cca87c0SSubhransu S. Prusty .name = "iDisp1 Pin", 91305057001SJeeja KP .ops = &skl_link_dai_ops, 91405057001SJeeja KP .playback = { 9158cca87c0SSubhransu S. Prusty .stream_name = "iDisp1 Tx", 91605057001SJeeja KP .channels_min = HDA_STEREO, 9177e12dc87SSubhransu S. Prusty .channels_max = 8, 91805057001SJeeja KP .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000, 9198cca87c0SSubhransu S. Prusty .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | 9208cca87c0SSubhransu S. Prusty SNDRV_PCM_FMTBIT_S24_LE, 9218cca87c0SSubhransu S. Prusty }, 9228cca87c0SSubhransu S. Prusty }, 9238cca87c0SSubhransu S. Prusty { 9248cca87c0SSubhransu S. Prusty .name = "iDisp2 Pin", 9258cca87c0SSubhransu S. Prusty .ops = &skl_link_dai_ops, 9268cca87c0SSubhransu S. Prusty .playback = { 9278cca87c0SSubhransu S. Prusty .stream_name = "iDisp2 Tx", 9288cca87c0SSubhransu S. Prusty .channels_min = HDA_STEREO, 9297e12dc87SSubhransu S. Prusty .channels_max = 8, 9308cca87c0SSubhransu S. Prusty .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000| 9318cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_48000, 9328cca87c0SSubhransu S. Prusty .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | 9338cca87c0SSubhransu S. Prusty SNDRV_PCM_FMTBIT_S24_LE, 9348cca87c0SSubhransu S. Prusty }, 9358cca87c0SSubhransu S. Prusty }, 9368cca87c0SSubhransu S. Prusty { 9378cca87c0SSubhransu S. Prusty .name = "iDisp3 Pin", 9388cca87c0SSubhransu S. Prusty .ops = &skl_link_dai_ops, 9398cca87c0SSubhransu S. Prusty .playback = { 9408cca87c0SSubhransu S. Prusty .stream_name = "iDisp3 Tx", 9418cca87c0SSubhransu S. Prusty .channels_min = HDA_STEREO, 9427e12dc87SSubhransu S. Prusty .channels_max = 8, 9438cca87c0SSubhransu S. Prusty .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000| 9448cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_48000, 9458cca87c0SSubhransu S. Prusty .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | 9468cca87c0SSubhransu S. Prusty SNDRV_PCM_FMTBIT_S24_LE, 94705057001SJeeja KP }, 94805057001SJeeja KP }, 94905057001SJeeja KP { 95005057001SJeeja KP .name = "DMIC01 Pin", 95105057001SJeeja KP .ops = &skl_dmic_dai_ops, 95205057001SJeeja KP .capture = { 95305057001SJeeja KP .stream_name = "DMIC01 Rx", 9548f35bf3fSJeeja KP .channels_min = HDA_MONO, 9558f35bf3fSJeeja KP .channels_max = HDA_QUAD, 95605057001SJeeja KP .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, 95705057001SJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 95805057001SJeeja KP }, 95905057001SJeeja KP }, 96005057001SJeeja KP { 96105057001SJeeja KP .name = "HD-Codec Pin", 96205057001SJeeja KP .ops = &skl_link_dai_ops, 96305057001SJeeja KP .playback = { 96405057001SJeeja KP .stream_name = "HD-Codec Tx", 96505057001SJeeja KP .channels_min = HDA_STEREO, 96605057001SJeeja KP .channels_max = HDA_STEREO, 96705057001SJeeja KP .rates = SNDRV_PCM_RATE_48000, 96805057001SJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE, 96905057001SJeeja KP }, 97005057001SJeeja KP .capture = { 97105057001SJeeja KP .stream_name = "HD-Codec Rx", 97205057001SJeeja KP .channels_min = HDA_STEREO, 97305057001SJeeja KP .channels_max = HDA_STEREO, 97405057001SJeeja KP .rates = SNDRV_PCM_RATE_48000, 97505057001SJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE, 97605057001SJeeja KP }, 97705057001SJeeja KP }, 978a40e693cSJeeja KP }; 979a40e693cSJeeja KP 980606e21fdSGuneshwor Singh int skl_dai_load(struct snd_soc_component *cmp, 981606e21fdSGuneshwor Singh struct snd_soc_dai_driver *pcm_dai) 982606e21fdSGuneshwor Singh { 983606e21fdSGuneshwor Singh pcm_dai->ops = &skl_pcm_dai_ops; 984606e21fdSGuneshwor Singh 985606e21fdSGuneshwor Singh return 0; 986606e21fdSGuneshwor Singh } 987606e21fdSGuneshwor Singh 988a40e693cSJeeja KP static int skl_platform_open(struct snd_pcm_substream *substream) 989a40e693cSJeeja KP { 990a40e693cSJeeja KP struct snd_soc_pcm_runtime *rtd = substream->private_data; 991a40e693cSJeeja KP struct snd_soc_dai_link *dai_link = rtd->dai_link; 992a40e693cSJeeja KP 993a40e693cSJeeja KP dev_dbg(rtd->cpu_dai->dev, "In %s:%s\n", __func__, 994a40e693cSJeeja KP dai_link->cpu_dai_name); 995a40e693cSJeeja KP 996a40e693cSJeeja KP snd_soc_set_runtime_hwparams(substream, &azx_pcm_hw); 997a40e693cSJeeja KP 998a40e693cSJeeja KP return 0; 999a40e693cSJeeja KP } 1000a40e693cSJeeja KP 1001b663a8c5SJeeja KP static int skl_coupled_trigger(struct snd_pcm_substream *substream, 1002a40e693cSJeeja KP int cmd) 1003a40e693cSJeeja KP { 1004a40e693cSJeeja KP struct hdac_ext_bus *ebus = get_bus_ctx(substream); 1005a40e693cSJeeja KP struct hdac_bus *bus = ebus_to_hbus(ebus); 1006a40e693cSJeeja KP struct hdac_ext_stream *stream; 1007a40e693cSJeeja KP struct snd_pcm_substream *s; 1008a40e693cSJeeja KP bool start; 1009a40e693cSJeeja KP int sbits = 0; 1010a40e693cSJeeja KP unsigned long cookie; 1011a40e693cSJeeja KP struct hdac_stream *hstr; 1012a40e693cSJeeja KP 1013a40e693cSJeeja KP stream = get_hdac_ext_stream(substream); 1014a40e693cSJeeja KP hstr = hdac_stream(stream); 1015a40e693cSJeeja KP 1016a40e693cSJeeja KP dev_dbg(bus->dev, "In %s cmd=%d\n", __func__, cmd); 1017a40e693cSJeeja KP 1018a40e693cSJeeja KP if (!hstr->prepared) 1019a40e693cSJeeja KP return -EPIPE; 1020a40e693cSJeeja KP 1021a40e693cSJeeja KP switch (cmd) { 1022a40e693cSJeeja KP case SNDRV_PCM_TRIGGER_START: 1023a40e693cSJeeja KP case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 1024a40e693cSJeeja KP case SNDRV_PCM_TRIGGER_RESUME: 1025a40e693cSJeeja KP start = true; 1026a40e693cSJeeja KP break; 1027a40e693cSJeeja KP 1028a40e693cSJeeja KP case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 1029a40e693cSJeeja KP case SNDRV_PCM_TRIGGER_SUSPEND: 1030a40e693cSJeeja KP case SNDRV_PCM_TRIGGER_STOP: 1031a40e693cSJeeja KP start = false; 1032a40e693cSJeeja KP break; 1033a40e693cSJeeja KP 1034a40e693cSJeeja KP default: 1035a40e693cSJeeja KP return -EINVAL; 1036a40e693cSJeeja KP } 1037a40e693cSJeeja KP 1038a40e693cSJeeja KP snd_pcm_group_for_each_entry(s, substream) { 1039a40e693cSJeeja KP if (s->pcm->card != substream->pcm->card) 1040a40e693cSJeeja KP continue; 1041a40e693cSJeeja KP stream = get_hdac_ext_stream(s); 1042a40e693cSJeeja KP sbits |= 1 << hdac_stream(stream)->index; 1043a40e693cSJeeja KP snd_pcm_trigger_done(s, substream); 1044a40e693cSJeeja KP } 1045a40e693cSJeeja KP 1046a40e693cSJeeja KP spin_lock_irqsave(&bus->reg_lock, cookie); 1047a40e693cSJeeja KP 1048a40e693cSJeeja KP /* first, set SYNC bits of corresponding streams */ 1049a40e693cSJeeja KP snd_hdac_stream_sync_trigger(hstr, true, sbits, AZX_REG_SSYNC); 1050a40e693cSJeeja KP 1051a40e693cSJeeja KP snd_pcm_group_for_each_entry(s, substream) { 1052a40e693cSJeeja KP if (s->pcm->card != substream->pcm->card) 1053a40e693cSJeeja KP continue; 1054a40e693cSJeeja KP stream = get_hdac_ext_stream(s); 1055a40e693cSJeeja KP if (start) 1056a40e693cSJeeja KP snd_hdac_stream_start(hdac_stream(stream), true); 1057a40e693cSJeeja KP else 1058a40e693cSJeeja KP snd_hdac_stream_stop(hdac_stream(stream)); 1059a40e693cSJeeja KP } 1060a40e693cSJeeja KP spin_unlock_irqrestore(&bus->reg_lock, cookie); 1061a40e693cSJeeja KP 1062a40e693cSJeeja KP snd_hdac_stream_sync(hstr, start, sbits); 1063a40e693cSJeeja KP 1064a40e693cSJeeja KP spin_lock_irqsave(&bus->reg_lock, cookie); 1065a40e693cSJeeja KP 1066a40e693cSJeeja KP /* reset SYNC bits */ 1067a40e693cSJeeja KP snd_hdac_stream_sync_trigger(hstr, false, sbits, AZX_REG_SSYNC); 1068a40e693cSJeeja KP if (start) 1069a40e693cSJeeja KP snd_hdac_stream_timecounter_init(hstr, sbits); 1070a40e693cSJeeja KP spin_unlock_irqrestore(&bus->reg_lock, cookie); 1071a40e693cSJeeja KP 1072a40e693cSJeeja KP return 0; 1073a40e693cSJeeja KP } 1074a40e693cSJeeja KP 107505057001SJeeja KP static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream, 107605057001SJeeja KP int cmd) 107705057001SJeeja KP { 107805057001SJeeja KP struct hdac_ext_bus *ebus = get_bus_ctx(substream); 107905057001SJeeja KP 1080fc94733eSVinod Koul if (!(ebus_to_hbus(ebus))->ppcap) 1081b663a8c5SJeeja KP return skl_coupled_trigger(substream, cmd); 1082d1730c3dSJeeja KP 1083d1730c3dSJeeja KP return 0; 108405057001SJeeja KP } 108505057001SJeeja KP 10867b96144dSJeeja KP static snd_pcm_uframes_t skl_platform_pcm_pointer 10877b96144dSJeeja KP (struct snd_pcm_substream *substream) 1088a40e693cSJeeja KP { 10897b96144dSJeeja KP struct hdac_ext_stream *hstream = get_hdac_ext_stream(substream); 1090ca590c1cSDharageswari R struct hdac_ext_bus *ebus = get_bus_ctx(substream); 1091a40e693cSJeeja KP unsigned int pos; 1092a40e693cSJeeja KP 1093ca590c1cSDharageswari R /* 1094ca590c1cSDharageswari R * Use DPIB for Playback stream as the periodic DMA Position-in- 1095ca590c1cSDharageswari R * Buffer Writes may be scheduled at the same time or later than 1096ca590c1cSDharageswari R * the MSI and does not guarantee to reflect the Position of the 1097ca590c1cSDharageswari R * last buffer that was transferred. Whereas DPIB register in 1098ca590c1cSDharageswari R * HAD space reflects the actual data that is transferred. 1099ca590c1cSDharageswari R * Use the position buffer for capture, as DPIB write gets 1100ca590c1cSDharageswari R * completed earlier than the actual data written to the DDR. 1101fdd85a05SHardik T Shah * 1102fdd85a05SHardik T Shah * For capture stream following workaround is required to fix the 1103fdd85a05SHardik T Shah * incorrect position reporting. 1104fdd85a05SHardik T Shah * 1105fdd85a05SHardik T Shah * 1. Wait for 20us before reading the DMA position in buffer once 1106fdd85a05SHardik T Shah * the interrupt is generated for stream completion as update happens 1107fdd85a05SHardik T Shah * on the HDA frame boundary i.e. 20.833uSec. 1108fdd85a05SHardik T Shah * 2. Read DPIB register to flush the DMA position value. This dummy 1109fdd85a05SHardik T Shah * read is required to flush DMA position value. 1110fdd85a05SHardik T Shah * 3. Read the DMA Position-in-Buffer. This value now will be equal to 1111fdd85a05SHardik T Shah * or greater than period boundary. 1112ca590c1cSDharageswari R */ 1113fdd85a05SHardik T Shah 1114fdd85a05SHardik T Shah if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 1115ca590c1cSDharageswari R pos = readl(ebus->bus.remap_addr + AZX_REG_VS_SDXDPIB_XBASE + 1116ca590c1cSDharageswari R (AZX_REG_VS_SDXDPIB_XINTERVAL * 1117ca590c1cSDharageswari R hdac_stream(hstream)->index)); 1118fdd85a05SHardik T Shah } else { 1119fdd85a05SHardik T Shah udelay(20); 1120fdd85a05SHardik T Shah readl(ebus->bus.remap_addr + 1121fdd85a05SHardik T Shah AZX_REG_VS_SDXDPIB_XBASE + 1122fdd85a05SHardik T Shah (AZX_REG_VS_SDXDPIB_XINTERVAL * 1123fdd85a05SHardik T Shah hdac_stream(hstream)->index)); 1124a40e693cSJeeja KP pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream)); 1125fdd85a05SHardik T Shah } 1126a40e693cSJeeja KP 1127a40e693cSJeeja KP if (pos >= hdac_stream(hstream)->bufsize) 1128a40e693cSJeeja KP pos = 0; 1129a40e693cSJeeja KP 11307b96144dSJeeja KP return bytes_to_frames(substream->runtime, pos); 1131a40e693cSJeeja KP } 1132a40e693cSJeeja KP 1133a40e693cSJeeja KP static u64 skl_adjust_codec_delay(struct snd_pcm_substream *substream, 1134a40e693cSJeeja KP u64 nsec) 1135a40e693cSJeeja KP { 1136a40e693cSJeeja KP struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 1137a40e693cSJeeja KP struct snd_soc_dai *codec_dai = rtd->codec_dai; 1138a40e693cSJeeja KP u64 codec_frames, codec_nsecs; 1139a40e693cSJeeja KP 1140a40e693cSJeeja KP if (!codec_dai->driver->ops->delay) 1141a40e693cSJeeja KP return nsec; 1142a40e693cSJeeja KP 1143a40e693cSJeeja KP codec_frames = codec_dai->driver->ops->delay(substream, codec_dai); 1144a40e693cSJeeja KP codec_nsecs = div_u64(codec_frames * 1000000000LL, 1145a40e693cSJeeja KP substream->runtime->rate); 1146a40e693cSJeeja KP 1147a40e693cSJeeja KP if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 1148a40e693cSJeeja KP return nsec + codec_nsecs; 1149a40e693cSJeeja KP 1150a40e693cSJeeja KP return (nsec > codec_nsecs) ? nsec - codec_nsecs : 0; 1151a40e693cSJeeja KP } 1152a40e693cSJeeja KP 1153a40e693cSJeeja KP static int skl_get_time_info(struct snd_pcm_substream *substream, 1154a40e693cSJeeja KP struct timespec *system_ts, struct timespec *audio_ts, 1155a40e693cSJeeja KP struct snd_pcm_audio_tstamp_config *audio_tstamp_config, 1156a40e693cSJeeja KP struct snd_pcm_audio_tstamp_report *audio_tstamp_report) 1157a40e693cSJeeja KP { 1158a40e693cSJeeja KP struct hdac_ext_stream *sstream = get_hdac_ext_stream(substream); 1159a40e693cSJeeja KP struct hdac_stream *hstr = hdac_stream(sstream); 1160a40e693cSJeeja KP u64 nsec; 1161a40e693cSJeeja KP 1162a40e693cSJeeja KP if ((substream->runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_ATIME) && 1163a40e693cSJeeja KP (audio_tstamp_config->type_requested == SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK)) { 1164a40e693cSJeeja KP 1165a40e693cSJeeja KP snd_pcm_gettime(substream->runtime, system_ts); 1166a40e693cSJeeja KP 1167a40e693cSJeeja KP nsec = timecounter_read(&hstr->tc); 1168a40e693cSJeeja KP nsec = div_u64(nsec, 3); /* can be optimized */ 1169a40e693cSJeeja KP if (audio_tstamp_config->report_delay) 1170a40e693cSJeeja KP nsec = skl_adjust_codec_delay(substream, nsec); 1171a40e693cSJeeja KP 1172a40e693cSJeeja KP *audio_ts = ns_to_timespec(nsec); 1173a40e693cSJeeja KP 1174a40e693cSJeeja KP audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK; 1175a40e693cSJeeja KP audio_tstamp_report->accuracy_report = 1; /* rest of struct is valid */ 1176a40e693cSJeeja KP audio_tstamp_report->accuracy = 42; /* 24MHzWallClk == 42ns resolution */ 1177a40e693cSJeeja KP 1178a40e693cSJeeja KP } else { 1179a40e693cSJeeja KP audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT; 1180a40e693cSJeeja KP } 1181a40e693cSJeeja KP 1182a40e693cSJeeja KP return 0; 1183a40e693cSJeeja KP } 1184a40e693cSJeeja KP 1185115c7254SJulia Lawall static const struct snd_pcm_ops skl_platform_ops = { 1186a40e693cSJeeja KP .open = skl_platform_open, 1187a40e693cSJeeja KP .ioctl = snd_pcm_lib_ioctl, 1188a40e693cSJeeja KP .trigger = skl_platform_pcm_trigger, 1189a40e693cSJeeja KP .pointer = skl_platform_pcm_pointer, 1190a40e693cSJeeja KP .get_time_info = skl_get_time_info, 1191a40e693cSJeeja KP .mmap = snd_pcm_lib_default_mmap, 1192a40e693cSJeeja KP .page = snd_pcm_sgbuf_ops_page, 1193a40e693cSJeeja KP }; 1194a40e693cSJeeja KP 1195a40e693cSJeeja KP static void skl_pcm_free(struct snd_pcm *pcm) 1196a40e693cSJeeja KP { 1197a40e693cSJeeja KP snd_pcm_lib_preallocate_free_for_all(pcm); 1198a40e693cSJeeja KP } 1199a40e693cSJeeja KP 1200a40e693cSJeeja KP #define MAX_PREALLOC_SIZE (32 * 1024 * 1024) 1201a40e693cSJeeja KP 1202a40e693cSJeeja KP static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd) 1203a40e693cSJeeja KP { 1204a40e693cSJeeja KP struct snd_soc_dai *dai = rtd->cpu_dai; 1205a40e693cSJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); 1206a40e693cSJeeja KP struct snd_pcm *pcm = rtd->pcm; 1207a40e693cSJeeja KP unsigned int size; 1208a40e693cSJeeja KP int retval = 0; 1209a40e693cSJeeja KP struct skl *skl = ebus_to_skl(ebus); 1210a40e693cSJeeja KP 1211a40e693cSJeeja KP if (dai->driver->playback.channels_min || 1212a40e693cSJeeja KP dai->driver->capture.channels_min) { 1213a40e693cSJeeja KP /* buffer pre-allocation */ 1214a40e693cSJeeja KP size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024; 1215a40e693cSJeeja KP if (size > MAX_PREALLOC_SIZE) 1216a40e693cSJeeja KP size = MAX_PREALLOC_SIZE; 1217a40e693cSJeeja KP retval = snd_pcm_lib_preallocate_pages_for_all(pcm, 1218a40e693cSJeeja KP SNDRV_DMA_TYPE_DEV_SG, 1219a40e693cSJeeja KP snd_dma_pci_data(skl->pci), 1220a40e693cSJeeja KP size, MAX_PREALLOC_SIZE); 1221a40e693cSJeeja KP if (retval) { 122208458871SColin Ian King dev_err(dai->dev, "dma buffer allocation fail\n"); 1223a40e693cSJeeja KP return retval; 1224a40e693cSJeeja KP } 1225a40e693cSJeeja KP } 1226a40e693cSJeeja KP 1227a40e693cSJeeja KP return retval; 1228a40e693cSJeeja KP } 1229a40e693cSJeeja KP 1230b26199eaSJeeja KP static int skl_get_module_info(struct skl *skl, struct skl_module_cfg *mconfig) 1231b26199eaSJeeja KP { 1232b26199eaSJeeja KP struct skl_sst *ctx = skl->skl_sst; 123391fe0e70SJeeja KP struct skl_module_inst_id *pin_id; 123491fe0e70SJeeja KP uuid_le *uuid_mod, *uuid_tplg; 123591fe0e70SJeeja KP struct skl_module *skl_module; 1236b26199eaSJeeja KP struct uuid_module *module; 123791fe0e70SJeeja KP int i, ret = -EIO; 1238b26199eaSJeeja KP 1239b26199eaSJeeja KP uuid_mod = (uuid_le *)mconfig->guid; 1240b26199eaSJeeja KP 1241b26199eaSJeeja KP if (list_empty(&ctx->uuid_list)) { 1242b26199eaSJeeja KP dev_err(ctx->dev, "Module list is empty\n"); 1243b26199eaSJeeja KP return -EIO; 1244b26199eaSJeeja KP } 1245b26199eaSJeeja KP 1246b26199eaSJeeja KP list_for_each_entry(module, &ctx->uuid_list, list) { 1247b26199eaSJeeja KP if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) { 1248b26199eaSJeeja KP mconfig->id.module_id = module->id; 1249f6fa56e2SRamesh Babu if (mconfig->module) 1250f6fa56e2SRamesh Babu mconfig->module->loadable = module->is_loadable; 125191fe0e70SJeeja KP ret = 0; 125291fe0e70SJeeja KP break; 1253b26199eaSJeeja KP } 1254b26199eaSJeeja KP } 1255b26199eaSJeeja KP 125691fe0e70SJeeja KP if (ret) 125791fe0e70SJeeja KP return ret; 125891fe0e70SJeeja KP 125991fe0e70SJeeja KP uuid_mod = &module->uuid; 126091fe0e70SJeeja KP ret = -EIO; 126191fe0e70SJeeja KP for (i = 0; i < skl->nr_modules; i++) { 126291fe0e70SJeeja KP skl_module = skl->modules[i]; 126391fe0e70SJeeja KP uuid_tplg = &skl_module->uuid; 126491fe0e70SJeeja KP if (!uuid_le_cmp(*uuid_mod, *uuid_tplg)) { 126591fe0e70SJeeja KP mconfig->module = skl_module; 126691fe0e70SJeeja KP ret = 0; 126791fe0e70SJeeja KP break; 126891fe0e70SJeeja KP } 126991fe0e70SJeeja KP } 127091fe0e70SJeeja KP if (skl->nr_modules && ret) 127191fe0e70SJeeja KP return ret; 127291fe0e70SJeeja KP 127391fe0e70SJeeja KP list_for_each_entry(module, &ctx->uuid_list, list) { 127491fe0e70SJeeja KP for (i = 0; i < MAX_IN_QUEUE; i++) { 127591fe0e70SJeeja KP pin_id = &mconfig->m_in_pin[i].id; 127691fe0e70SJeeja KP if (!uuid_le_cmp(pin_id->mod_uuid, module->uuid)) 127791fe0e70SJeeja KP pin_id->module_id = module->id; 127891fe0e70SJeeja KP } 127991fe0e70SJeeja KP 128091fe0e70SJeeja KP for (i = 0; i < MAX_OUT_QUEUE; i++) { 128191fe0e70SJeeja KP pin_id = &mconfig->m_out_pin[i].id; 128291fe0e70SJeeja KP if (!uuid_le_cmp(pin_id->mod_uuid, module->uuid)) 128391fe0e70SJeeja KP pin_id->module_id = module->id; 128491fe0e70SJeeja KP } 128591fe0e70SJeeja KP } 128691fe0e70SJeeja KP 128791fe0e70SJeeja KP return 0; 1288b26199eaSJeeja KP } 1289b26199eaSJeeja KP 129064cb1d0aSVinod Koul static int skl_populate_modules(struct skl *skl) 129164cb1d0aSVinod Koul { 129264cb1d0aSVinod Koul struct skl_pipeline *p; 129364cb1d0aSVinod Koul struct skl_pipe_module *m; 129464cb1d0aSVinod Koul struct snd_soc_dapm_widget *w; 129564cb1d0aSVinod Koul struct skl_module_cfg *mconfig; 1296b26199eaSJeeja KP int ret = 0; 129764cb1d0aSVinod Koul 129864cb1d0aSVinod Koul list_for_each_entry(p, &skl->ppl_list, node) { 129964cb1d0aSVinod Koul list_for_each_entry(m, &p->pipe->w_list, node) { 130064cb1d0aSVinod Koul w = m->w; 130164cb1d0aSVinod Koul mconfig = w->priv; 130264cb1d0aSVinod Koul 1303b26199eaSJeeja KP ret = skl_get_module_info(skl, mconfig); 130464cb1d0aSVinod Koul if (ret < 0) { 130564cb1d0aSVinod Koul dev_err(skl->skl_sst->dev, 1306b26199eaSJeeja KP "query module info failed\n"); 1307b26199eaSJeeja KP return ret; 130864cb1d0aSVinod Koul } 130964cb1d0aSVinod Koul } 131064cb1d0aSVinod Koul } 1311b26199eaSJeeja KP 131264cb1d0aSVinod Koul return ret; 131364cb1d0aSVinod Koul } 131464cb1d0aSVinod Koul 1315b663a8c5SJeeja KP static int skl_platform_soc_probe(struct snd_soc_platform *platform) 1316b663a8c5SJeeja KP { 1317b663a8c5SJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(platform->dev); 1318fe3f4442SDharageswari R struct skl *skl = ebus_to_skl(ebus); 131978cdbbdaSVinod Koul const struct skl_dsp_ops *ops; 1320fe3f4442SDharageswari R int ret; 1321b663a8c5SJeeja KP 132278cdbbdaSVinod Koul pm_runtime_get_sync(platform->dev); 1323ec8ae570SVinod Koul if ((ebus_to_hbus(ebus))->ppcap) { 13245cdf6c09SVinod Koul skl->platform = platform; 13255cdf6c09SVinod Koul 13265cdf6c09SVinod Koul /* init debugfs */ 13275cdf6c09SVinod Koul skl->debugfs = skl_debugfs_init(skl); 13285cdf6c09SVinod Koul 1329fe3f4442SDharageswari R ret = skl_tplg_init(platform, ebus); 1330fe3f4442SDharageswari R if (ret < 0) { 1331fe3f4442SDharageswari R dev_err(platform->dev, "Failed to init topology!\n"); 1332fe3f4442SDharageswari R return ret; 1333fe3f4442SDharageswari R } 133478cdbbdaSVinod Koul 133578cdbbdaSVinod Koul /* load the firmwares, since all is set */ 133678cdbbdaSVinod Koul ops = skl_get_dsp_ops(skl->pci->device); 133778cdbbdaSVinod Koul if (!ops) 133878cdbbdaSVinod Koul return -EIO; 133978cdbbdaSVinod Koul 134078cdbbdaSVinod Koul if (skl->skl_sst->is_first_boot == false) { 134178cdbbdaSVinod Koul dev_err(platform->dev, "DSP reports first boot done!!!\n"); 134278cdbbdaSVinod Koul return -EIO; 1343fe3f4442SDharageswari R } 1344b663a8c5SJeeja KP 1345d5cc0a1fSPardha Saradhi K /* disable dynamic clock gating during fw and lib download */ 1346d5cc0a1fSPardha Saradhi K skl->skl_sst->enable_miscbdcge(platform->dev, false); 1347d5cc0a1fSPardha Saradhi K 134878cdbbdaSVinod Koul ret = ops->init_fw(platform->dev, skl->skl_sst); 1349d5cc0a1fSPardha Saradhi K skl->skl_sst->enable_miscbdcge(platform->dev, true); 135078cdbbdaSVinod Koul if (ret < 0) { 135178cdbbdaSVinod Koul dev_err(platform->dev, "Failed to boot first fw: %d\n", ret); 135278cdbbdaSVinod Koul return ret; 135378cdbbdaSVinod Koul } 135464cb1d0aSVinod Koul skl_populate_modules(skl); 1355a26a3f53SPardha Saradhi K skl->skl_sst->update_d0i3c = skl_update_d0i3c; 1356cb729d80SG Kranthi skl_dsp_enable_notification(skl->skl_sst, false); 13579452314dSPradeep Tewani 13589452314dSPradeep Tewani if (skl->cfg.astate_cfg != NULL) { 13599452314dSPradeep Tewani skl_dsp_set_astate_cfg(skl->skl_sst, 13609452314dSPradeep Tewani skl->cfg.astate_cfg->count, 13619452314dSPradeep Tewani skl->cfg.astate_cfg); 13629452314dSPradeep Tewani } 136378cdbbdaSVinod Koul } 136478cdbbdaSVinod Koul pm_runtime_mark_last_busy(platform->dev); 136578cdbbdaSVinod Koul pm_runtime_put_autosuspend(platform->dev); 136678cdbbdaSVinod Koul 1367b663a8c5SJeeja KP return 0; 1368b663a8c5SJeeja KP } 136980cc4df8SBhumika Goyal static const struct snd_soc_platform_driver skl_platform_drv = { 1370b663a8c5SJeeja KP .probe = skl_platform_soc_probe, 1371a40e693cSJeeja KP .ops = &skl_platform_ops, 1372a40e693cSJeeja KP .pcm_new = skl_pcm_new, 1373a40e693cSJeeja KP .pcm_free = skl_pcm_free, 1374a40e693cSJeeja KP }; 1375a40e693cSJeeja KP 1376a40e693cSJeeja KP static const struct snd_soc_component_driver skl_component = { 1377a40e693cSJeeja KP .name = "pcm", 1378a40e693cSJeeja KP }; 1379a40e693cSJeeja KP 1380a40e693cSJeeja KP int skl_platform_register(struct device *dev) 1381a40e693cSJeeja KP { 1382a40e693cSJeeja KP int ret; 1383b663a8c5SJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dev); 1384b663a8c5SJeeja KP struct skl *skl = ebus_to_skl(ebus); 1385c3ae22e3SGuneshwor Singh struct snd_soc_dai_driver *dais; 1386c3ae22e3SGuneshwor Singh int num_dais = ARRAY_SIZE(skl_platform_dai); 1387b663a8c5SJeeja KP 1388b663a8c5SJeeja KP INIT_LIST_HEAD(&skl->ppl_list); 1389b8c722ddSJeeja KP INIT_LIST_HEAD(&skl->bind_list); 1390a40e693cSJeeja KP 1391a40e693cSJeeja KP ret = snd_soc_register_platform(dev, &skl_platform_drv); 1392a40e693cSJeeja KP if (ret) { 1393a40e693cSJeeja KP dev_err(dev, "soc platform registration failed %d\n", ret); 1394a40e693cSJeeja KP return ret; 1395a40e693cSJeeja KP } 1396c3ae22e3SGuneshwor Singh 1397c3ae22e3SGuneshwor Singh skl->dais = kmemdup(skl_platform_dai, sizeof(skl_platform_dai), 1398c3ae22e3SGuneshwor Singh GFP_KERNEL); 1399c3ae22e3SGuneshwor Singh if (!skl->dais) { 1400c3ae22e3SGuneshwor Singh ret = -ENOMEM; 1401c3ae22e3SGuneshwor Singh goto err; 1402a40e693cSJeeja KP } 1403a40e693cSJeeja KP 1404c3ae22e3SGuneshwor Singh if (!skl->use_tplg_pcm) { 1405c3ae22e3SGuneshwor Singh dais = krealloc(skl->dais, sizeof(skl_fe_dai) + 1406c3ae22e3SGuneshwor Singh sizeof(skl_platform_dai), GFP_KERNEL); 1407c3ae22e3SGuneshwor Singh if (!dais) { 1408c3ae22e3SGuneshwor Singh ret = -ENOMEM; 1409c3ae22e3SGuneshwor Singh goto err; 1410c3ae22e3SGuneshwor Singh } 1411c3ae22e3SGuneshwor Singh 1412c3ae22e3SGuneshwor Singh skl->dais = dais; 1413c3ae22e3SGuneshwor Singh memcpy(&skl->dais[ARRAY_SIZE(skl_platform_dai)], skl_fe_dai, 1414c3ae22e3SGuneshwor Singh sizeof(skl_fe_dai)); 1415c3ae22e3SGuneshwor Singh num_dais += ARRAY_SIZE(skl_fe_dai); 1416c3ae22e3SGuneshwor Singh } 1417c3ae22e3SGuneshwor Singh 1418c3ae22e3SGuneshwor Singh ret = snd_soc_register_component(dev, &skl_component, 1419c3ae22e3SGuneshwor Singh skl->dais, num_dais); 1420c3ae22e3SGuneshwor Singh if (ret) { 1421c3ae22e3SGuneshwor Singh dev_err(dev, "soc component registration failed %d\n", ret); 1422c3ae22e3SGuneshwor Singh goto err; 1423c3ae22e3SGuneshwor Singh } 1424c3ae22e3SGuneshwor Singh 1425c3ae22e3SGuneshwor Singh return 0; 1426c3ae22e3SGuneshwor Singh err: 1427c3ae22e3SGuneshwor Singh snd_soc_unregister_platform(dev); 1428a40e693cSJeeja KP return ret; 1429a40e693cSJeeja KP 1430a40e693cSJeeja KP } 1431a40e693cSJeeja KP 1432a40e693cSJeeja KP int skl_platform_unregister(struct device *dev) 1433a40e693cSJeeja KP { 1434b8c722ddSJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dev); 1435b8c722ddSJeeja KP struct skl *skl = ebus_to_skl(ebus); 1436550b349aSDan Carpenter struct skl_module_deferred_bind *modules, *tmp; 1437b8c722ddSJeeja KP 1438b8c722ddSJeeja KP if (!list_empty(&skl->bind_list)) { 1439550b349aSDan Carpenter list_for_each_entry_safe(modules, tmp, &skl->bind_list, node) { 1440b8c722ddSJeeja KP list_del(&modules->node); 1441b8c722ddSJeeja KP kfree(modules); 1442b8c722ddSJeeja KP } 1443b8c722ddSJeeja KP } 1444b8c722ddSJeeja KP 1445a40e693cSJeeja KP snd_soc_unregister_component(dev); 1446a40e693cSJeeja KP snd_soc_unregister_platform(dev); 1447c3ae22e3SGuneshwor Singh kfree(skl->dais); 1448c3ae22e3SGuneshwor Singh 1449a40e693cSJeeja KP return 0; 1450a40e693cSJeeja KP } 1451