162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * skl-pcm.c -ASoC HDA Platform driver file implementing PCM functionality 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2014-2015 Intel Corp 662306a36Sopenharmony_ci * Author: Jeeja KP <jeeja.kp@intel.com> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/pci.h> 1462306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1562306a36Sopenharmony_ci#include <linux/delay.h> 1662306a36Sopenharmony_ci#include <sound/hdaudio.h> 1762306a36Sopenharmony_ci#include <sound/pcm_params.h> 1862306a36Sopenharmony_ci#include <sound/soc.h> 1962306a36Sopenharmony_ci#include "skl.h" 2062306a36Sopenharmony_ci#include "skl-topology.h" 2162306a36Sopenharmony_ci#include "skl-sst-dsp.h" 2262306a36Sopenharmony_ci#include "skl-sst-ipc.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define HDA_MONO 1 2562306a36Sopenharmony_ci#define HDA_STEREO 2 2662306a36Sopenharmony_ci#define HDA_QUAD 4 2762306a36Sopenharmony_ci#define HDA_MAX 8 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic const struct snd_pcm_hardware azx_pcm_hw = { 3062306a36Sopenharmony_ci .info = (SNDRV_PCM_INFO_MMAP | 3162306a36Sopenharmony_ci SNDRV_PCM_INFO_INTERLEAVED | 3262306a36Sopenharmony_ci SNDRV_PCM_INFO_BLOCK_TRANSFER | 3362306a36Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 3462306a36Sopenharmony_ci SNDRV_PCM_INFO_PAUSE | 3562306a36Sopenharmony_ci SNDRV_PCM_INFO_RESUME | 3662306a36Sopenharmony_ci SNDRV_PCM_INFO_SYNC_START | 3762306a36Sopenharmony_ci SNDRV_PCM_INFO_HAS_WALL_CLOCK | /* legacy */ 3862306a36Sopenharmony_ci SNDRV_PCM_INFO_HAS_LINK_ATIME | 3962306a36Sopenharmony_ci SNDRV_PCM_INFO_NO_PERIOD_WAKEUP), 4062306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | 4162306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE | 4262306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE, 4362306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | 4462306a36Sopenharmony_ci SNDRV_PCM_RATE_8000, 4562306a36Sopenharmony_ci .rate_min = 8000, 4662306a36Sopenharmony_ci .rate_max = 48000, 4762306a36Sopenharmony_ci .channels_min = 1, 4862306a36Sopenharmony_ci .channels_max = 8, 4962306a36Sopenharmony_ci .buffer_bytes_max = AZX_MAX_BUF_SIZE, 5062306a36Sopenharmony_ci .period_bytes_min = 128, 5162306a36Sopenharmony_ci .period_bytes_max = AZX_MAX_BUF_SIZE / 2, 5262306a36Sopenharmony_ci .periods_min = 2, 5362306a36Sopenharmony_ci .periods_max = AZX_MAX_FRAG, 5462306a36Sopenharmony_ci .fifo_size = 0, 5562306a36Sopenharmony_ci}; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic inline 5862306a36Sopenharmony_cistruct hdac_ext_stream *get_hdac_ext_stream(struct snd_pcm_substream *substream) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci return substream->runtime->private_data; 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic struct hdac_bus *get_bus_ctx(struct snd_pcm_substream *substream) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); 6662306a36Sopenharmony_ci struct hdac_stream *hstream = hdac_stream(stream); 6762306a36Sopenharmony_ci struct hdac_bus *bus = hstream->bus; 6862306a36Sopenharmony_ci return bus; 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic int skl_substream_alloc_pages(struct hdac_bus *bus, 7262306a36Sopenharmony_ci struct snd_pcm_substream *substream, 7362306a36Sopenharmony_ci size_t size) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci hdac_stream(stream)->bufsize = 0; 7862306a36Sopenharmony_ci hdac_stream(stream)->period_bytes = 0; 7962306a36Sopenharmony_ci hdac_stream(stream)->format_val = 0; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci return 0; 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic void skl_set_pcm_constrains(struct hdac_bus *bus, 8562306a36Sopenharmony_ci struct snd_pcm_runtime *runtime) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci /* avoid wrap-around with wall-clock */ 9062306a36Sopenharmony_ci snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME, 9162306a36Sopenharmony_ci 20, 178000000); 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic enum hdac_ext_stream_type skl_get_host_stream_type(struct hdac_bus *bus) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci if (bus->ppcap) 9762306a36Sopenharmony_ci return HDAC_EXT_STREAM_TYPE_HOST; 9862306a36Sopenharmony_ci else 9962306a36Sopenharmony_ci return HDAC_EXT_STREAM_TYPE_COUPLED; 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci/* 10362306a36Sopenharmony_ci * check if the stream opened is marked as ignore_suspend by machine, if so 10462306a36Sopenharmony_ci * then enable suspend_active refcount 10562306a36Sopenharmony_ci * 10662306a36Sopenharmony_ci * The count supend_active does not need lock as it is used in open/close 10762306a36Sopenharmony_ci * and suspend context 10862306a36Sopenharmony_ci */ 10962306a36Sopenharmony_cistatic void skl_set_suspend_active(struct snd_pcm_substream *substream, 11062306a36Sopenharmony_ci struct snd_soc_dai *dai, bool enable) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci struct hdac_bus *bus = dev_get_drvdata(dai->dev); 11362306a36Sopenharmony_ci struct snd_soc_dapm_widget *w; 11462306a36Sopenharmony_ci struct skl_dev *skl = bus_to_skl(bus); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci w = snd_soc_dai_get_widget(dai, substream->stream); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci if (w->ignore_suspend && enable) 11962306a36Sopenharmony_ci skl->supend_active++; 12062306a36Sopenharmony_ci else if (w->ignore_suspend && !enable) 12162306a36Sopenharmony_ci skl->supend_active--; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ciint skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct hdac_bus *bus = dev_get_drvdata(dev); 12762306a36Sopenharmony_ci struct skl_dev *skl = bus_to_skl(bus); 12862306a36Sopenharmony_ci unsigned int format_val; 12962306a36Sopenharmony_ci struct hdac_stream *hstream; 13062306a36Sopenharmony_ci struct hdac_ext_stream *stream; 13162306a36Sopenharmony_ci int err; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci hstream = snd_hdac_get_stream(bus, params->stream, 13462306a36Sopenharmony_ci params->host_dma_id + 1); 13562306a36Sopenharmony_ci if (!hstream) 13662306a36Sopenharmony_ci return -EINVAL; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci stream = stream_to_hdac_ext_stream(hstream); 13962306a36Sopenharmony_ci snd_hdac_ext_stream_decouple(bus, stream, true); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci format_val = snd_hdac_calc_stream_format(params->s_freq, 14262306a36Sopenharmony_ci params->ch, params->format, params->host_bps, 0); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n", 14562306a36Sopenharmony_ci format_val, params->s_freq, params->ch, params->format); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci snd_hdac_stream_reset(hdac_stream(stream)); 14862306a36Sopenharmony_ci err = snd_hdac_stream_set_params(hdac_stream(stream), format_val); 14962306a36Sopenharmony_ci if (err < 0) 15062306a36Sopenharmony_ci return err; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci /* 15362306a36Sopenharmony_ci * The recommended SDxFMT programming sequence for BXT 15462306a36Sopenharmony_ci * platforms is to couple the stream before writing the format 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_ci if (HDA_CONTROLLER_IS_APL(skl->pci)) { 15762306a36Sopenharmony_ci snd_hdac_ext_stream_decouple(bus, stream, false); 15862306a36Sopenharmony_ci err = snd_hdac_stream_setup(hdac_stream(stream)); 15962306a36Sopenharmony_ci snd_hdac_ext_stream_decouple(bus, stream, true); 16062306a36Sopenharmony_ci } else { 16162306a36Sopenharmony_ci err = snd_hdac_stream_setup(hdac_stream(stream)); 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci if (err < 0) 16562306a36Sopenharmony_ci return err; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci hdac_stream(stream)->prepared = 1; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci return 0; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ciint skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct hdac_bus *bus = dev_get_drvdata(dev); 17562306a36Sopenharmony_ci unsigned int format_val; 17662306a36Sopenharmony_ci struct hdac_stream *hstream; 17762306a36Sopenharmony_ci struct hdac_ext_stream *stream; 17862306a36Sopenharmony_ci struct hdac_ext_link *link; 17962306a36Sopenharmony_ci unsigned char stream_tag; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci hstream = snd_hdac_get_stream(bus, params->stream, 18262306a36Sopenharmony_ci params->link_dma_id + 1); 18362306a36Sopenharmony_ci if (!hstream) 18462306a36Sopenharmony_ci return -EINVAL; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci stream = stream_to_hdac_ext_stream(hstream); 18762306a36Sopenharmony_ci snd_hdac_ext_stream_decouple(bus, stream, true); 18862306a36Sopenharmony_ci format_val = snd_hdac_calc_stream_format(params->s_freq, params->ch, 18962306a36Sopenharmony_ci params->format, params->link_bps, 0); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n", 19262306a36Sopenharmony_ci format_val, params->s_freq, params->ch, params->format); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci snd_hdac_ext_stream_reset(stream); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci snd_hdac_ext_stream_setup(stream, format_val); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci stream_tag = hstream->stream_tag; 19962306a36Sopenharmony_ci if (stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK) { 20062306a36Sopenharmony_ci list_for_each_entry(link, &bus->hlink_list, list) { 20162306a36Sopenharmony_ci if (link->index == params->link_index) 20262306a36Sopenharmony_ci snd_hdac_ext_bus_link_set_stream_id(link, 20362306a36Sopenharmony_ci stream_tag); 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci stream->link_prepared = 1; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci return 0; 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic int skl_pcm_open(struct snd_pcm_substream *substream, 21362306a36Sopenharmony_ci struct snd_soc_dai *dai) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci struct hdac_bus *bus = dev_get_drvdata(dai->dev); 21662306a36Sopenharmony_ci struct hdac_ext_stream *stream; 21762306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 21862306a36Sopenharmony_ci struct skl_dma_params *dma_params; 21962306a36Sopenharmony_ci struct skl_dev *skl = get_skl_ctx(dai->dev); 22062306a36Sopenharmony_ci struct skl_module_cfg *mconfig; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci stream = snd_hdac_ext_stream_assign(bus, substream, 22562306a36Sopenharmony_ci skl_get_host_stream_type(bus)); 22662306a36Sopenharmony_ci if (stream == NULL) 22762306a36Sopenharmony_ci return -EBUSY; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci skl_set_pcm_constrains(bus, runtime); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci /* 23262306a36Sopenharmony_ci * disable WALLCLOCK timestamps for capture streams 23362306a36Sopenharmony_ci * until we figure out how to handle digital inputs 23462306a36Sopenharmony_ci */ 23562306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 23662306a36Sopenharmony_ci runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_WALL_CLOCK; /* legacy */ 23762306a36Sopenharmony_ci runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_LINK_ATIME; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci runtime->private_data = stream; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci dma_params = kzalloc(sizeof(*dma_params), GFP_KERNEL); 24362306a36Sopenharmony_ci if (!dma_params) 24462306a36Sopenharmony_ci return -ENOMEM; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci dma_params->stream_tag = hdac_stream(stream)->stream_tag; 24762306a36Sopenharmony_ci snd_soc_dai_set_dma_data(dai, substream, dma_params); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci dev_dbg(dai->dev, "stream tag set in dma params=%d\n", 25062306a36Sopenharmony_ci dma_params->stream_tag); 25162306a36Sopenharmony_ci skl_set_suspend_active(substream, dai, true); 25262306a36Sopenharmony_ci snd_pcm_set_sync(substream); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); 25562306a36Sopenharmony_ci if (!mconfig) { 25662306a36Sopenharmony_ci kfree(dma_params); 25762306a36Sopenharmony_ci return -EINVAL; 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci skl_tplg_d0i3_get(skl, mconfig->d0i3_caps); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci return 0; 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic int skl_pcm_prepare(struct snd_pcm_substream *substream, 26662306a36Sopenharmony_ci struct snd_soc_dai *dai) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci struct skl_dev *skl = get_skl_ctx(dai->dev); 26962306a36Sopenharmony_ci struct skl_module_cfg *mconfig; 27062306a36Sopenharmony_ci int ret; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* 27762306a36Sopenharmony_ci * In case of XRUN recovery or in the case when the application 27862306a36Sopenharmony_ci * calls prepare another time, reset the FW pipe to clean state 27962306a36Sopenharmony_ci */ 28062306a36Sopenharmony_ci if (mconfig && 28162306a36Sopenharmony_ci (substream->runtime->state == SNDRV_PCM_STATE_XRUN || 28262306a36Sopenharmony_ci mconfig->pipe->state == SKL_PIPE_CREATED || 28362306a36Sopenharmony_ci mconfig->pipe->state == SKL_PIPE_PAUSED)) { 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci ret = skl_reset_pipe(skl, mconfig->pipe); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (ret < 0) 28862306a36Sopenharmony_ci return ret; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci ret = skl_pcm_host_dma_prepare(dai->dev, 29162306a36Sopenharmony_ci mconfig->pipe->p_params); 29262306a36Sopenharmony_ci if (ret < 0) 29362306a36Sopenharmony_ci return ret; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci return 0; 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic int skl_pcm_hw_params(struct snd_pcm_substream *substream, 30062306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 30162306a36Sopenharmony_ci struct snd_soc_dai *dai) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci struct hdac_bus *bus = dev_get_drvdata(dai->dev); 30462306a36Sopenharmony_ci struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); 30562306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 30662306a36Sopenharmony_ci struct skl_pipe_params p_params = {0}; 30762306a36Sopenharmony_ci struct skl_module_cfg *m_cfg; 30862306a36Sopenharmony_ci int ret, dma_id; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); 31162306a36Sopenharmony_ci ret = skl_substream_alloc_pages(bus, substream, 31262306a36Sopenharmony_ci params_buffer_bytes(params)); 31362306a36Sopenharmony_ci if (ret < 0) 31462306a36Sopenharmony_ci return ret; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci dev_dbg(dai->dev, "format_val, rate=%d, ch=%d, format=%d\n", 31762306a36Sopenharmony_ci runtime->rate, runtime->channels, runtime->format); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci dma_id = hdac_stream(stream)->stream_tag - 1; 32062306a36Sopenharmony_ci dev_dbg(dai->dev, "dma_id=%d\n", dma_id); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci p_params.s_fmt = snd_pcm_format_width(params_format(params)); 32362306a36Sopenharmony_ci p_params.s_cont = snd_pcm_format_physical_width(params_format(params)); 32462306a36Sopenharmony_ci p_params.ch = params_channels(params); 32562306a36Sopenharmony_ci p_params.s_freq = params_rate(params); 32662306a36Sopenharmony_ci p_params.host_dma_id = dma_id; 32762306a36Sopenharmony_ci p_params.stream = substream->stream; 32862306a36Sopenharmony_ci p_params.format = params_format(params); 32962306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 33062306a36Sopenharmony_ci p_params.host_bps = dai->driver->playback.sig_bits; 33162306a36Sopenharmony_ci else 33262306a36Sopenharmony_ci p_params.host_bps = dai->driver->capture.sig_bits; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci m_cfg = skl_tplg_fe_get_cpr_module(dai, p_params.stream); 33662306a36Sopenharmony_ci if (m_cfg) 33762306a36Sopenharmony_ci skl_tplg_update_pipe_params(dai->dev, m_cfg, &p_params); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci return 0; 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic void skl_pcm_close(struct snd_pcm_substream *substream, 34362306a36Sopenharmony_ci struct snd_soc_dai *dai) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); 34662306a36Sopenharmony_ci struct hdac_bus *bus = dev_get_drvdata(dai->dev); 34762306a36Sopenharmony_ci struct skl_dma_params *dma_params = NULL; 34862306a36Sopenharmony_ci struct skl_dev *skl = bus_to_skl(bus); 34962306a36Sopenharmony_ci struct skl_module_cfg *mconfig; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci snd_hdac_ext_stream_release(stream, skl_get_host_stream_type(bus)); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci dma_params = snd_soc_dai_get_dma_data(dai, substream); 35662306a36Sopenharmony_ci /* 35762306a36Sopenharmony_ci * now we should set this to NULL as we are freeing by the 35862306a36Sopenharmony_ci * dma_params 35962306a36Sopenharmony_ci */ 36062306a36Sopenharmony_ci snd_soc_dai_set_dma_data(dai, substream, NULL); 36162306a36Sopenharmony_ci skl_set_suspend_active(substream, dai, false); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci /* 36462306a36Sopenharmony_ci * check if close is for "Reference Pin" and set back the 36562306a36Sopenharmony_ci * CGCTL.MISCBDCGE if disabled by driver 36662306a36Sopenharmony_ci */ 36762306a36Sopenharmony_ci if (!strncmp(dai->name, "Reference Pin", 13) && 36862306a36Sopenharmony_ci skl->miscbdcg_disabled) { 36962306a36Sopenharmony_ci skl->enable_miscbdcge(dai->dev, true); 37062306a36Sopenharmony_ci skl->miscbdcg_disabled = false; 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); 37462306a36Sopenharmony_ci if (mconfig) 37562306a36Sopenharmony_ci skl_tplg_d0i3_put(skl, mconfig->d0i3_caps); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci kfree(dma_params); 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic int skl_pcm_hw_free(struct snd_pcm_substream *substream, 38162306a36Sopenharmony_ci struct snd_soc_dai *dai) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); 38462306a36Sopenharmony_ci struct skl_dev *skl = get_skl_ctx(dai->dev); 38562306a36Sopenharmony_ci struct skl_module_cfg *mconfig; 38662306a36Sopenharmony_ci int ret; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci if (mconfig) { 39362306a36Sopenharmony_ci ret = skl_reset_pipe(skl, mconfig->pipe); 39462306a36Sopenharmony_ci if (ret < 0) 39562306a36Sopenharmony_ci dev_err(dai->dev, "%s:Reset failed ret =%d", 39662306a36Sopenharmony_ci __func__, ret); 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci snd_hdac_stream_cleanup(hdac_stream(stream)); 40062306a36Sopenharmony_ci hdac_stream(stream)->prepared = 0; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci return 0; 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_cistatic int skl_be_hw_params(struct snd_pcm_substream *substream, 40662306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 40762306a36Sopenharmony_ci struct snd_soc_dai *dai) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci struct skl_pipe_params p_params = {0}; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci p_params.s_fmt = snd_pcm_format_width(params_format(params)); 41262306a36Sopenharmony_ci p_params.s_cont = snd_pcm_format_physical_width(params_format(params)); 41362306a36Sopenharmony_ci p_params.ch = params_channels(params); 41462306a36Sopenharmony_ci p_params.s_freq = params_rate(params); 41562306a36Sopenharmony_ci p_params.stream = substream->stream; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci return skl_tplg_be_update_params(dai, &p_params); 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_cistatic int skl_decoupled_trigger(struct snd_pcm_substream *substream, 42162306a36Sopenharmony_ci int cmd) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci struct hdac_bus *bus = get_bus_ctx(substream); 42462306a36Sopenharmony_ci struct hdac_ext_stream *stream; 42562306a36Sopenharmony_ci int start; 42662306a36Sopenharmony_ci unsigned long cookie; 42762306a36Sopenharmony_ci struct hdac_stream *hstr; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci stream = get_hdac_ext_stream(substream); 43062306a36Sopenharmony_ci hstr = hdac_stream(stream); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci if (!hstr->prepared) 43362306a36Sopenharmony_ci return -EPIPE; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci switch (cmd) { 43662306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 43762306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 43862306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 43962306a36Sopenharmony_ci start = 1; 44062306a36Sopenharmony_ci break; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 44362306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 44462306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 44562306a36Sopenharmony_ci start = 0; 44662306a36Sopenharmony_ci break; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci default: 44962306a36Sopenharmony_ci return -EINVAL; 45062306a36Sopenharmony_ci } 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci spin_lock_irqsave(&bus->reg_lock, cookie); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci if (start) { 45562306a36Sopenharmony_ci snd_hdac_stream_start(hdac_stream(stream)); 45662306a36Sopenharmony_ci snd_hdac_stream_timecounter_init(hstr, 0); 45762306a36Sopenharmony_ci } else { 45862306a36Sopenharmony_ci snd_hdac_stream_stop(hdac_stream(stream)); 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci spin_unlock_irqrestore(&bus->reg_lock, cookie); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci return 0; 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistatic int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, 46762306a36Sopenharmony_ci struct snd_soc_dai *dai) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci struct skl_dev *skl = get_skl_ctx(dai->dev); 47062306a36Sopenharmony_ci struct skl_module_cfg *mconfig; 47162306a36Sopenharmony_ci struct hdac_bus *bus = get_bus_ctx(substream); 47262306a36Sopenharmony_ci struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); 47362306a36Sopenharmony_ci struct hdac_stream *hstream = hdac_stream(stream); 47462306a36Sopenharmony_ci struct snd_soc_dapm_widget *w; 47562306a36Sopenharmony_ci int ret; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); 47862306a36Sopenharmony_ci if (!mconfig) 47962306a36Sopenharmony_ci return -EIO; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci w = snd_soc_dai_get_widget(dai, substream->stream); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci switch (cmd) { 48462306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 48562306a36Sopenharmony_ci if (!w->ignore_suspend) { 48662306a36Sopenharmony_ci /* 48762306a36Sopenharmony_ci * enable DMA Resume enable bit for the stream, set the 48862306a36Sopenharmony_ci * dpib & lpib position to resume before starting the 48962306a36Sopenharmony_ci * DMA 49062306a36Sopenharmony_ci */ 49162306a36Sopenharmony_ci snd_hdac_stream_drsm_enable(bus, true, hstream->index); 49262306a36Sopenharmony_ci snd_hdac_stream_set_dpibr(bus, hstream, hstream->lpib); 49362306a36Sopenharmony_ci snd_hdac_stream_set_lpib(hstream, hstream->lpib); 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci fallthrough; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 49862306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 49962306a36Sopenharmony_ci /* 50062306a36Sopenharmony_ci * Start HOST DMA and Start FE Pipe.This is to make sure that 50162306a36Sopenharmony_ci * there are no underrun/overrun in the case when the FE 50262306a36Sopenharmony_ci * pipeline is started but there is a delay in starting the 50362306a36Sopenharmony_ci * DMA channel on the host. 50462306a36Sopenharmony_ci */ 50562306a36Sopenharmony_ci ret = skl_decoupled_trigger(substream, cmd); 50662306a36Sopenharmony_ci if (ret < 0) 50762306a36Sopenharmony_ci return ret; 50862306a36Sopenharmony_ci return skl_run_pipe(skl, mconfig->pipe); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 51162306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 51262306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 51362306a36Sopenharmony_ci /* 51462306a36Sopenharmony_ci * Stop FE Pipe first and stop DMA. This is to make sure that 51562306a36Sopenharmony_ci * there are no underrun/overrun in the case if there is a delay 51662306a36Sopenharmony_ci * between the two operations. 51762306a36Sopenharmony_ci */ 51862306a36Sopenharmony_ci ret = skl_stop_pipe(skl, mconfig->pipe); 51962306a36Sopenharmony_ci if (ret < 0) 52062306a36Sopenharmony_ci return ret; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci ret = skl_decoupled_trigger(substream, cmd); 52362306a36Sopenharmony_ci if ((cmd == SNDRV_PCM_TRIGGER_SUSPEND) && !w->ignore_suspend) { 52462306a36Sopenharmony_ci /* save the dpib and lpib positions */ 52562306a36Sopenharmony_ci hstream->dpib = readl(bus->remap_addr + 52662306a36Sopenharmony_ci AZX_REG_VS_SDXDPIB_XBASE + 52762306a36Sopenharmony_ci (AZX_REG_VS_SDXDPIB_XINTERVAL * 52862306a36Sopenharmony_ci hstream->index)); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci hstream->lpib = snd_hdac_stream_get_pos_lpib(hstream); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci snd_hdac_ext_stream_decouple(bus, stream, false); 53362306a36Sopenharmony_ci } 53462306a36Sopenharmony_ci break; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci default: 53762306a36Sopenharmony_ci return -EINVAL; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci return 0; 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_cistatic int skl_link_hw_params(struct snd_pcm_substream *substream, 54562306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 54662306a36Sopenharmony_ci struct snd_soc_dai *dai) 54762306a36Sopenharmony_ci{ 54862306a36Sopenharmony_ci struct hdac_bus *bus = dev_get_drvdata(dai->dev); 54962306a36Sopenharmony_ci struct hdac_ext_stream *link_dev; 55062306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 55162306a36Sopenharmony_ci struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 55262306a36Sopenharmony_ci struct skl_pipe_params p_params = {0}; 55362306a36Sopenharmony_ci struct hdac_ext_link *link; 55462306a36Sopenharmony_ci int stream_tag; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci link_dev = snd_hdac_ext_stream_assign(bus, substream, 55762306a36Sopenharmony_ci HDAC_EXT_STREAM_TYPE_LINK); 55862306a36Sopenharmony_ci if (!link_dev) 55962306a36Sopenharmony_ci return -EBUSY; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci link = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name); 56462306a36Sopenharmony_ci if (!link) 56562306a36Sopenharmony_ci return -EINVAL; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci stream_tag = hdac_stream(link_dev)->stream_tag; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci /* set the hdac_stream in the codec dai */ 57062306a36Sopenharmony_ci snd_soc_dai_set_stream(codec_dai, hdac_stream(link_dev), substream->stream); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci p_params.s_fmt = snd_pcm_format_width(params_format(params)); 57362306a36Sopenharmony_ci p_params.s_cont = snd_pcm_format_physical_width(params_format(params)); 57462306a36Sopenharmony_ci p_params.ch = params_channels(params); 57562306a36Sopenharmony_ci p_params.s_freq = params_rate(params); 57662306a36Sopenharmony_ci p_params.stream = substream->stream; 57762306a36Sopenharmony_ci p_params.link_dma_id = stream_tag - 1; 57862306a36Sopenharmony_ci p_params.link_index = link->index; 57962306a36Sopenharmony_ci p_params.format = params_format(params); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 58262306a36Sopenharmony_ci p_params.link_bps = codec_dai->driver->playback.sig_bits; 58362306a36Sopenharmony_ci else 58462306a36Sopenharmony_ci p_params.link_bps = codec_dai->driver->capture.sig_bits; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci return skl_tplg_be_update_params(dai, &p_params); 58762306a36Sopenharmony_ci} 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_cistatic int skl_link_pcm_prepare(struct snd_pcm_substream *substream, 59062306a36Sopenharmony_ci struct snd_soc_dai *dai) 59162306a36Sopenharmony_ci{ 59262306a36Sopenharmony_ci struct skl_dev *skl = get_skl_ctx(dai->dev); 59362306a36Sopenharmony_ci struct skl_module_cfg *mconfig = NULL; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci /* In case of XRUN recovery, reset the FW pipe to clean state */ 59662306a36Sopenharmony_ci mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream); 59762306a36Sopenharmony_ci if (mconfig && !mconfig->pipe->passthru && 59862306a36Sopenharmony_ci (substream->runtime->state == SNDRV_PCM_STATE_XRUN)) 59962306a36Sopenharmony_ci skl_reset_pipe(skl, mconfig->pipe); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci return 0; 60262306a36Sopenharmony_ci} 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_cistatic int skl_link_pcm_trigger(struct snd_pcm_substream *substream, 60562306a36Sopenharmony_ci int cmd, struct snd_soc_dai *dai) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci struct hdac_ext_stream *link_dev = 60862306a36Sopenharmony_ci snd_soc_dai_get_dma_data(dai, substream); 60962306a36Sopenharmony_ci struct hdac_bus *bus = get_bus_ctx(substream); 61062306a36Sopenharmony_ci struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd); 61362306a36Sopenharmony_ci switch (cmd) { 61462306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 61562306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 61662306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 61762306a36Sopenharmony_ci snd_hdac_ext_stream_start(link_dev); 61862306a36Sopenharmony_ci break; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 62162306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 62262306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 62362306a36Sopenharmony_ci snd_hdac_ext_stream_clear(link_dev); 62462306a36Sopenharmony_ci if (cmd == SNDRV_PCM_TRIGGER_SUSPEND) 62562306a36Sopenharmony_ci snd_hdac_ext_stream_decouple(bus, stream, false); 62662306a36Sopenharmony_ci break; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci default: 62962306a36Sopenharmony_ci return -EINVAL; 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci return 0; 63262306a36Sopenharmony_ci} 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_cistatic int skl_link_hw_free(struct snd_pcm_substream *substream, 63562306a36Sopenharmony_ci struct snd_soc_dai *dai) 63662306a36Sopenharmony_ci{ 63762306a36Sopenharmony_ci struct hdac_bus *bus = dev_get_drvdata(dai->dev); 63862306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 63962306a36Sopenharmony_ci struct hdac_ext_stream *link_dev = 64062306a36Sopenharmony_ci snd_soc_dai_get_dma_data(dai, substream); 64162306a36Sopenharmony_ci struct hdac_ext_link *link; 64262306a36Sopenharmony_ci unsigned char stream_tag; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci link_dev->link_prepared = 0; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci link = snd_hdac_ext_bus_get_hlink_by_name(bus, asoc_rtd_to_codec(rtd, 0)->component->name); 64962306a36Sopenharmony_ci if (!link) 65062306a36Sopenharmony_ci return -EINVAL; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 65362306a36Sopenharmony_ci stream_tag = hdac_stream(link_dev)->stream_tag; 65462306a36Sopenharmony_ci snd_hdac_ext_bus_link_clear_stream_id(link, stream_tag); 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK); 65862306a36Sopenharmony_ci return 0; 65962306a36Sopenharmony_ci} 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_cistatic const struct snd_soc_dai_ops skl_pcm_dai_ops = { 66262306a36Sopenharmony_ci .startup = skl_pcm_open, 66362306a36Sopenharmony_ci .shutdown = skl_pcm_close, 66462306a36Sopenharmony_ci .prepare = skl_pcm_prepare, 66562306a36Sopenharmony_ci .hw_params = skl_pcm_hw_params, 66662306a36Sopenharmony_ci .hw_free = skl_pcm_hw_free, 66762306a36Sopenharmony_ci .trigger = skl_pcm_trigger, 66862306a36Sopenharmony_ci}; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_cistatic const struct snd_soc_dai_ops skl_dmic_dai_ops = { 67162306a36Sopenharmony_ci .hw_params = skl_be_hw_params, 67262306a36Sopenharmony_ci}; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_cistatic const struct snd_soc_dai_ops skl_be_ssp_dai_ops = { 67562306a36Sopenharmony_ci .hw_params = skl_be_hw_params, 67662306a36Sopenharmony_ci}; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_cistatic const struct snd_soc_dai_ops skl_link_dai_ops = { 67962306a36Sopenharmony_ci .prepare = skl_link_pcm_prepare, 68062306a36Sopenharmony_ci .hw_params = skl_link_hw_params, 68162306a36Sopenharmony_ci .hw_free = skl_link_hw_free, 68262306a36Sopenharmony_ci .trigger = skl_link_pcm_trigger, 68362306a36Sopenharmony_ci}; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_cistatic struct snd_soc_dai_driver skl_fe_dai[] = { 68662306a36Sopenharmony_ci{ 68762306a36Sopenharmony_ci .name = "System Pin", 68862306a36Sopenharmony_ci .ops = &skl_pcm_dai_ops, 68962306a36Sopenharmony_ci .playback = { 69062306a36Sopenharmony_ci .stream_name = "System Playback", 69162306a36Sopenharmony_ci .channels_min = HDA_MONO, 69262306a36Sopenharmony_ci .channels_max = HDA_STEREO, 69362306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_8000, 69462306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | 69562306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, 69662306a36Sopenharmony_ci .sig_bits = 32, 69762306a36Sopenharmony_ci }, 69862306a36Sopenharmony_ci .capture = { 69962306a36Sopenharmony_ci .stream_name = "System Capture", 70062306a36Sopenharmony_ci .channels_min = HDA_MONO, 70162306a36Sopenharmony_ci .channels_max = HDA_STEREO, 70262306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, 70362306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 70462306a36Sopenharmony_ci .sig_bits = 32, 70562306a36Sopenharmony_ci }, 70662306a36Sopenharmony_ci}, 70762306a36Sopenharmony_ci{ 70862306a36Sopenharmony_ci .name = "System Pin2", 70962306a36Sopenharmony_ci .ops = &skl_pcm_dai_ops, 71062306a36Sopenharmony_ci .playback = { 71162306a36Sopenharmony_ci .stream_name = "Headset Playback", 71262306a36Sopenharmony_ci .channels_min = HDA_MONO, 71362306a36Sopenharmony_ci .channels_max = HDA_STEREO, 71462306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | 71562306a36Sopenharmony_ci SNDRV_PCM_RATE_8000, 71662306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | 71762306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, 71862306a36Sopenharmony_ci }, 71962306a36Sopenharmony_ci}, 72062306a36Sopenharmony_ci{ 72162306a36Sopenharmony_ci .name = "Echoref Pin", 72262306a36Sopenharmony_ci .ops = &skl_pcm_dai_ops, 72362306a36Sopenharmony_ci .capture = { 72462306a36Sopenharmony_ci .stream_name = "Echoreference Capture", 72562306a36Sopenharmony_ci .channels_min = HDA_STEREO, 72662306a36Sopenharmony_ci .channels_max = HDA_STEREO, 72762306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | 72862306a36Sopenharmony_ci SNDRV_PCM_RATE_8000, 72962306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | 73062306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, 73162306a36Sopenharmony_ci }, 73262306a36Sopenharmony_ci}, 73362306a36Sopenharmony_ci{ 73462306a36Sopenharmony_ci .name = "Reference Pin", 73562306a36Sopenharmony_ci .ops = &skl_pcm_dai_ops, 73662306a36Sopenharmony_ci .capture = { 73762306a36Sopenharmony_ci .stream_name = "Reference Capture", 73862306a36Sopenharmony_ci .channels_min = HDA_MONO, 73962306a36Sopenharmony_ci .channels_max = HDA_QUAD, 74062306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, 74162306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 74262306a36Sopenharmony_ci .sig_bits = 32, 74362306a36Sopenharmony_ci }, 74462306a36Sopenharmony_ci}, 74562306a36Sopenharmony_ci{ 74662306a36Sopenharmony_ci .name = "Deepbuffer Pin", 74762306a36Sopenharmony_ci .ops = &skl_pcm_dai_ops, 74862306a36Sopenharmony_ci .playback = { 74962306a36Sopenharmony_ci .stream_name = "Deepbuffer Playback", 75062306a36Sopenharmony_ci .channels_min = HDA_STEREO, 75162306a36Sopenharmony_ci .channels_max = HDA_STEREO, 75262306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000, 75362306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 75462306a36Sopenharmony_ci .sig_bits = 32, 75562306a36Sopenharmony_ci }, 75662306a36Sopenharmony_ci}, 75762306a36Sopenharmony_ci{ 75862306a36Sopenharmony_ci .name = "LowLatency Pin", 75962306a36Sopenharmony_ci .ops = &skl_pcm_dai_ops, 76062306a36Sopenharmony_ci .playback = { 76162306a36Sopenharmony_ci .stream_name = "Low Latency Playback", 76262306a36Sopenharmony_ci .channels_min = HDA_STEREO, 76362306a36Sopenharmony_ci .channels_max = HDA_STEREO, 76462306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000, 76562306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 76662306a36Sopenharmony_ci .sig_bits = 32, 76762306a36Sopenharmony_ci }, 76862306a36Sopenharmony_ci}, 76962306a36Sopenharmony_ci{ 77062306a36Sopenharmony_ci .name = "DMIC Pin", 77162306a36Sopenharmony_ci .ops = &skl_pcm_dai_ops, 77262306a36Sopenharmony_ci .capture = { 77362306a36Sopenharmony_ci .stream_name = "DMIC Capture", 77462306a36Sopenharmony_ci .channels_min = HDA_MONO, 77562306a36Sopenharmony_ci .channels_max = HDA_QUAD, 77662306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, 77762306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 77862306a36Sopenharmony_ci .sig_bits = 32, 77962306a36Sopenharmony_ci }, 78062306a36Sopenharmony_ci}, 78162306a36Sopenharmony_ci{ 78262306a36Sopenharmony_ci .name = "HDMI1 Pin", 78362306a36Sopenharmony_ci .ops = &skl_pcm_dai_ops, 78462306a36Sopenharmony_ci .playback = { 78562306a36Sopenharmony_ci .stream_name = "HDMI1 Playback", 78662306a36Sopenharmony_ci .channels_min = HDA_STEREO, 78762306a36Sopenharmony_ci .channels_max = 8, 78862306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | 78962306a36Sopenharmony_ci SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | 79062306a36Sopenharmony_ci SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | 79162306a36Sopenharmony_ci SNDRV_PCM_RATE_192000, 79262306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | 79362306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE, 79462306a36Sopenharmony_ci .sig_bits = 32, 79562306a36Sopenharmony_ci }, 79662306a36Sopenharmony_ci}, 79762306a36Sopenharmony_ci{ 79862306a36Sopenharmony_ci .name = "HDMI2 Pin", 79962306a36Sopenharmony_ci .ops = &skl_pcm_dai_ops, 80062306a36Sopenharmony_ci .playback = { 80162306a36Sopenharmony_ci .stream_name = "HDMI2 Playback", 80262306a36Sopenharmony_ci .channels_min = HDA_STEREO, 80362306a36Sopenharmony_ci .channels_max = 8, 80462306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | 80562306a36Sopenharmony_ci SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | 80662306a36Sopenharmony_ci SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | 80762306a36Sopenharmony_ci SNDRV_PCM_RATE_192000, 80862306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | 80962306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE, 81062306a36Sopenharmony_ci .sig_bits = 32, 81162306a36Sopenharmony_ci }, 81262306a36Sopenharmony_ci}, 81362306a36Sopenharmony_ci{ 81462306a36Sopenharmony_ci .name = "HDMI3 Pin", 81562306a36Sopenharmony_ci .ops = &skl_pcm_dai_ops, 81662306a36Sopenharmony_ci .playback = { 81762306a36Sopenharmony_ci .stream_name = "HDMI3 Playback", 81862306a36Sopenharmony_ci .channels_min = HDA_STEREO, 81962306a36Sopenharmony_ci .channels_max = 8, 82062306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | 82162306a36Sopenharmony_ci SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | 82262306a36Sopenharmony_ci SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | 82362306a36Sopenharmony_ci SNDRV_PCM_RATE_192000, 82462306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | 82562306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE, 82662306a36Sopenharmony_ci .sig_bits = 32, 82762306a36Sopenharmony_ci }, 82862306a36Sopenharmony_ci}, 82962306a36Sopenharmony_ci}; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci/* BE CPU Dais */ 83262306a36Sopenharmony_cistatic struct snd_soc_dai_driver skl_platform_dai[] = { 83362306a36Sopenharmony_ci{ 83462306a36Sopenharmony_ci .name = "SSP0 Pin", 83562306a36Sopenharmony_ci .ops = &skl_be_ssp_dai_ops, 83662306a36Sopenharmony_ci .playback = { 83762306a36Sopenharmony_ci .stream_name = "ssp0 Tx", 83862306a36Sopenharmony_ci .channels_min = HDA_STEREO, 83962306a36Sopenharmony_ci .channels_max = HDA_STEREO, 84062306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000, 84162306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE, 84262306a36Sopenharmony_ci }, 84362306a36Sopenharmony_ci .capture = { 84462306a36Sopenharmony_ci .stream_name = "ssp0 Rx", 84562306a36Sopenharmony_ci .channels_min = HDA_STEREO, 84662306a36Sopenharmony_ci .channels_max = HDA_STEREO, 84762306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000, 84862306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE, 84962306a36Sopenharmony_ci }, 85062306a36Sopenharmony_ci}, 85162306a36Sopenharmony_ci{ 85262306a36Sopenharmony_ci .name = "SSP1 Pin", 85362306a36Sopenharmony_ci .ops = &skl_be_ssp_dai_ops, 85462306a36Sopenharmony_ci .playback = { 85562306a36Sopenharmony_ci .stream_name = "ssp1 Tx", 85662306a36Sopenharmony_ci .channels_min = HDA_STEREO, 85762306a36Sopenharmony_ci .channels_max = HDA_STEREO, 85862306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000, 85962306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE, 86062306a36Sopenharmony_ci }, 86162306a36Sopenharmony_ci .capture = { 86262306a36Sopenharmony_ci .stream_name = "ssp1 Rx", 86362306a36Sopenharmony_ci .channels_min = HDA_STEREO, 86462306a36Sopenharmony_ci .channels_max = HDA_STEREO, 86562306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000, 86662306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE, 86762306a36Sopenharmony_ci }, 86862306a36Sopenharmony_ci}, 86962306a36Sopenharmony_ci{ 87062306a36Sopenharmony_ci .name = "SSP2 Pin", 87162306a36Sopenharmony_ci .ops = &skl_be_ssp_dai_ops, 87262306a36Sopenharmony_ci .playback = { 87362306a36Sopenharmony_ci .stream_name = "ssp2 Tx", 87462306a36Sopenharmony_ci .channels_min = HDA_STEREO, 87562306a36Sopenharmony_ci .channels_max = HDA_STEREO, 87662306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000, 87762306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE, 87862306a36Sopenharmony_ci }, 87962306a36Sopenharmony_ci .capture = { 88062306a36Sopenharmony_ci .stream_name = "ssp2 Rx", 88162306a36Sopenharmony_ci .channels_min = HDA_STEREO, 88262306a36Sopenharmony_ci .channels_max = HDA_STEREO, 88362306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000, 88462306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE, 88562306a36Sopenharmony_ci }, 88662306a36Sopenharmony_ci}, 88762306a36Sopenharmony_ci{ 88862306a36Sopenharmony_ci .name = "SSP3 Pin", 88962306a36Sopenharmony_ci .ops = &skl_be_ssp_dai_ops, 89062306a36Sopenharmony_ci .playback = { 89162306a36Sopenharmony_ci .stream_name = "ssp3 Tx", 89262306a36Sopenharmony_ci .channels_min = HDA_STEREO, 89362306a36Sopenharmony_ci .channels_max = HDA_STEREO, 89462306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000, 89562306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE, 89662306a36Sopenharmony_ci }, 89762306a36Sopenharmony_ci .capture = { 89862306a36Sopenharmony_ci .stream_name = "ssp3 Rx", 89962306a36Sopenharmony_ci .channels_min = HDA_STEREO, 90062306a36Sopenharmony_ci .channels_max = HDA_STEREO, 90162306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000, 90262306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE, 90362306a36Sopenharmony_ci }, 90462306a36Sopenharmony_ci}, 90562306a36Sopenharmony_ci{ 90662306a36Sopenharmony_ci .name = "SSP4 Pin", 90762306a36Sopenharmony_ci .ops = &skl_be_ssp_dai_ops, 90862306a36Sopenharmony_ci .playback = { 90962306a36Sopenharmony_ci .stream_name = "ssp4 Tx", 91062306a36Sopenharmony_ci .channels_min = HDA_STEREO, 91162306a36Sopenharmony_ci .channels_max = HDA_STEREO, 91262306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000, 91362306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE, 91462306a36Sopenharmony_ci }, 91562306a36Sopenharmony_ci .capture = { 91662306a36Sopenharmony_ci .stream_name = "ssp4 Rx", 91762306a36Sopenharmony_ci .channels_min = HDA_STEREO, 91862306a36Sopenharmony_ci .channels_max = HDA_STEREO, 91962306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000, 92062306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE, 92162306a36Sopenharmony_ci }, 92262306a36Sopenharmony_ci}, 92362306a36Sopenharmony_ci{ 92462306a36Sopenharmony_ci .name = "SSP5 Pin", 92562306a36Sopenharmony_ci .ops = &skl_be_ssp_dai_ops, 92662306a36Sopenharmony_ci .playback = { 92762306a36Sopenharmony_ci .stream_name = "ssp5 Tx", 92862306a36Sopenharmony_ci .channels_min = HDA_STEREO, 92962306a36Sopenharmony_ci .channels_max = HDA_STEREO, 93062306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000, 93162306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE, 93262306a36Sopenharmony_ci }, 93362306a36Sopenharmony_ci .capture = { 93462306a36Sopenharmony_ci .stream_name = "ssp5 Rx", 93562306a36Sopenharmony_ci .channels_min = HDA_STEREO, 93662306a36Sopenharmony_ci .channels_max = HDA_STEREO, 93762306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000, 93862306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE, 93962306a36Sopenharmony_ci }, 94062306a36Sopenharmony_ci}, 94162306a36Sopenharmony_ci{ 94262306a36Sopenharmony_ci .name = "iDisp1 Pin", 94362306a36Sopenharmony_ci .ops = &skl_link_dai_ops, 94462306a36Sopenharmony_ci .playback = { 94562306a36Sopenharmony_ci .stream_name = "iDisp1 Tx", 94662306a36Sopenharmony_ci .channels_min = HDA_STEREO, 94762306a36Sopenharmony_ci .channels_max = 8, 94862306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000, 94962306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | 95062306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE, 95162306a36Sopenharmony_ci }, 95262306a36Sopenharmony_ci}, 95362306a36Sopenharmony_ci{ 95462306a36Sopenharmony_ci .name = "iDisp2 Pin", 95562306a36Sopenharmony_ci .ops = &skl_link_dai_ops, 95662306a36Sopenharmony_ci .playback = { 95762306a36Sopenharmony_ci .stream_name = "iDisp2 Tx", 95862306a36Sopenharmony_ci .channels_min = HDA_STEREO, 95962306a36Sopenharmony_ci .channels_max = 8, 96062306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000| 96162306a36Sopenharmony_ci SNDRV_PCM_RATE_48000, 96262306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | 96362306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE, 96462306a36Sopenharmony_ci }, 96562306a36Sopenharmony_ci}, 96662306a36Sopenharmony_ci{ 96762306a36Sopenharmony_ci .name = "iDisp3 Pin", 96862306a36Sopenharmony_ci .ops = &skl_link_dai_ops, 96962306a36Sopenharmony_ci .playback = { 97062306a36Sopenharmony_ci .stream_name = "iDisp3 Tx", 97162306a36Sopenharmony_ci .channels_min = HDA_STEREO, 97262306a36Sopenharmony_ci .channels_max = 8, 97362306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000| 97462306a36Sopenharmony_ci SNDRV_PCM_RATE_48000, 97562306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | 97662306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE, 97762306a36Sopenharmony_ci }, 97862306a36Sopenharmony_ci}, 97962306a36Sopenharmony_ci{ 98062306a36Sopenharmony_ci .name = "DMIC01 Pin", 98162306a36Sopenharmony_ci .ops = &skl_dmic_dai_ops, 98262306a36Sopenharmony_ci .capture = { 98362306a36Sopenharmony_ci .stream_name = "DMIC01 Rx", 98462306a36Sopenharmony_ci .channels_min = HDA_MONO, 98562306a36Sopenharmony_ci .channels_max = HDA_QUAD, 98662306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, 98762306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 98862306a36Sopenharmony_ci }, 98962306a36Sopenharmony_ci}, 99062306a36Sopenharmony_ci{ 99162306a36Sopenharmony_ci .name = "DMIC16k Pin", 99262306a36Sopenharmony_ci .ops = &skl_dmic_dai_ops, 99362306a36Sopenharmony_ci .capture = { 99462306a36Sopenharmony_ci .stream_name = "DMIC16k Rx", 99562306a36Sopenharmony_ci .channels_min = HDA_MONO, 99662306a36Sopenharmony_ci .channels_max = HDA_QUAD, 99762306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_16000, 99862306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE, 99962306a36Sopenharmony_ci }, 100062306a36Sopenharmony_ci}, 100162306a36Sopenharmony_ci{ 100262306a36Sopenharmony_ci .name = "Analog CPU DAI", 100362306a36Sopenharmony_ci .ops = &skl_link_dai_ops, 100462306a36Sopenharmony_ci .playback = { 100562306a36Sopenharmony_ci .stream_name = "Analog CPU Playback", 100662306a36Sopenharmony_ci .channels_min = HDA_MONO, 100762306a36Sopenharmony_ci .channels_max = HDA_MAX, 100862306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_192000, 100962306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | 101062306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE, 101162306a36Sopenharmony_ci }, 101262306a36Sopenharmony_ci .capture = { 101362306a36Sopenharmony_ci .stream_name = "Analog CPU Capture", 101462306a36Sopenharmony_ci .channels_min = HDA_MONO, 101562306a36Sopenharmony_ci .channels_max = HDA_MAX, 101662306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_192000, 101762306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | 101862306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE, 101962306a36Sopenharmony_ci }, 102062306a36Sopenharmony_ci}, 102162306a36Sopenharmony_ci{ 102262306a36Sopenharmony_ci .name = "Alt Analog CPU DAI", 102362306a36Sopenharmony_ci .ops = &skl_link_dai_ops, 102462306a36Sopenharmony_ci .playback = { 102562306a36Sopenharmony_ci .stream_name = "Alt Analog CPU Playback", 102662306a36Sopenharmony_ci .channels_min = HDA_MONO, 102762306a36Sopenharmony_ci .channels_max = HDA_MAX, 102862306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_192000, 102962306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | 103062306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE, 103162306a36Sopenharmony_ci }, 103262306a36Sopenharmony_ci .capture = { 103362306a36Sopenharmony_ci .stream_name = "Alt Analog CPU Capture", 103462306a36Sopenharmony_ci .channels_min = HDA_MONO, 103562306a36Sopenharmony_ci .channels_max = HDA_MAX, 103662306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_192000, 103762306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | 103862306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE, 103962306a36Sopenharmony_ci }, 104062306a36Sopenharmony_ci}, 104162306a36Sopenharmony_ci{ 104262306a36Sopenharmony_ci .name = "Digital CPU DAI", 104362306a36Sopenharmony_ci .ops = &skl_link_dai_ops, 104462306a36Sopenharmony_ci .playback = { 104562306a36Sopenharmony_ci .stream_name = "Digital CPU Playback", 104662306a36Sopenharmony_ci .channels_min = HDA_MONO, 104762306a36Sopenharmony_ci .channels_max = HDA_MAX, 104862306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_192000, 104962306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | 105062306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE, 105162306a36Sopenharmony_ci }, 105262306a36Sopenharmony_ci .capture = { 105362306a36Sopenharmony_ci .stream_name = "Digital CPU Capture", 105462306a36Sopenharmony_ci .channels_min = HDA_MONO, 105562306a36Sopenharmony_ci .channels_max = HDA_MAX, 105662306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_192000, 105762306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | 105862306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE, 105962306a36Sopenharmony_ci }, 106062306a36Sopenharmony_ci}, 106162306a36Sopenharmony_ci}; 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ciint skl_dai_load(struct snd_soc_component *cmp, int index, 106462306a36Sopenharmony_ci struct snd_soc_dai_driver *dai_drv, 106562306a36Sopenharmony_ci struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai) 106662306a36Sopenharmony_ci{ 106762306a36Sopenharmony_ci dai_drv->ops = &skl_pcm_dai_ops; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci return 0; 107062306a36Sopenharmony_ci} 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_cistatic int skl_platform_soc_open(struct snd_soc_component *component, 107362306a36Sopenharmony_ci struct snd_pcm_substream *substream) 107462306a36Sopenharmony_ci{ 107562306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 107662306a36Sopenharmony_ci struct snd_soc_dai_link *dai_link = rtd->dai_link; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci dev_dbg(asoc_rtd_to_cpu(rtd, 0)->dev, "In %s:%s\n", __func__, 107962306a36Sopenharmony_ci dai_link->cpus->dai_name); 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci snd_soc_set_runtime_hwparams(substream, &azx_pcm_hw); 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci return 0; 108462306a36Sopenharmony_ci} 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_cistatic int skl_coupled_trigger(struct snd_pcm_substream *substream, 108762306a36Sopenharmony_ci int cmd) 108862306a36Sopenharmony_ci{ 108962306a36Sopenharmony_ci struct hdac_bus *bus = get_bus_ctx(substream); 109062306a36Sopenharmony_ci struct hdac_ext_stream *stream; 109162306a36Sopenharmony_ci struct snd_pcm_substream *s; 109262306a36Sopenharmony_ci bool start; 109362306a36Sopenharmony_ci int sbits = 0; 109462306a36Sopenharmony_ci unsigned long cookie; 109562306a36Sopenharmony_ci struct hdac_stream *hstr; 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci stream = get_hdac_ext_stream(substream); 109862306a36Sopenharmony_ci hstr = hdac_stream(stream); 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci dev_dbg(bus->dev, "In %s cmd=%d\n", __func__, cmd); 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci if (!hstr->prepared) 110362306a36Sopenharmony_ci return -EPIPE; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci switch (cmd) { 110662306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 110762306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 110862306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 110962306a36Sopenharmony_ci start = true; 111062306a36Sopenharmony_ci break; 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 111362306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 111462306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 111562306a36Sopenharmony_ci start = false; 111662306a36Sopenharmony_ci break; 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci default: 111962306a36Sopenharmony_ci return -EINVAL; 112062306a36Sopenharmony_ci } 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci snd_pcm_group_for_each_entry(s, substream) { 112362306a36Sopenharmony_ci if (s->pcm->card != substream->pcm->card) 112462306a36Sopenharmony_ci continue; 112562306a36Sopenharmony_ci stream = get_hdac_ext_stream(s); 112662306a36Sopenharmony_ci sbits |= 1 << hdac_stream(stream)->index; 112762306a36Sopenharmony_ci snd_pcm_trigger_done(s, substream); 112862306a36Sopenharmony_ci } 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci spin_lock_irqsave(&bus->reg_lock, cookie); 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci /* first, set SYNC bits of corresponding streams */ 113362306a36Sopenharmony_ci snd_hdac_stream_sync_trigger(hstr, true, sbits, AZX_REG_SSYNC); 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci snd_pcm_group_for_each_entry(s, substream) { 113662306a36Sopenharmony_ci if (s->pcm->card != substream->pcm->card) 113762306a36Sopenharmony_ci continue; 113862306a36Sopenharmony_ci stream = get_hdac_ext_stream(s); 113962306a36Sopenharmony_ci if (start) 114062306a36Sopenharmony_ci snd_hdac_stream_start(hdac_stream(stream)); 114162306a36Sopenharmony_ci else 114262306a36Sopenharmony_ci snd_hdac_stream_stop(hdac_stream(stream)); 114362306a36Sopenharmony_ci } 114462306a36Sopenharmony_ci spin_unlock_irqrestore(&bus->reg_lock, cookie); 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci snd_hdac_stream_sync(hstr, start, sbits); 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci spin_lock_irqsave(&bus->reg_lock, cookie); 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci /* reset SYNC bits */ 115162306a36Sopenharmony_ci snd_hdac_stream_sync_trigger(hstr, false, sbits, AZX_REG_SSYNC); 115262306a36Sopenharmony_ci if (start) 115362306a36Sopenharmony_ci snd_hdac_stream_timecounter_init(hstr, sbits); 115462306a36Sopenharmony_ci spin_unlock_irqrestore(&bus->reg_lock, cookie); 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci return 0; 115762306a36Sopenharmony_ci} 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_cistatic int skl_platform_soc_trigger(struct snd_soc_component *component, 116062306a36Sopenharmony_ci struct snd_pcm_substream *substream, 116162306a36Sopenharmony_ci int cmd) 116262306a36Sopenharmony_ci{ 116362306a36Sopenharmony_ci struct hdac_bus *bus = get_bus_ctx(substream); 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci if (!bus->ppcap) 116662306a36Sopenharmony_ci return skl_coupled_trigger(substream, cmd); 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci return 0; 116962306a36Sopenharmony_ci} 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_cistatic snd_pcm_uframes_t skl_platform_soc_pointer( 117262306a36Sopenharmony_ci struct snd_soc_component *component, 117362306a36Sopenharmony_ci struct snd_pcm_substream *substream) 117462306a36Sopenharmony_ci{ 117562306a36Sopenharmony_ci struct hdac_ext_stream *hstream = get_hdac_ext_stream(substream); 117662306a36Sopenharmony_ci struct hdac_bus *bus = get_bus_ctx(substream); 117762306a36Sopenharmony_ci unsigned int pos; 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci /* 118062306a36Sopenharmony_ci * Use DPIB for Playback stream as the periodic DMA Position-in- 118162306a36Sopenharmony_ci * Buffer Writes may be scheduled at the same time or later than 118262306a36Sopenharmony_ci * the MSI and does not guarantee to reflect the Position of the 118362306a36Sopenharmony_ci * last buffer that was transferred. Whereas DPIB register in 118462306a36Sopenharmony_ci * HAD space reflects the actual data that is transferred. 118562306a36Sopenharmony_ci * Use the position buffer for capture, as DPIB write gets 118662306a36Sopenharmony_ci * completed earlier than the actual data written to the DDR. 118762306a36Sopenharmony_ci * 118862306a36Sopenharmony_ci * For capture stream following workaround is required to fix the 118962306a36Sopenharmony_ci * incorrect position reporting. 119062306a36Sopenharmony_ci * 119162306a36Sopenharmony_ci * 1. Wait for 20us before reading the DMA position in buffer once 119262306a36Sopenharmony_ci * the interrupt is generated for stream completion as update happens 119362306a36Sopenharmony_ci * on the HDA frame boundary i.e. 20.833uSec. 119462306a36Sopenharmony_ci * 2. Read DPIB register to flush the DMA position value. This dummy 119562306a36Sopenharmony_ci * read is required to flush DMA position value. 119662306a36Sopenharmony_ci * 3. Read the DMA Position-in-Buffer. This value now will be equal to 119762306a36Sopenharmony_ci * or greater than period boundary. 119862306a36Sopenharmony_ci */ 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 120162306a36Sopenharmony_ci pos = readl(bus->remap_addr + AZX_REG_VS_SDXDPIB_XBASE + 120262306a36Sopenharmony_ci (AZX_REG_VS_SDXDPIB_XINTERVAL * 120362306a36Sopenharmony_ci hdac_stream(hstream)->index)); 120462306a36Sopenharmony_ci } else { 120562306a36Sopenharmony_ci udelay(20); 120662306a36Sopenharmony_ci readl(bus->remap_addr + 120762306a36Sopenharmony_ci AZX_REG_VS_SDXDPIB_XBASE + 120862306a36Sopenharmony_ci (AZX_REG_VS_SDXDPIB_XINTERVAL * 120962306a36Sopenharmony_ci hdac_stream(hstream)->index)); 121062306a36Sopenharmony_ci pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream)); 121162306a36Sopenharmony_ci } 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci if (pos >= hdac_stream(hstream)->bufsize) 121462306a36Sopenharmony_ci pos = 0; 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci return bytes_to_frames(substream->runtime, pos); 121762306a36Sopenharmony_ci} 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_cistatic u64 skl_adjust_codec_delay(struct snd_pcm_substream *substream, 122062306a36Sopenharmony_ci u64 nsec) 122162306a36Sopenharmony_ci{ 122262306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 122362306a36Sopenharmony_ci struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 122462306a36Sopenharmony_ci u64 codec_frames, codec_nsecs; 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci if (!codec_dai->driver->ops->delay) 122762306a36Sopenharmony_ci return nsec; 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci codec_frames = codec_dai->driver->ops->delay(substream, codec_dai); 123062306a36Sopenharmony_ci codec_nsecs = div_u64(codec_frames * 1000000000LL, 123162306a36Sopenharmony_ci substream->runtime->rate); 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 123462306a36Sopenharmony_ci return nsec + codec_nsecs; 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci return (nsec > codec_nsecs) ? nsec - codec_nsecs : 0; 123762306a36Sopenharmony_ci} 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_cistatic int skl_platform_soc_get_time_info( 124062306a36Sopenharmony_ci struct snd_soc_component *component, 124162306a36Sopenharmony_ci struct snd_pcm_substream *substream, 124262306a36Sopenharmony_ci struct timespec64 *system_ts, struct timespec64 *audio_ts, 124362306a36Sopenharmony_ci struct snd_pcm_audio_tstamp_config *audio_tstamp_config, 124462306a36Sopenharmony_ci struct snd_pcm_audio_tstamp_report *audio_tstamp_report) 124562306a36Sopenharmony_ci{ 124662306a36Sopenharmony_ci struct hdac_ext_stream *sstream = get_hdac_ext_stream(substream); 124762306a36Sopenharmony_ci struct hdac_stream *hstr = hdac_stream(sstream); 124862306a36Sopenharmony_ci u64 nsec; 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci if ((substream->runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_ATIME) && 125162306a36Sopenharmony_ci (audio_tstamp_config->type_requested == SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK)) { 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci snd_pcm_gettime(substream->runtime, system_ts); 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci nsec = timecounter_read(&hstr->tc); 125662306a36Sopenharmony_ci if (audio_tstamp_config->report_delay) 125762306a36Sopenharmony_ci nsec = skl_adjust_codec_delay(substream, nsec); 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci *audio_ts = ns_to_timespec64(nsec); 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK; 126262306a36Sopenharmony_ci audio_tstamp_report->accuracy_report = 1; /* rest of struct is valid */ 126362306a36Sopenharmony_ci audio_tstamp_report->accuracy = 42; /* 24MHzWallClk == 42ns resolution */ 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci } else { 126662306a36Sopenharmony_ci audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT; 126762306a36Sopenharmony_ci } 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci return 0; 127062306a36Sopenharmony_ci} 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci#define MAX_PREALLOC_SIZE (32 * 1024 * 1024) 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_cistatic int skl_platform_soc_new(struct snd_soc_component *component, 127562306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd) 127662306a36Sopenharmony_ci{ 127762306a36Sopenharmony_ci struct snd_soc_dai *dai = asoc_rtd_to_cpu(rtd, 0); 127862306a36Sopenharmony_ci struct hdac_bus *bus = dev_get_drvdata(dai->dev); 127962306a36Sopenharmony_ci struct snd_pcm *pcm = rtd->pcm; 128062306a36Sopenharmony_ci unsigned int size; 128162306a36Sopenharmony_ci struct skl_dev *skl = bus_to_skl(bus); 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci if (dai->driver->playback.channels_min || 128462306a36Sopenharmony_ci dai->driver->capture.channels_min) { 128562306a36Sopenharmony_ci /* buffer pre-allocation */ 128662306a36Sopenharmony_ci size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024; 128762306a36Sopenharmony_ci if (size > MAX_PREALLOC_SIZE) 128862306a36Sopenharmony_ci size = MAX_PREALLOC_SIZE; 128962306a36Sopenharmony_ci snd_pcm_set_managed_buffer_all(pcm, 129062306a36Sopenharmony_ci SNDRV_DMA_TYPE_DEV_SG, 129162306a36Sopenharmony_ci &skl->pci->dev, 129262306a36Sopenharmony_ci size, MAX_PREALLOC_SIZE); 129362306a36Sopenharmony_ci } 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci return 0; 129662306a36Sopenharmony_ci} 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_cistatic int skl_get_module_info(struct skl_dev *skl, 129962306a36Sopenharmony_ci struct skl_module_cfg *mconfig) 130062306a36Sopenharmony_ci{ 130162306a36Sopenharmony_ci struct skl_module_inst_id *pin_id; 130262306a36Sopenharmony_ci guid_t *uuid_mod, *uuid_tplg; 130362306a36Sopenharmony_ci struct skl_module *skl_module; 130462306a36Sopenharmony_ci struct uuid_module *module; 130562306a36Sopenharmony_ci int i, ret = -EIO; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci uuid_mod = (guid_t *)mconfig->guid; 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci if (list_empty(&skl->uuid_list)) { 131062306a36Sopenharmony_ci dev_err(skl->dev, "Module list is empty\n"); 131162306a36Sopenharmony_ci return -EIO; 131262306a36Sopenharmony_ci } 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci for (i = 0; i < skl->nr_modules; i++) { 131562306a36Sopenharmony_ci skl_module = skl->modules[i]; 131662306a36Sopenharmony_ci uuid_tplg = &skl_module->uuid; 131762306a36Sopenharmony_ci if (guid_equal(uuid_mod, uuid_tplg)) { 131862306a36Sopenharmony_ci mconfig->module = skl_module; 131962306a36Sopenharmony_ci ret = 0; 132062306a36Sopenharmony_ci break; 132162306a36Sopenharmony_ci } 132262306a36Sopenharmony_ci } 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci if (skl->nr_modules && ret) 132562306a36Sopenharmony_ci return ret; 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci ret = -EIO; 132862306a36Sopenharmony_ci list_for_each_entry(module, &skl->uuid_list, list) { 132962306a36Sopenharmony_ci if (guid_equal(uuid_mod, &module->uuid)) { 133062306a36Sopenharmony_ci mconfig->id.module_id = module->id; 133162306a36Sopenharmony_ci mconfig->module->loadable = module->is_loadable; 133262306a36Sopenharmony_ci ret = 0; 133362306a36Sopenharmony_ci } 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci for (i = 0; i < MAX_IN_QUEUE; i++) { 133662306a36Sopenharmony_ci pin_id = &mconfig->m_in_pin[i].id; 133762306a36Sopenharmony_ci if (guid_equal(&pin_id->mod_uuid, &module->uuid)) 133862306a36Sopenharmony_ci pin_id->module_id = module->id; 133962306a36Sopenharmony_ci } 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci for (i = 0; i < MAX_OUT_QUEUE; i++) { 134262306a36Sopenharmony_ci pin_id = &mconfig->m_out_pin[i].id; 134362306a36Sopenharmony_ci if (guid_equal(&pin_id->mod_uuid, &module->uuid)) 134462306a36Sopenharmony_ci pin_id->module_id = module->id; 134562306a36Sopenharmony_ci } 134662306a36Sopenharmony_ci } 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci return ret; 134962306a36Sopenharmony_ci} 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_cistatic int skl_populate_modules(struct skl_dev *skl) 135262306a36Sopenharmony_ci{ 135362306a36Sopenharmony_ci struct skl_pipeline *p; 135462306a36Sopenharmony_ci struct skl_pipe_module *m; 135562306a36Sopenharmony_ci struct snd_soc_dapm_widget *w; 135662306a36Sopenharmony_ci struct skl_module_cfg *mconfig; 135762306a36Sopenharmony_ci int ret = 0; 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci list_for_each_entry(p, &skl->ppl_list, node) { 136062306a36Sopenharmony_ci list_for_each_entry(m, &p->pipe->w_list, node) { 136162306a36Sopenharmony_ci w = m->w; 136262306a36Sopenharmony_ci mconfig = w->priv; 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci ret = skl_get_module_info(skl, mconfig); 136562306a36Sopenharmony_ci if (ret < 0) { 136662306a36Sopenharmony_ci dev_err(skl->dev, 136762306a36Sopenharmony_ci "query module info failed\n"); 136862306a36Sopenharmony_ci return ret; 136962306a36Sopenharmony_ci } 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci skl_tplg_add_moduleid_in_bind_params(skl, w); 137262306a36Sopenharmony_ci } 137362306a36Sopenharmony_ci } 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci return ret; 137662306a36Sopenharmony_ci} 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_cistatic int skl_platform_soc_probe(struct snd_soc_component *component) 137962306a36Sopenharmony_ci{ 138062306a36Sopenharmony_ci struct hdac_bus *bus = dev_get_drvdata(component->dev); 138162306a36Sopenharmony_ci struct skl_dev *skl = bus_to_skl(bus); 138262306a36Sopenharmony_ci const struct skl_dsp_ops *ops; 138362306a36Sopenharmony_ci int ret; 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(component->dev); 138662306a36Sopenharmony_ci if (ret < 0 && ret != -EACCES) 138762306a36Sopenharmony_ci return ret; 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci if (bus->ppcap) { 139062306a36Sopenharmony_ci skl->component = component; 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci /* init debugfs */ 139362306a36Sopenharmony_ci skl->debugfs = skl_debugfs_init(skl); 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci ret = skl_tplg_init(component, bus); 139662306a36Sopenharmony_ci if (ret < 0) { 139762306a36Sopenharmony_ci dev_err(component->dev, "Failed to init topology!\n"); 139862306a36Sopenharmony_ci return ret; 139962306a36Sopenharmony_ci } 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci /* load the firmwares, since all is set */ 140262306a36Sopenharmony_ci ops = skl_get_dsp_ops(skl->pci->device); 140362306a36Sopenharmony_ci if (!ops) 140462306a36Sopenharmony_ci return -EIO; 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci /* 140762306a36Sopenharmony_ci * Disable dynamic clock and power gating during firmware 140862306a36Sopenharmony_ci * and library download 140962306a36Sopenharmony_ci */ 141062306a36Sopenharmony_ci skl->enable_miscbdcge(component->dev, false); 141162306a36Sopenharmony_ci skl->clock_power_gating(component->dev, false); 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci ret = ops->init_fw(component->dev, skl); 141462306a36Sopenharmony_ci skl->enable_miscbdcge(component->dev, true); 141562306a36Sopenharmony_ci skl->clock_power_gating(component->dev, true); 141662306a36Sopenharmony_ci if (ret < 0) { 141762306a36Sopenharmony_ci dev_err(component->dev, "Failed to boot first fw: %d\n", ret); 141862306a36Sopenharmony_ci return ret; 141962306a36Sopenharmony_ci } 142062306a36Sopenharmony_ci skl_populate_modules(skl); 142162306a36Sopenharmony_ci skl->update_d0i3c = skl_update_d0i3c; 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci if (skl->cfg.astate_cfg != NULL) { 142462306a36Sopenharmony_ci skl_dsp_set_astate_cfg(skl, 142562306a36Sopenharmony_ci skl->cfg.astate_cfg->count, 142662306a36Sopenharmony_ci skl->cfg.astate_cfg); 142762306a36Sopenharmony_ci } 142862306a36Sopenharmony_ci } 142962306a36Sopenharmony_ci pm_runtime_mark_last_busy(component->dev); 143062306a36Sopenharmony_ci pm_runtime_put_autosuspend(component->dev); 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci return 0; 143362306a36Sopenharmony_ci} 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_cistatic void skl_platform_soc_remove(struct snd_soc_component *component) 143662306a36Sopenharmony_ci{ 143762306a36Sopenharmony_ci struct hdac_bus *bus = dev_get_drvdata(component->dev); 143862306a36Sopenharmony_ci struct skl_dev *skl = bus_to_skl(bus); 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci skl_tplg_exit(component, bus); 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci skl_debugfs_exit(skl); 144362306a36Sopenharmony_ci} 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_cistatic const struct snd_soc_component_driver skl_component = { 144662306a36Sopenharmony_ci .name = "pcm", 144762306a36Sopenharmony_ci .probe = skl_platform_soc_probe, 144862306a36Sopenharmony_ci .remove = skl_platform_soc_remove, 144962306a36Sopenharmony_ci .open = skl_platform_soc_open, 145062306a36Sopenharmony_ci .trigger = skl_platform_soc_trigger, 145162306a36Sopenharmony_ci .pointer = skl_platform_soc_pointer, 145262306a36Sopenharmony_ci .get_time_info = skl_platform_soc_get_time_info, 145362306a36Sopenharmony_ci .pcm_construct = skl_platform_soc_new, 145462306a36Sopenharmony_ci .module_get_upon_open = 1, /* increment refcount when a pcm is opened */ 145562306a36Sopenharmony_ci}; 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ciint skl_platform_register(struct device *dev) 145862306a36Sopenharmony_ci{ 145962306a36Sopenharmony_ci int ret; 146062306a36Sopenharmony_ci struct snd_soc_dai_driver *dais; 146162306a36Sopenharmony_ci int num_dais = ARRAY_SIZE(skl_platform_dai); 146262306a36Sopenharmony_ci struct hdac_bus *bus = dev_get_drvdata(dev); 146362306a36Sopenharmony_ci struct skl_dev *skl = bus_to_skl(bus); 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci skl->dais = kmemdup(skl_platform_dai, sizeof(skl_platform_dai), 146662306a36Sopenharmony_ci GFP_KERNEL); 146762306a36Sopenharmony_ci if (!skl->dais) { 146862306a36Sopenharmony_ci ret = -ENOMEM; 146962306a36Sopenharmony_ci goto err; 147062306a36Sopenharmony_ci } 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci if (!skl->use_tplg_pcm) { 147362306a36Sopenharmony_ci dais = krealloc(skl->dais, sizeof(skl_fe_dai) + 147462306a36Sopenharmony_ci sizeof(skl_platform_dai), GFP_KERNEL); 147562306a36Sopenharmony_ci if (!dais) { 147662306a36Sopenharmony_ci kfree(skl->dais); 147762306a36Sopenharmony_ci ret = -ENOMEM; 147862306a36Sopenharmony_ci goto err; 147962306a36Sopenharmony_ci } 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci skl->dais = dais; 148262306a36Sopenharmony_ci memcpy(&skl->dais[ARRAY_SIZE(skl_platform_dai)], skl_fe_dai, 148362306a36Sopenharmony_ci sizeof(skl_fe_dai)); 148462306a36Sopenharmony_ci num_dais += ARRAY_SIZE(skl_fe_dai); 148562306a36Sopenharmony_ci } 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci ret = devm_snd_soc_register_component(dev, &skl_component, 148862306a36Sopenharmony_ci skl->dais, num_dais); 148962306a36Sopenharmony_ci if (ret) { 149062306a36Sopenharmony_ci kfree(skl->dais); 149162306a36Sopenharmony_ci dev_err(dev, "soc component registration failed %d\n", ret); 149262306a36Sopenharmony_ci } 149362306a36Sopenharmony_cierr: 149462306a36Sopenharmony_ci return ret; 149562306a36Sopenharmony_ci} 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ciint skl_platform_unregister(struct device *dev) 149862306a36Sopenharmony_ci{ 149962306a36Sopenharmony_ci struct hdac_bus *bus = dev_get_drvdata(dev); 150062306a36Sopenharmony_ci struct skl_dev *skl = bus_to_skl(bus); 150162306a36Sopenharmony_ci struct skl_module_deferred_bind *modules, *tmp; 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci list_for_each_entry_safe(modules, tmp, &skl->bind_list, node) { 150462306a36Sopenharmony_ci list_del(&modules->node); 150562306a36Sopenharmony_ci kfree(modules); 150662306a36Sopenharmony_ci } 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci kfree(skl->dais); 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci return 0; 151162306a36Sopenharmony_ci} 1512