16f23f4e2SPierre-Louis Bossart // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
26f23f4e2SPierre-Louis Bossart // Copyright(c) 2023 Intel Corporation. All rights reserved.
36f23f4e2SPierre-Louis Bossart
46f23f4e2SPierre-Louis Bossart /*
56f23f4e2SPierre-Louis Bossart * Soundwire Intel ops for LunarLake
66f23f4e2SPierre-Louis Bossart */
76f23f4e2SPierre-Louis Bossart
86f23f4e2SPierre-Louis Bossart #include <linux/acpi.h>
96f23f4e2SPierre-Louis Bossart #include <linux/device.h>
106f23f4e2SPierre-Louis Bossart #include <linux/soundwire/sdw_registers.h>
116f23f4e2SPierre-Louis Bossart #include <linux/soundwire/sdw.h>
126f23f4e2SPierre-Louis Bossart #include <linux/soundwire/sdw_intel.h>
138c4c9a9aSPierre-Louis Bossart #include <sound/pcm_params.h>
14806f5abdSPierre-Louis Bossart #include <sound/hda-mlink.h>
156f23f4e2SPierre-Louis Bossart #include "cadence_master.h"
166f23f4e2SPierre-Louis Bossart #include "bus.h"
176f23f4e2SPierre-Louis Bossart #include "intel.h"
186f23f4e2SPierre-Louis Bossart
19f40bb244SPierre-Louis Bossart /*
20f40bb244SPierre-Louis Bossart * shim vendor-specific (vs) ops
21f40bb244SPierre-Louis Bossart */
22f40bb244SPierre-Louis Bossart
intel_shim_vs_init(struct sdw_intel * sdw)23f40bb244SPierre-Louis Bossart static void intel_shim_vs_init(struct sdw_intel *sdw)
24f40bb244SPierre-Louis Bossart {
25f40bb244SPierre-Louis Bossart void __iomem *shim_vs = sdw->link_res->shim_vs;
26*262853dcSChao Song u16 act;
27f40bb244SPierre-Louis Bossart
28*262853dcSChao Song act = intel_readw(shim_vs, SDW_SHIM2_INTEL_VS_ACTMCTL);
29f40bb244SPierre-Louis Bossart u16p_replace_bits(&act, 0x1, SDW_SHIM2_INTEL_VS_ACTMCTL_DOAIS);
30f40bb244SPierre-Louis Bossart act |= SDW_SHIM2_INTEL_VS_ACTMCTL_DACTQE;
31f40bb244SPierre-Louis Bossart act |= SDW_SHIM2_INTEL_VS_ACTMCTL_DODS;
32f40bb244SPierre-Louis Bossart intel_writew(shim_vs, SDW_SHIM2_INTEL_VS_ACTMCTL, act);
33f40bb244SPierre-Louis Bossart usleep_range(10, 15);
34f40bb244SPierre-Louis Bossart }
35f40bb244SPierre-Louis Bossart
intel_shim_check_wake(struct sdw_intel * sdw)36b8e39bc4SPierre-Louis Bossart static int intel_shim_check_wake(struct sdw_intel *sdw)
37b8e39bc4SPierre-Louis Bossart {
38b8e39bc4SPierre-Louis Bossart void __iomem *shim_vs;
39b8e39bc4SPierre-Louis Bossart u16 wake_sts;
40b8e39bc4SPierre-Louis Bossart
41b8e39bc4SPierre-Louis Bossart shim_vs = sdw->link_res->shim_vs;
42b8e39bc4SPierre-Louis Bossart wake_sts = intel_readw(shim_vs, SDW_SHIM2_INTEL_VS_WAKESTS);
43b8e39bc4SPierre-Louis Bossart
44b8e39bc4SPierre-Louis Bossart return wake_sts & SDW_SHIM2_INTEL_VS_WAKEEN_PWS;
45b8e39bc4SPierre-Louis Bossart }
46b8e39bc4SPierre-Louis Bossart
intel_shim_wake(struct sdw_intel * sdw,bool wake_enable)47b8e39bc4SPierre-Louis Bossart static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable)
48b8e39bc4SPierre-Louis Bossart {
49b8e39bc4SPierre-Louis Bossart void __iomem *shim_vs = sdw->link_res->shim_vs;
50b8e39bc4SPierre-Louis Bossart u16 wake_en;
51b8e39bc4SPierre-Louis Bossart u16 wake_sts;
52b8e39bc4SPierre-Louis Bossart
53b8e39bc4SPierre-Louis Bossart wake_en = intel_readw(shim_vs, SDW_SHIM2_INTEL_VS_WAKEEN);
54b8e39bc4SPierre-Louis Bossart
55b8e39bc4SPierre-Louis Bossart if (wake_enable) {
56b8e39bc4SPierre-Louis Bossart /* Enable the wakeup */
57b8e39bc4SPierre-Louis Bossart wake_en |= SDW_SHIM2_INTEL_VS_WAKEEN_PWE;
58b8e39bc4SPierre-Louis Bossart intel_writew(shim_vs, SDW_SHIM2_INTEL_VS_WAKEEN, wake_en);
59b8e39bc4SPierre-Louis Bossart } else {
60b8e39bc4SPierre-Louis Bossart /* Disable the wake up interrupt */
61b8e39bc4SPierre-Louis Bossart wake_en &= ~SDW_SHIM2_INTEL_VS_WAKEEN_PWE;
62b8e39bc4SPierre-Louis Bossart intel_writew(shim_vs, SDW_SHIM2_INTEL_VS_WAKEEN, wake_en);
63b8e39bc4SPierre-Louis Bossart
64b8e39bc4SPierre-Louis Bossart /* Clear wake status (W1C) */
65b8e39bc4SPierre-Louis Bossart wake_sts = intel_readw(shim_vs, SDW_SHIM2_INTEL_VS_WAKESTS);
66b8e39bc4SPierre-Louis Bossart wake_sts |= SDW_SHIM2_INTEL_VS_WAKEEN_PWS;
67b8e39bc4SPierre-Louis Bossart intel_writew(shim_vs, SDW_SHIM2_INTEL_VS_WAKESTS, wake_sts);
68b8e39bc4SPierre-Louis Bossart }
69b8e39bc4SPierre-Louis Bossart }
70b8e39bc4SPierre-Louis Bossart
intel_link_power_up(struct sdw_intel * sdw)71806f5abdSPierre-Louis Bossart static int intel_link_power_up(struct sdw_intel *sdw)
72806f5abdSPierre-Louis Bossart {
73d3565643SPierre-Louis Bossart struct sdw_bus *bus = &sdw->cdns.bus;
74d3565643SPierre-Louis Bossart struct sdw_master_prop *prop = &bus->prop;
75d3565643SPierre-Louis Bossart u32 *shim_mask = sdw->link_res->shim_mask;
76d3565643SPierre-Louis Bossart unsigned int link_id = sdw->instance;
77d3565643SPierre-Louis Bossart u32 syncprd;
78806f5abdSPierre-Louis Bossart int ret;
79806f5abdSPierre-Louis Bossart
80806f5abdSPierre-Louis Bossart mutex_lock(sdw->link_res->shim_lock);
81806f5abdSPierre-Louis Bossart
82d3565643SPierre-Louis Bossart if (!*shim_mask) {
83d3565643SPierre-Louis Bossart /* we first need to program the SyncPRD/CPU registers */
84d3565643SPierre-Louis Bossart dev_dbg(sdw->cdns.dev, "first link up, programming SYNCPRD\n");
85d3565643SPierre-Louis Bossart
86d3565643SPierre-Louis Bossart if (prop->mclk_freq % 6000000)
87d3565643SPierre-Louis Bossart syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_38_4;
88d3565643SPierre-Louis Bossart else
89d3565643SPierre-Louis Bossart syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24;
90d3565643SPierre-Louis Bossart
91d3565643SPierre-Louis Bossart ret = hdac_bus_eml_sdw_set_syncprd_unlocked(sdw->link_res->hbus, syncprd);
92d3565643SPierre-Louis Bossart if (ret < 0) {
93d3565643SPierre-Louis Bossart dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_set_syncprd failed: %d\n",
94d3565643SPierre-Louis Bossart __func__, ret);
95d3565643SPierre-Louis Bossart goto out;
96d3565643SPierre-Louis Bossart }
97d3565643SPierre-Louis Bossart }
98d3565643SPierre-Louis Bossart
99d3565643SPierre-Louis Bossart ret = hdac_bus_eml_sdw_power_up_unlocked(sdw->link_res->hbus, link_id);
100806f5abdSPierre-Louis Bossart if (ret < 0) {
101806f5abdSPierre-Louis Bossart dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_power_up failed: %d\n",
102806f5abdSPierre-Louis Bossart __func__, ret);
103806f5abdSPierre-Louis Bossart goto out;
104806f5abdSPierre-Louis Bossart }
105806f5abdSPierre-Louis Bossart
106d3565643SPierre-Louis Bossart if (!*shim_mask) {
107d3565643SPierre-Louis Bossart /* SYNCPU will change once link is active */
108d3565643SPierre-Louis Bossart ret = hdac_bus_eml_sdw_wait_syncpu_unlocked(sdw->link_res->hbus);
109d3565643SPierre-Louis Bossart if (ret < 0) {
110d3565643SPierre-Louis Bossart dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_wait_syncpu failed: %d\n",
111d3565643SPierre-Louis Bossart __func__, ret);
112d3565643SPierre-Louis Bossart goto out;
113d3565643SPierre-Louis Bossart }
114d3565643SPierre-Louis Bossart }
115d3565643SPierre-Louis Bossart
116d3565643SPierre-Louis Bossart *shim_mask |= BIT(link_id);
117d3565643SPierre-Louis Bossart
118806f5abdSPierre-Louis Bossart sdw->cdns.link_up = true;
119f40bb244SPierre-Louis Bossart
120f40bb244SPierre-Louis Bossart intel_shim_vs_init(sdw);
121f40bb244SPierre-Louis Bossart
122806f5abdSPierre-Louis Bossart out:
123806f5abdSPierre-Louis Bossart mutex_unlock(sdw->link_res->shim_lock);
124806f5abdSPierre-Louis Bossart
125806f5abdSPierre-Louis Bossart return ret;
126806f5abdSPierre-Louis Bossart }
127806f5abdSPierre-Louis Bossart
intel_link_power_down(struct sdw_intel * sdw)128806f5abdSPierre-Louis Bossart static int intel_link_power_down(struct sdw_intel *sdw)
129806f5abdSPierre-Louis Bossart {
130d3565643SPierre-Louis Bossart u32 *shim_mask = sdw->link_res->shim_mask;
131d3565643SPierre-Louis Bossart unsigned int link_id = sdw->instance;
132806f5abdSPierre-Louis Bossart int ret;
133806f5abdSPierre-Louis Bossart
134806f5abdSPierre-Louis Bossart mutex_lock(sdw->link_res->shim_lock);
135806f5abdSPierre-Louis Bossart
136806f5abdSPierre-Louis Bossart sdw->cdns.link_up = false;
137806f5abdSPierre-Louis Bossart
138d3565643SPierre-Louis Bossart *shim_mask &= ~BIT(link_id);
139d3565643SPierre-Louis Bossart
140d3565643SPierre-Louis Bossart ret = hdac_bus_eml_sdw_power_down_unlocked(sdw->link_res->hbus, link_id);
141806f5abdSPierre-Louis Bossart if (ret < 0) {
142806f5abdSPierre-Louis Bossart dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_power_down failed: %d\n",
143806f5abdSPierre-Louis Bossart __func__, ret);
144806f5abdSPierre-Louis Bossart
145806f5abdSPierre-Louis Bossart /*
146806f5abdSPierre-Louis Bossart * we leave the sdw->cdns.link_up flag as false since we've disabled
147806f5abdSPierre-Louis Bossart * the link at this point and cannot handle interrupts any longer.
148806f5abdSPierre-Louis Bossart */
149806f5abdSPierre-Louis Bossart }
150806f5abdSPierre-Louis Bossart
151806f5abdSPierre-Louis Bossart mutex_unlock(sdw->link_res->shim_lock);
152806f5abdSPierre-Louis Bossart
153806f5abdSPierre-Louis Bossart return ret;
154806f5abdSPierre-Louis Bossart }
155806f5abdSPierre-Louis Bossart
intel_sync_arm(struct sdw_intel * sdw)1564d1e2464SPierre-Louis Bossart static void intel_sync_arm(struct sdw_intel *sdw)
1574d1e2464SPierre-Louis Bossart {
1584d1e2464SPierre-Louis Bossart unsigned int link_id = sdw->instance;
1594d1e2464SPierre-Louis Bossart
1604d1e2464SPierre-Louis Bossart mutex_lock(sdw->link_res->shim_lock);
1614d1e2464SPierre-Louis Bossart
1624d1e2464SPierre-Louis Bossart hdac_bus_eml_sdw_sync_arm_unlocked(sdw->link_res->hbus, link_id);
1634d1e2464SPierre-Louis Bossart
1644d1e2464SPierre-Louis Bossart mutex_unlock(sdw->link_res->shim_lock);
1654d1e2464SPierre-Louis Bossart }
1664d1e2464SPierre-Louis Bossart
intel_sync_go_unlocked(struct sdw_intel * sdw)1674d1e2464SPierre-Louis Bossart static int intel_sync_go_unlocked(struct sdw_intel *sdw)
1684d1e2464SPierre-Louis Bossart {
1694d1e2464SPierre-Louis Bossart int ret;
1704d1e2464SPierre-Louis Bossart
1714d1e2464SPierre-Louis Bossart ret = hdac_bus_eml_sdw_sync_go_unlocked(sdw->link_res->hbus);
1724d1e2464SPierre-Louis Bossart if (ret < 0)
1734d1e2464SPierre-Louis Bossart dev_err(sdw->cdns.dev, "%s: SyncGO clear failed: %d\n", __func__, ret);
1744d1e2464SPierre-Louis Bossart
1754d1e2464SPierre-Louis Bossart return ret;
1764d1e2464SPierre-Louis Bossart }
1774d1e2464SPierre-Louis Bossart
intel_sync_go(struct sdw_intel * sdw)1784d1e2464SPierre-Louis Bossart static int intel_sync_go(struct sdw_intel *sdw)
1794d1e2464SPierre-Louis Bossart {
1804d1e2464SPierre-Louis Bossart int ret;
1814d1e2464SPierre-Louis Bossart
1824d1e2464SPierre-Louis Bossart mutex_lock(sdw->link_res->shim_lock);
1834d1e2464SPierre-Louis Bossart
1844d1e2464SPierre-Louis Bossart ret = intel_sync_go_unlocked(sdw);
1854d1e2464SPierre-Louis Bossart
1864d1e2464SPierre-Louis Bossart mutex_unlock(sdw->link_res->shim_lock);
1874d1e2464SPierre-Louis Bossart
1884d1e2464SPierre-Louis Bossart return ret;
1894d1e2464SPierre-Louis Bossart }
1904d1e2464SPierre-Louis Bossart
intel_check_cmdsync_unlocked(struct sdw_intel * sdw)1917ba18639SPierre-Louis Bossart static bool intel_check_cmdsync_unlocked(struct sdw_intel *sdw)
1927ba18639SPierre-Louis Bossart {
1937ba18639SPierre-Louis Bossart return hdac_bus_eml_sdw_check_cmdsync_unlocked(sdw->link_res->hbus);
1947ba18639SPierre-Louis Bossart }
1957ba18639SPierre-Louis Bossart
1968c4c9a9aSPierre-Louis Bossart /* DAI callbacks */
intel_params_stream(struct sdw_intel * sdw,struct snd_pcm_substream * substream,struct snd_soc_dai * dai,struct snd_pcm_hw_params * hw_params,int link_id,int alh_stream_id)1978c4c9a9aSPierre-Louis Bossart static int intel_params_stream(struct sdw_intel *sdw,
1988c4c9a9aSPierre-Louis Bossart struct snd_pcm_substream *substream,
1998c4c9a9aSPierre-Louis Bossart struct snd_soc_dai *dai,
2008c4c9a9aSPierre-Louis Bossart struct snd_pcm_hw_params *hw_params,
2018c4c9a9aSPierre-Louis Bossart int link_id, int alh_stream_id)
2028c4c9a9aSPierre-Louis Bossart {
2038c4c9a9aSPierre-Louis Bossart struct sdw_intel_link_res *res = sdw->link_res;
2048c4c9a9aSPierre-Louis Bossart struct sdw_intel_stream_params_data params_data;
2058c4c9a9aSPierre-Louis Bossart
2068c4c9a9aSPierre-Louis Bossart params_data.substream = substream;
2078c4c9a9aSPierre-Louis Bossart params_data.dai = dai;
2088c4c9a9aSPierre-Louis Bossart params_data.hw_params = hw_params;
2098c4c9a9aSPierre-Louis Bossart params_data.link_id = link_id;
2108c4c9a9aSPierre-Louis Bossart params_data.alh_stream_id = alh_stream_id;
2118c4c9a9aSPierre-Louis Bossart
2128c4c9a9aSPierre-Louis Bossart if (res->ops && res->ops->params_stream && res->dev)
2138c4c9a9aSPierre-Louis Bossart return res->ops->params_stream(res->dev,
2148c4c9a9aSPierre-Louis Bossart ¶ms_data);
2158c4c9a9aSPierre-Louis Bossart return -EIO;
2168c4c9a9aSPierre-Louis Bossart }
2178c4c9a9aSPierre-Louis Bossart
intel_free_stream(struct sdw_intel * sdw,struct snd_pcm_substream * substream,struct snd_soc_dai * dai,int link_id)2188c4c9a9aSPierre-Louis Bossart static int intel_free_stream(struct sdw_intel *sdw,
2198c4c9a9aSPierre-Louis Bossart struct snd_pcm_substream *substream,
2208c4c9a9aSPierre-Louis Bossart struct snd_soc_dai *dai,
2218c4c9a9aSPierre-Louis Bossart int link_id)
2228c4c9a9aSPierre-Louis Bossart
2238c4c9a9aSPierre-Louis Bossart {
2248c4c9a9aSPierre-Louis Bossart struct sdw_intel_link_res *res = sdw->link_res;
2258c4c9a9aSPierre-Louis Bossart struct sdw_intel_stream_free_data free_data;
2268c4c9a9aSPierre-Louis Bossart
2278c4c9a9aSPierre-Louis Bossart free_data.substream = substream;
2288c4c9a9aSPierre-Louis Bossart free_data.dai = dai;
2298c4c9a9aSPierre-Louis Bossart free_data.link_id = link_id;
2308c4c9a9aSPierre-Louis Bossart
2318c4c9a9aSPierre-Louis Bossart if (res->ops && res->ops->free_stream && res->dev)
2328c4c9a9aSPierre-Louis Bossart return res->ops->free_stream(res->dev,
2338c4c9a9aSPierre-Louis Bossart &free_data);
2348c4c9a9aSPierre-Louis Bossart
2358c4c9a9aSPierre-Louis Bossart return 0;
2368c4c9a9aSPierre-Louis Bossart }
2378c4c9a9aSPierre-Louis Bossart
238d2f0daf6SPierre-Louis Bossart /*
239d2f0daf6SPierre-Louis Bossart * DAI operations
240d2f0daf6SPierre-Louis Bossart */
intel_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)2418c4c9a9aSPierre-Louis Bossart static int intel_hw_params(struct snd_pcm_substream *substream,
2428c4c9a9aSPierre-Louis Bossart struct snd_pcm_hw_params *params,
2438c4c9a9aSPierre-Louis Bossart struct snd_soc_dai *dai)
2448c4c9a9aSPierre-Louis Bossart {
2458c4c9a9aSPierre-Louis Bossart struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
2468c4c9a9aSPierre-Louis Bossart struct sdw_intel *sdw = cdns_to_intel(cdns);
2478c4c9a9aSPierre-Louis Bossart struct sdw_cdns_dai_runtime *dai_runtime;
2488c4c9a9aSPierre-Louis Bossart struct sdw_cdns_pdi *pdi;
2498c4c9a9aSPierre-Louis Bossart struct sdw_stream_config sconfig;
2508c4c9a9aSPierre-Louis Bossart struct sdw_port_config *pconfig;
2518c4c9a9aSPierre-Louis Bossart int ch, dir;
2528c4c9a9aSPierre-Louis Bossart int ret;
2538c4c9a9aSPierre-Louis Bossart
2548c4c9a9aSPierre-Louis Bossart dai_runtime = cdns->dai_runtime_array[dai->id];
2558c4c9a9aSPierre-Louis Bossart if (!dai_runtime)
2568c4c9a9aSPierre-Louis Bossart return -EIO;
2578c4c9a9aSPierre-Louis Bossart
2588c4c9a9aSPierre-Louis Bossart ch = params_channels(params);
2598c4c9a9aSPierre-Louis Bossart if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
2608c4c9a9aSPierre-Louis Bossart dir = SDW_DATA_DIR_RX;
2618c4c9a9aSPierre-Louis Bossart else
2628c4c9a9aSPierre-Louis Bossart dir = SDW_DATA_DIR_TX;
2638c4c9a9aSPierre-Louis Bossart
2648c4c9a9aSPierre-Louis Bossart pdi = sdw_cdns_alloc_pdi(cdns, &cdns->pcm, ch, dir, dai->id);
2658c4c9a9aSPierre-Louis Bossart
2668c4c9a9aSPierre-Louis Bossart if (!pdi) {
2678c4c9a9aSPierre-Louis Bossart ret = -EINVAL;
2688c4c9a9aSPierre-Louis Bossart goto error;
2698c4c9a9aSPierre-Louis Bossart }
2708c4c9a9aSPierre-Louis Bossart
2718c4c9a9aSPierre-Louis Bossart /* the SHIM will be configured in the callback functions */
2728c4c9a9aSPierre-Louis Bossart
2738c4c9a9aSPierre-Louis Bossart sdw_cdns_config_stream(cdns, ch, dir, pdi);
2748c4c9a9aSPierre-Louis Bossart
2758c4c9a9aSPierre-Louis Bossart /* store pdi and state, may be needed in prepare step */
2768c4c9a9aSPierre-Louis Bossart dai_runtime->paused = false;
2778c4c9a9aSPierre-Louis Bossart dai_runtime->suspended = false;
2788c4c9a9aSPierre-Louis Bossart dai_runtime->pdi = pdi;
2798c4c9a9aSPierre-Louis Bossart
2808c4c9a9aSPierre-Louis Bossart /* Inform DSP about PDI stream number */
2818c4c9a9aSPierre-Louis Bossart ret = intel_params_stream(sdw, substream, dai, params,
2828c4c9a9aSPierre-Louis Bossart sdw->instance,
2838c4c9a9aSPierre-Louis Bossart pdi->intel_alh_id);
2848c4c9a9aSPierre-Louis Bossart if (ret)
2858c4c9a9aSPierre-Louis Bossart goto error;
2868c4c9a9aSPierre-Louis Bossart
2878c4c9a9aSPierre-Louis Bossart sconfig.direction = dir;
2888c4c9a9aSPierre-Louis Bossart sconfig.ch_count = ch;
2898c4c9a9aSPierre-Louis Bossart sconfig.frame_rate = params_rate(params);
2908c4c9a9aSPierre-Louis Bossart sconfig.type = dai_runtime->stream_type;
2918c4c9a9aSPierre-Louis Bossart
2928c4c9a9aSPierre-Louis Bossart sconfig.bps = snd_pcm_format_width(params_format(params));
2938c4c9a9aSPierre-Louis Bossart
2948c4c9a9aSPierre-Louis Bossart /* Port configuration */
2958c4c9a9aSPierre-Louis Bossart pconfig = kzalloc(sizeof(*pconfig), GFP_KERNEL);
2968c4c9a9aSPierre-Louis Bossart if (!pconfig) {
2978c4c9a9aSPierre-Louis Bossart ret = -ENOMEM;
2988c4c9a9aSPierre-Louis Bossart goto error;
2998c4c9a9aSPierre-Louis Bossart }
3008c4c9a9aSPierre-Louis Bossart
3018c4c9a9aSPierre-Louis Bossart pconfig->num = pdi->num;
3028c4c9a9aSPierre-Louis Bossart pconfig->ch_mask = (1 << ch) - 1;
3038c4c9a9aSPierre-Louis Bossart
3048c4c9a9aSPierre-Louis Bossart ret = sdw_stream_add_master(&cdns->bus, &sconfig,
3058c4c9a9aSPierre-Louis Bossart pconfig, 1, dai_runtime->stream);
3068c4c9a9aSPierre-Louis Bossart if (ret)
3078c4c9a9aSPierre-Louis Bossart dev_err(cdns->dev, "add master to stream failed:%d\n", ret);
3088c4c9a9aSPierre-Louis Bossart
3098c4c9a9aSPierre-Louis Bossart kfree(pconfig);
3108c4c9a9aSPierre-Louis Bossart error:
3118c4c9a9aSPierre-Louis Bossart return ret;
3128c4c9a9aSPierre-Louis Bossart }
3138c4c9a9aSPierre-Louis Bossart
intel_prepare(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)3148c4c9a9aSPierre-Louis Bossart static int intel_prepare(struct snd_pcm_substream *substream,
3158c4c9a9aSPierre-Louis Bossart struct snd_soc_dai *dai)
3168c4c9a9aSPierre-Louis Bossart {
3178c4c9a9aSPierre-Louis Bossart struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
3188c4c9a9aSPierre-Louis Bossart struct sdw_intel *sdw = cdns_to_intel(cdns);
3198c4c9a9aSPierre-Louis Bossart struct sdw_cdns_dai_runtime *dai_runtime;
3208c4c9a9aSPierre-Louis Bossart int ch, dir;
3218c4c9a9aSPierre-Louis Bossart int ret = 0;
3228c4c9a9aSPierre-Louis Bossart
3238c4c9a9aSPierre-Louis Bossart dai_runtime = cdns->dai_runtime_array[dai->id];
3248c4c9a9aSPierre-Louis Bossart if (!dai_runtime) {
3258c4c9a9aSPierre-Louis Bossart dev_err(dai->dev, "failed to get dai runtime in %s\n",
3268c4c9a9aSPierre-Louis Bossart __func__);
3278c4c9a9aSPierre-Louis Bossart return -EIO;
3288c4c9a9aSPierre-Louis Bossart }
3298c4c9a9aSPierre-Louis Bossart
3308c4c9a9aSPierre-Louis Bossart if (dai_runtime->suspended) {
3318c4c9a9aSPierre-Louis Bossart struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
3328c4c9a9aSPierre-Louis Bossart struct snd_pcm_hw_params *hw_params;
3338c4c9a9aSPierre-Louis Bossart
3348c4c9a9aSPierre-Louis Bossart hw_params = &rtd->dpcm[substream->stream].hw_params;
3358c4c9a9aSPierre-Louis Bossart
3368c4c9a9aSPierre-Louis Bossart dai_runtime->suspended = false;
3378c4c9a9aSPierre-Louis Bossart
3388c4c9a9aSPierre-Louis Bossart /*
3398c4c9a9aSPierre-Louis Bossart * .prepare() is called after system resume, where we
3408c4c9a9aSPierre-Louis Bossart * need to reinitialize the SHIM/ALH/Cadence IP.
3418c4c9a9aSPierre-Louis Bossart * .prepare() is also called to deal with underflows,
3428c4c9a9aSPierre-Louis Bossart * but in those cases we cannot touch ALH/SHIM
3438c4c9a9aSPierre-Louis Bossart * registers
3448c4c9a9aSPierre-Louis Bossart */
3458c4c9a9aSPierre-Louis Bossart
3468c4c9a9aSPierre-Louis Bossart /* configure stream */
3478c4c9a9aSPierre-Louis Bossart ch = params_channels(hw_params);
3488c4c9a9aSPierre-Louis Bossart if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
3498c4c9a9aSPierre-Louis Bossart dir = SDW_DATA_DIR_RX;
3508c4c9a9aSPierre-Louis Bossart else
3518c4c9a9aSPierre-Louis Bossart dir = SDW_DATA_DIR_TX;
3528c4c9a9aSPierre-Louis Bossart
3538c4c9a9aSPierre-Louis Bossart /* the SHIM will be configured in the callback functions */
3548c4c9a9aSPierre-Louis Bossart
3558c4c9a9aSPierre-Louis Bossart sdw_cdns_config_stream(cdns, ch, dir, dai_runtime->pdi);
3568c4c9a9aSPierre-Louis Bossart
3578c4c9a9aSPierre-Louis Bossart /* Inform DSP about PDI stream number */
3588c4c9a9aSPierre-Louis Bossart ret = intel_params_stream(sdw, substream, dai,
3598c4c9a9aSPierre-Louis Bossart hw_params,
3608c4c9a9aSPierre-Louis Bossart sdw->instance,
3618c4c9a9aSPierre-Louis Bossart dai_runtime->pdi->intel_alh_id);
3628c4c9a9aSPierre-Louis Bossart }
3638c4c9a9aSPierre-Louis Bossart
3648c4c9a9aSPierre-Louis Bossart return ret;
3658c4c9a9aSPierre-Louis Bossart }
3668c4c9a9aSPierre-Louis Bossart
3678c4c9a9aSPierre-Louis Bossart static int
intel_hw_free(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)3688c4c9a9aSPierre-Louis Bossart intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
3698c4c9a9aSPierre-Louis Bossart {
3708c4c9a9aSPierre-Louis Bossart struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
3718c4c9a9aSPierre-Louis Bossart struct sdw_intel *sdw = cdns_to_intel(cdns);
3728c4c9a9aSPierre-Louis Bossart struct sdw_cdns_dai_runtime *dai_runtime;
3738c4c9a9aSPierre-Louis Bossart int ret;
3748c4c9a9aSPierre-Louis Bossart
3758c4c9a9aSPierre-Louis Bossart dai_runtime = cdns->dai_runtime_array[dai->id];
3768c4c9a9aSPierre-Louis Bossart if (!dai_runtime)
3778c4c9a9aSPierre-Louis Bossart return -EIO;
3788c4c9a9aSPierre-Louis Bossart
3798c4c9a9aSPierre-Louis Bossart /*
3808c4c9a9aSPierre-Louis Bossart * The sdw stream state will transition to RELEASED when stream->
3818c4c9a9aSPierre-Louis Bossart * master_list is empty. So the stream state will transition to
3828c4c9a9aSPierre-Louis Bossart * DEPREPARED for the first cpu-dai and to RELEASED for the last
3838c4c9a9aSPierre-Louis Bossart * cpu-dai.
3848c4c9a9aSPierre-Louis Bossart */
3858c4c9a9aSPierre-Louis Bossart ret = sdw_stream_remove_master(&cdns->bus, dai_runtime->stream);
3868c4c9a9aSPierre-Louis Bossart if (ret < 0) {
3878c4c9a9aSPierre-Louis Bossart dev_err(dai->dev, "remove master from stream %s failed: %d\n",
3888c4c9a9aSPierre-Louis Bossart dai_runtime->stream->name, ret);
3898c4c9a9aSPierre-Louis Bossart return ret;
3908c4c9a9aSPierre-Louis Bossart }
3918c4c9a9aSPierre-Louis Bossart
3928c4c9a9aSPierre-Louis Bossart ret = intel_free_stream(sdw, substream, dai, sdw->instance);
3938c4c9a9aSPierre-Louis Bossart if (ret < 0) {
3948c4c9a9aSPierre-Louis Bossart dev_err(dai->dev, "intel_free_stream: failed %d\n", ret);
3958c4c9a9aSPierre-Louis Bossart return ret;
3968c4c9a9aSPierre-Louis Bossart }
3978c4c9a9aSPierre-Louis Bossart
3988c4c9a9aSPierre-Louis Bossart dai_runtime->pdi = NULL;
3998c4c9a9aSPierre-Louis Bossart
4008c4c9a9aSPierre-Louis Bossart return 0;
4018c4c9a9aSPierre-Louis Bossart }
4028c4c9a9aSPierre-Louis Bossart
intel_pcm_set_sdw_stream(struct snd_soc_dai * dai,void * stream,int direction)4038c4c9a9aSPierre-Louis Bossart static int intel_pcm_set_sdw_stream(struct snd_soc_dai *dai,
4048c4c9a9aSPierre-Louis Bossart void *stream, int direction)
4058c4c9a9aSPierre-Louis Bossart {
4068c4c9a9aSPierre-Louis Bossart return cdns_set_sdw_stream(dai, stream, direction);
4078c4c9a9aSPierre-Louis Bossart }
4088c4c9a9aSPierre-Louis Bossart
intel_get_sdw_stream(struct snd_soc_dai * dai,int direction)4098c4c9a9aSPierre-Louis Bossart static void *intel_get_sdw_stream(struct snd_soc_dai *dai,
4108c4c9a9aSPierre-Louis Bossart int direction)
4118c4c9a9aSPierre-Louis Bossart {
4128c4c9a9aSPierre-Louis Bossart struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
4138c4c9a9aSPierre-Louis Bossart struct sdw_cdns_dai_runtime *dai_runtime;
4148c4c9a9aSPierre-Louis Bossart
4158c4c9a9aSPierre-Louis Bossart dai_runtime = cdns->dai_runtime_array[dai->id];
4168c4c9a9aSPierre-Louis Bossart if (!dai_runtime)
4178c4c9a9aSPierre-Louis Bossart return ERR_PTR(-EINVAL);
4188c4c9a9aSPierre-Louis Bossart
4198c4c9a9aSPierre-Louis Bossart return dai_runtime->stream;
4208c4c9a9aSPierre-Louis Bossart }
4218c4c9a9aSPierre-Louis Bossart
intel_trigger(struct snd_pcm_substream * substream,int cmd,struct snd_soc_dai * dai)4228c4c9a9aSPierre-Louis Bossart static int intel_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
4238c4c9a9aSPierre-Louis Bossart {
4248c4c9a9aSPierre-Louis Bossart struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
4258c4c9a9aSPierre-Louis Bossart struct sdw_intel *sdw = cdns_to_intel(cdns);
4268c4c9a9aSPierre-Louis Bossart struct sdw_intel_link_res *res = sdw->link_res;
4278c4c9a9aSPierre-Louis Bossart struct sdw_cdns_dai_runtime *dai_runtime;
4288c4c9a9aSPierre-Louis Bossart int ret = 0;
4298c4c9a9aSPierre-Louis Bossart
4308c4c9a9aSPierre-Louis Bossart /*
4318c4c9a9aSPierre-Louis Bossart * The .trigger callback is used to program HDaudio DMA and send required IPC to audio
4328c4c9a9aSPierre-Louis Bossart * firmware.
4338c4c9a9aSPierre-Louis Bossart */
4348c4c9a9aSPierre-Louis Bossart if (res->ops && res->ops->trigger) {
4358c4c9a9aSPierre-Louis Bossart ret = res->ops->trigger(substream, cmd, dai);
4368c4c9a9aSPierre-Louis Bossart if (ret < 0)
4378c4c9a9aSPierre-Louis Bossart return ret;
4388c4c9a9aSPierre-Louis Bossart }
4398c4c9a9aSPierre-Louis Bossart
4408c4c9a9aSPierre-Louis Bossart dai_runtime = cdns->dai_runtime_array[dai->id];
4418c4c9a9aSPierre-Louis Bossart if (!dai_runtime) {
4428c4c9a9aSPierre-Louis Bossart dev_err(dai->dev, "failed to get dai runtime in %s\n",
4438c4c9a9aSPierre-Louis Bossart __func__);
4448c4c9a9aSPierre-Louis Bossart return -EIO;
4458c4c9a9aSPierre-Louis Bossart }
4468c4c9a9aSPierre-Louis Bossart
4478c4c9a9aSPierre-Louis Bossart switch (cmd) {
4488c4c9a9aSPierre-Louis Bossart case SNDRV_PCM_TRIGGER_SUSPEND:
4498c4c9a9aSPierre-Louis Bossart
4508c4c9a9aSPierre-Louis Bossart /*
4518c4c9a9aSPierre-Louis Bossart * The .prepare callback is used to deal with xruns and resume operations.
4528c4c9a9aSPierre-Louis Bossart * In the case of xruns, the DMAs and SHIM registers cannot be touched,
4538c4c9a9aSPierre-Louis Bossart * but for resume operations the DMAs and SHIM registers need to be initialized.
4548c4c9a9aSPierre-Louis Bossart * the .trigger callback is used to track the suspend case only.
4558c4c9a9aSPierre-Louis Bossart */
4568c4c9a9aSPierre-Louis Bossart
4578c4c9a9aSPierre-Louis Bossart dai_runtime->suspended = true;
4588c4c9a9aSPierre-Louis Bossart
4598c4c9a9aSPierre-Louis Bossart break;
4608c4c9a9aSPierre-Louis Bossart
4618c4c9a9aSPierre-Louis Bossart case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
4628c4c9a9aSPierre-Louis Bossart dai_runtime->paused = true;
4638c4c9a9aSPierre-Louis Bossart break;
4648c4c9a9aSPierre-Louis Bossart case SNDRV_PCM_TRIGGER_STOP:
4658c4c9a9aSPierre-Louis Bossart case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
4668c4c9a9aSPierre-Louis Bossart dai_runtime->paused = false;
4678c4c9a9aSPierre-Louis Bossart break;
4688c4c9a9aSPierre-Louis Bossart default:
4698c4c9a9aSPierre-Louis Bossart break;
4708c4c9a9aSPierre-Louis Bossart }
4718c4c9a9aSPierre-Louis Bossart
4728c4c9a9aSPierre-Louis Bossart return ret;
4738c4c9a9aSPierre-Louis Bossart }
4748c4c9a9aSPierre-Louis Bossart
475d2f0daf6SPierre-Louis Bossart static const struct snd_soc_dai_ops intel_pcm_dai_ops = {
4768c4c9a9aSPierre-Louis Bossart .hw_params = intel_hw_params,
4778c4c9a9aSPierre-Louis Bossart .prepare = intel_prepare,
4788c4c9a9aSPierre-Louis Bossart .hw_free = intel_hw_free,
4798c4c9a9aSPierre-Louis Bossart .trigger = intel_trigger,
4808c4c9a9aSPierre-Louis Bossart .set_stream = intel_pcm_set_sdw_stream,
4818c4c9a9aSPierre-Louis Bossart .get_stream = intel_get_sdw_stream,
482d2f0daf6SPierre-Louis Bossart };
483d2f0daf6SPierre-Louis Bossart
484d2f0daf6SPierre-Louis Bossart static const struct snd_soc_component_driver dai_component = {
485d2f0daf6SPierre-Louis Bossart .name = "soundwire",
486d2f0daf6SPierre-Louis Bossart };
487d2f0daf6SPierre-Louis Bossart
488d2f0daf6SPierre-Louis Bossart /*
489d2f0daf6SPierre-Louis Bossart * PDI routines
490d2f0daf6SPierre-Louis Bossart */
intel_pdi_init(struct sdw_intel * sdw,struct sdw_cdns_stream_config * config)491d2f0daf6SPierre-Louis Bossart static void intel_pdi_init(struct sdw_intel *sdw,
492d2f0daf6SPierre-Louis Bossart struct sdw_cdns_stream_config *config)
493d2f0daf6SPierre-Louis Bossart {
494d2f0daf6SPierre-Louis Bossart void __iomem *shim = sdw->link_res->shim;
495d2f0daf6SPierre-Louis Bossart int pcm_cap;
496d2f0daf6SPierre-Louis Bossart
497d2f0daf6SPierre-Louis Bossart /* PCM Stream Capability */
498d2f0daf6SPierre-Louis Bossart pcm_cap = intel_readw(shim, SDW_SHIM2_PCMSCAP);
499d2f0daf6SPierre-Louis Bossart
500d2f0daf6SPierre-Louis Bossart config->pcm_bd = FIELD_GET(SDW_SHIM2_PCMSCAP_BSS, pcm_cap);
501d2f0daf6SPierre-Louis Bossart config->pcm_in = FIELD_GET(SDW_SHIM2_PCMSCAP_ISS, pcm_cap);
502d2f0daf6SPierre-Louis Bossart config->pcm_out = FIELD_GET(SDW_SHIM2_PCMSCAP_ISS, pcm_cap);
503d2f0daf6SPierre-Louis Bossart
504d2f0daf6SPierre-Louis Bossart dev_dbg(sdw->cdns.dev, "PCM cap bd:%d in:%d out:%d\n",
505d2f0daf6SPierre-Louis Bossart config->pcm_bd, config->pcm_in, config->pcm_out);
506d2f0daf6SPierre-Louis Bossart }
507d2f0daf6SPierre-Louis Bossart
508d2f0daf6SPierre-Louis Bossart static int
intel_pdi_get_ch_cap(struct sdw_intel * sdw,unsigned int pdi_num)509d2f0daf6SPierre-Louis Bossart intel_pdi_get_ch_cap(struct sdw_intel *sdw, unsigned int pdi_num)
510d2f0daf6SPierre-Louis Bossart {
511d2f0daf6SPierre-Louis Bossart void __iomem *shim = sdw->link_res->shim;
512d2f0daf6SPierre-Louis Bossart
513d2f0daf6SPierre-Louis Bossart /* zero based values for channel count in register */
514d2f0daf6SPierre-Louis Bossart return intel_readw(shim, SDW_SHIM2_PCMSYCHC(pdi_num)) + 1;
515d2f0daf6SPierre-Louis Bossart }
516d2f0daf6SPierre-Louis Bossart
intel_pdi_get_ch_update(struct sdw_intel * sdw,struct sdw_cdns_pdi * pdi,unsigned int num_pdi,unsigned int * num_ch)517d2f0daf6SPierre-Louis Bossart static void intel_pdi_get_ch_update(struct sdw_intel *sdw,
518d2f0daf6SPierre-Louis Bossart struct sdw_cdns_pdi *pdi,
519d2f0daf6SPierre-Louis Bossart unsigned int num_pdi,
520d2f0daf6SPierre-Louis Bossart unsigned int *num_ch)
521d2f0daf6SPierre-Louis Bossart {
522d2f0daf6SPierre-Louis Bossart int ch_count = 0;
523d2f0daf6SPierre-Louis Bossart int i;
524d2f0daf6SPierre-Louis Bossart
525d2f0daf6SPierre-Louis Bossart for (i = 0; i < num_pdi; i++) {
526d2f0daf6SPierre-Louis Bossart pdi->ch_count = intel_pdi_get_ch_cap(sdw, pdi->num);
527d2f0daf6SPierre-Louis Bossart ch_count += pdi->ch_count;
528d2f0daf6SPierre-Louis Bossart pdi++;
529d2f0daf6SPierre-Louis Bossart }
530d2f0daf6SPierre-Louis Bossart
531d2f0daf6SPierre-Louis Bossart *num_ch = ch_count;
532d2f0daf6SPierre-Louis Bossart }
533d2f0daf6SPierre-Louis Bossart
intel_pdi_stream_ch_update(struct sdw_intel * sdw,struct sdw_cdns_streams * stream)534d2f0daf6SPierre-Louis Bossart static void intel_pdi_stream_ch_update(struct sdw_intel *sdw,
535d2f0daf6SPierre-Louis Bossart struct sdw_cdns_streams *stream)
536d2f0daf6SPierre-Louis Bossart {
537d2f0daf6SPierre-Louis Bossart intel_pdi_get_ch_update(sdw, stream->bd, stream->num_bd,
538d2f0daf6SPierre-Louis Bossart &stream->num_ch_bd);
539d2f0daf6SPierre-Louis Bossart
540d2f0daf6SPierre-Louis Bossart intel_pdi_get_ch_update(sdw, stream->in, stream->num_in,
541d2f0daf6SPierre-Louis Bossart &stream->num_ch_in);
542d2f0daf6SPierre-Louis Bossart
543d2f0daf6SPierre-Louis Bossart intel_pdi_get_ch_update(sdw, stream->out, stream->num_out,
544d2f0daf6SPierre-Louis Bossart &stream->num_ch_out);
545d2f0daf6SPierre-Louis Bossart }
546d2f0daf6SPierre-Louis Bossart
intel_create_dai(struct sdw_cdns * cdns,struct snd_soc_dai_driver * dais,enum intel_pdi_type type,u32 num,u32 off,u32 max_ch)547d2f0daf6SPierre-Louis Bossart static int intel_create_dai(struct sdw_cdns *cdns,
548d2f0daf6SPierre-Louis Bossart struct snd_soc_dai_driver *dais,
549d2f0daf6SPierre-Louis Bossart enum intel_pdi_type type,
550d2f0daf6SPierre-Louis Bossart u32 num, u32 off, u32 max_ch)
551d2f0daf6SPierre-Louis Bossart {
552d2f0daf6SPierre-Louis Bossart int i;
553d2f0daf6SPierre-Louis Bossart
554d2f0daf6SPierre-Louis Bossart if (!num)
555d2f0daf6SPierre-Louis Bossart return 0;
556d2f0daf6SPierre-Louis Bossart
557d2f0daf6SPierre-Louis Bossart for (i = off; i < (off + num); i++) {
558d2f0daf6SPierre-Louis Bossart dais[i].name = devm_kasprintf(cdns->dev, GFP_KERNEL,
559d2f0daf6SPierre-Louis Bossart "SDW%d Pin%d",
560d2f0daf6SPierre-Louis Bossart cdns->instance, i);
561d2f0daf6SPierre-Louis Bossart if (!dais[i].name)
562d2f0daf6SPierre-Louis Bossart return -ENOMEM;
563d2f0daf6SPierre-Louis Bossart
564d2f0daf6SPierre-Louis Bossart if (type == INTEL_PDI_BD || type == INTEL_PDI_OUT) {
565d2f0daf6SPierre-Louis Bossart dais[i].playback.channels_min = 1;
566d2f0daf6SPierre-Louis Bossart dais[i].playback.channels_max = max_ch;
567d2f0daf6SPierre-Louis Bossart }
568d2f0daf6SPierre-Louis Bossart
569d2f0daf6SPierre-Louis Bossart if (type == INTEL_PDI_BD || type == INTEL_PDI_IN) {
570d2f0daf6SPierre-Louis Bossart dais[i].capture.channels_min = 1;
571d2f0daf6SPierre-Louis Bossart dais[i].capture.channels_max = max_ch;
572d2f0daf6SPierre-Louis Bossart }
573d2f0daf6SPierre-Louis Bossart
574d2f0daf6SPierre-Louis Bossart dais[i].ops = &intel_pcm_dai_ops;
575d2f0daf6SPierre-Louis Bossart }
576d2f0daf6SPierre-Louis Bossart
577d2f0daf6SPierre-Louis Bossart return 0;
578d2f0daf6SPierre-Louis Bossart }
579d2f0daf6SPierre-Louis Bossart
intel_register_dai(struct sdw_intel * sdw)580d2f0daf6SPierre-Louis Bossart static int intel_register_dai(struct sdw_intel *sdw)
581d2f0daf6SPierre-Louis Bossart {
582d2f0daf6SPierre-Louis Bossart struct sdw_cdns_dai_runtime **dai_runtime_array;
583d2f0daf6SPierre-Louis Bossart struct sdw_cdns_stream_config config;
584d2f0daf6SPierre-Louis Bossart struct sdw_cdns *cdns = &sdw->cdns;
585d2f0daf6SPierre-Louis Bossart struct sdw_cdns_streams *stream;
586d2f0daf6SPierre-Louis Bossart struct snd_soc_dai_driver *dais;
587d2f0daf6SPierre-Louis Bossart int num_dai;
588d2f0daf6SPierre-Louis Bossart int ret;
589d2f0daf6SPierre-Louis Bossart int off = 0;
590d2f0daf6SPierre-Louis Bossart
591d2f0daf6SPierre-Louis Bossart /* Read the PDI config and initialize cadence PDI */
592d2f0daf6SPierre-Louis Bossart intel_pdi_init(sdw, &config);
593d2f0daf6SPierre-Louis Bossart ret = sdw_cdns_pdi_init(cdns, config);
594d2f0daf6SPierre-Louis Bossart if (ret)
595d2f0daf6SPierre-Louis Bossart return ret;
596d2f0daf6SPierre-Louis Bossart
597d2f0daf6SPierre-Louis Bossart intel_pdi_stream_ch_update(sdw, &sdw->cdns.pcm);
598d2f0daf6SPierre-Louis Bossart
599d2f0daf6SPierre-Louis Bossart /* DAIs are created based on total number of PDIs supported */
600d2f0daf6SPierre-Louis Bossart num_dai = cdns->pcm.num_pdi;
601d2f0daf6SPierre-Louis Bossart
602d2f0daf6SPierre-Louis Bossart dai_runtime_array = devm_kcalloc(cdns->dev, num_dai,
603d2f0daf6SPierre-Louis Bossart sizeof(struct sdw_cdns_dai_runtime *),
604d2f0daf6SPierre-Louis Bossart GFP_KERNEL);
605d2f0daf6SPierre-Louis Bossart if (!dai_runtime_array)
606d2f0daf6SPierre-Louis Bossart return -ENOMEM;
607d2f0daf6SPierre-Louis Bossart cdns->dai_runtime_array = dai_runtime_array;
608d2f0daf6SPierre-Louis Bossart
609d2f0daf6SPierre-Louis Bossart dais = devm_kcalloc(cdns->dev, num_dai, sizeof(*dais), GFP_KERNEL);
610d2f0daf6SPierre-Louis Bossart if (!dais)
611d2f0daf6SPierre-Louis Bossart return -ENOMEM;
612d2f0daf6SPierre-Louis Bossart
613d2f0daf6SPierre-Louis Bossart /* Create PCM DAIs */
614d2f0daf6SPierre-Louis Bossart stream = &cdns->pcm;
615d2f0daf6SPierre-Louis Bossart
616d2f0daf6SPierre-Louis Bossart ret = intel_create_dai(cdns, dais, INTEL_PDI_IN, cdns->pcm.num_in,
617d2f0daf6SPierre-Louis Bossart off, stream->num_ch_in);
618d2f0daf6SPierre-Louis Bossart if (ret)
619d2f0daf6SPierre-Louis Bossart return ret;
620d2f0daf6SPierre-Louis Bossart
621d2f0daf6SPierre-Louis Bossart off += cdns->pcm.num_in;
622d2f0daf6SPierre-Louis Bossart ret = intel_create_dai(cdns, dais, INTEL_PDI_OUT, cdns->pcm.num_out,
623d2f0daf6SPierre-Louis Bossart off, stream->num_ch_out);
624d2f0daf6SPierre-Louis Bossart if (ret)
625d2f0daf6SPierre-Louis Bossart return ret;
626d2f0daf6SPierre-Louis Bossart
627d2f0daf6SPierre-Louis Bossart off += cdns->pcm.num_out;
628d2f0daf6SPierre-Louis Bossart ret = intel_create_dai(cdns, dais, INTEL_PDI_BD, cdns->pcm.num_bd,
629d2f0daf6SPierre-Louis Bossart off, stream->num_ch_bd);
630d2f0daf6SPierre-Louis Bossart if (ret)
631d2f0daf6SPierre-Louis Bossart return ret;
632d2f0daf6SPierre-Louis Bossart
633d2f0daf6SPierre-Louis Bossart return devm_snd_soc_register_component(cdns->dev, &dai_component,
634d2f0daf6SPierre-Louis Bossart dais, num_dai);
635d2f0daf6SPierre-Louis Bossart }
636d2f0daf6SPierre-Louis Bossart
intel_program_sdi(struct sdw_intel * sdw,int dev_num)637bcf71917SPierre-Louis Bossart static void intel_program_sdi(struct sdw_intel *sdw, int dev_num)
638bcf71917SPierre-Louis Bossart {
639bcf71917SPierre-Louis Bossart int ret;
640bcf71917SPierre-Louis Bossart
641bcf71917SPierre-Louis Bossart ret = hdac_bus_eml_sdw_set_lsdiid(sdw->link_res->hbus, sdw->instance, dev_num);
642bcf71917SPierre-Louis Bossart if (ret < 0)
643bcf71917SPierre-Louis Bossart dev_err(sdw->cdns.dev, "%s: could not set lsdiid for link %d %d\n",
644bcf71917SPierre-Louis Bossart __func__, sdw->instance, dev_num);
645bcf71917SPierre-Louis Bossart }
646bcf71917SPierre-Louis Bossart
6476f23f4e2SPierre-Louis Bossart const struct sdw_intel_hw_ops sdw_intel_lnl_hw_ops = {
648312316d5SPierre-Louis Bossart .debugfs_init = intel_ace2x_debugfs_init,
649312316d5SPierre-Louis Bossart .debugfs_exit = intel_ace2x_debugfs_exit,
650806f5abdSPierre-Louis Bossart
651d2f0daf6SPierre-Louis Bossart .register_dai = intel_register_dai,
652d2f0daf6SPierre-Louis Bossart
653f90ba301SPierre-Louis Bossart .check_clock_stop = intel_check_clock_stop,
654f90ba301SPierre-Louis Bossart .start_bus = intel_start_bus,
655f90ba301SPierre-Louis Bossart .start_bus_after_reset = intel_start_bus_after_reset,
656f90ba301SPierre-Louis Bossart .start_bus_after_clock_stop = intel_start_bus_after_clock_stop,
657f90ba301SPierre-Louis Bossart .stop_bus = intel_stop_bus,
658f90ba301SPierre-Louis Bossart
659806f5abdSPierre-Louis Bossart .link_power_up = intel_link_power_up,
660806f5abdSPierre-Louis Bossart .link_power_down = intel_link_power_down,
6614d1e2464SPierre-Louis Bossart
662b8e39bc4SPierre-Louis Bossart .shim_check_wake = intel_shim_check_wake,
663b8e39bc4SPierre-Louis Bossart .shim_wake = intel_shim_wake,
664b8e39bc4SPierre-Louis Bossart
66532c3aa85SPierre-Louis Bossart .pre_bank_switch = intel_pre_bank_switch,
66632c3aa85SPierre-Louis Bossart .post_bank_switch = intel_post_bank_switch,
66732c3aa85SPierre-Louis Bossart
6684d1e2464SPierre-Louis Bossart .sync_arm = intel_sync_arm,
6694d1e2464SPierre-Louis Bossart .sync_go_unlocked = intel_sync_go_unlocked,
6704d1e2464SPierre-Louis Bossart .sync_go = intel_sync_go,
6717ba18639SPierre-Louis Bossart .sync_check_cmdsync_unlocked = intel_check_cmdsync_unlocked,
672bcf71917SPierre-Louis Bossart
673bcf71917SPierre-Louis Bossart .program_sdi = intel_program_sdi,
6746f23f4e2SPierre-Louis Bossart };
6756f23f4e2SPierre-Louis Bossart EXPORT_SYMBOL_NS(sdw_intel_lnl_hw_ops, SOUNDWIRE_INTEL);
676806f5abdSPierre-Louis Bossart
677806f5abdSPierre-Louis Bossart MODULE_IMPORT_NS(SND_SOC_SOF_HDA_MLINK);
678