diff options
Diffstat (limited to '')
-rw-r--r-- | drivers/soundwire/intel.c | 68 |
1 files changed, 62 insertions, 6 deletions
diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 1287a325c4..01e1a0f3ec 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -345,8 +345,10 @@ static int intel_link_power_up(struct sdw_intel *sdw) u32 spa_mask, cpa_mask; u32 link_control; int ret = 0; + u32 clock_source; u32 syncprd; u32 sync_reg; + bool lcap_mlcs; mutex_lock(sdw->link_res->shim_lock); @@ -358,12 +360,35 @@ static int intel_link_power_up(struct sdw_intel *sdw) * is only dependent on the oscillator clock provided to * the IP, so adjust based on _DSD properties reported in DSDT * tables. The values reported are based on either 24MHz - * (CNL/CML) or 38.4 MHz (ICL/TGL+). + * (CNL/CML) or 38.4 MHz (ICL/TGL+). On MeteorLake additional + * frequencies are available with the MLCS clock source selection. */ - if (prop->mclk_freq % 6000000) - syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_38_4; - else - syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24; + lcap_mlcs = intel_readl(shim, SDW_SHIM_LCAP) & SDW_SHIM_LCAP_MLCS_MASK; + + if (prop->mclk_freq % 6000000) { + if (prop->mclk_freq % 2400000) { + if (lcap_mlcs) { + syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24_576; + clock_source = SDW_SHIM_MLCS_CARDINAL_CLK; + } else { + dev_err(sdw->cdns.dev, "%s: invalid clock configuration, mclk %d lcap_mlcs %d\n", + __func__, prop->mclk_freq, lcap_mlcs); + ret = -EINVAL; + goto out; + } + } else { + syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_38_4; + clock_source = SDW_SHIM_MLCS_XTAL_CLK; + } + } else { + if (lcap_mlcs) { + syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_96; + clock_source = SDW_SHIM_MLCS_AUDIO_PLL_CLK; + } else { + syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24; + clock_source = SDW_SHIM_MLCS_XTAL_CLK; + } + } if (!*shim_mask) { dev_dbg(sdw->cdns.dev, "powering up all links\n"); @@ -403,6 +428,13 @@ static int intel_link_power_up(struct sdw_intel *sdw) "Failed to set SHIM_SYNC: %d\n", ret); goto out; } + + /* update link clock if needed */ + if (lcap_mlcs) { + link_control = intel_readl(shim, SDW_SHIM_LCTL); + u32p_replace_bits(&link_control, clock_source, SDW_SHIM_LCTL_MLCS_MASK); + intel_writel(shim, SDW_SHIM_LCTL, link_control); + } } *shim_mask |= BIT(link_id); @@ -668,6 +700,24 @@ static int intel_params_stream(struct sdw_intel *sdw, * DAI routines */ +static int intel_free_stream(struct sdw_intel *sdw, + struct snd_pcm_substream *substream, + struct snd_soc_dai *dai, + int link_id) +{ + struct sdw_intel_link_res *res = sdw->link_res; + struct sdw_intel_stream_free_data free_data; + + free_data.substream = substream; + free_data.dai = dai; + free_data.link_id = link_id; + + if (res->ops && res->ops->free_stream && res->dev) + return res->ops->free_stream(res->dev, &free_data); + + return 0; +} + static int intel_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -799,6 +849,7 @@ static int intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); + struct sdw_intel *sdw = cdns_to_intel(cdns); struct sdw_cdns_dai_runtime *dai_runtime; int ret; @@ -819,6 +870,12 @@ intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) return ret; } + ret = intel_free_stream(sdw, substream, dai, sdw->instance); + if (ret < 0) { + dev_err(dai->dev, "intel_free_stream: failed %d\n", ret); + return ret; + } + dai_runtime->pdi = NULL; return 0; @@ -1062,4 +1119,3 @@ const struct sdw_intel_hw_ops sdw_intel_cnl_hw_ops = { .sync_check_cmdsync_unlocked = intel_check_cmdsync_unlocked, }; EXPORT_SYMBOL_NS(sdw_intel_cnl_hw_ops, SOUNDWIRE_INTEL); - |