diff --git a/include/sound/soc.h b/include/sound/soc.h index 5e3919ffb00c..fc4fcac72cf7 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1193,6 +1193,8 @@ struct snd_soc_pcm_runtime { ((i) < (rtd)->num_cpus + (rtd)->num_codecs) && \ ((dai) = (rtd)->dais[i]); \ (i)++) +#define for_each_rtd_dais_rollback(rtd, i, dai) \ + for (; (--(i) >= 0) && ((dai) = (rtd)->dais[i]);) void snd_soc_close_delayed_work(struct snd_soc_pcm_runtime *rtd); @@ -1361,6 +1363,8 @@ void snd_soc_unregister_dai(struct snd_soc_dai *dai); struct snd_soc_dai *snd_soc_find_dai( const struct snd_soc_dai_link_component *dlc); +struct snd_soc_dai *snd_soc_find_dai_with_mutex( + const struct snd_soc_dai_link_component *dlc); #include diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c index 5fe724728e84..e4675cfff7b2 100644 --- a/sound/soc/codecs/max98373-sdw.c +++ b/sound/soc/codecs/max98373-sdw.c @@ -838,8 +838,8 @@ static int max98373_sdw_probe(struct sdw_slave *slave, /* Regmap Initialization */ regmap = devm_regmap_init_sdw(slave, &max98373_sdw_regmap); - if (!regmap) - return -EINVAL; + if (IS_ERR(regmap)) + return PTR_ERR(regmap); return max98373_init(slave, regmap); } diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index 5e445fee4ef5..821e7395f90f 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -306,6 +306,13 @@ static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai, struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(dai->component); int ret; + /* + * Some sound card sets 0 Hz as reset, + * but it is impossible to set. Ignore it here + */ + if (freq == 0) + return 0; + if (freq > PCM3168A_MAX_SYSCLK) return -EINVAL; diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index b0ba0d2acbdd..56e952a904a3 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -684,8 +684,8 @@ static int rt1308_sdw_probe(struct sdw_slave *slave, /* Regmap Initialization */ regmap = devm_regmap_init_sdw(slave, &rt1308_sdw_regmap); - if (!regmap) - return -EINVAL; + if (IS_ERR(regmap)) + return PTR_ERR(regmap); rt1308_sdw_init(&slave->dev, regmap, slave); diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c index 4d14048d1197..1d24bf040718 100644 --- a/sound/soc/codecs/rt700-sdw.c +++ b/sound/soc/codecs/rt700-sdw.c @@ -452,8 +452,8 @@ static int rt700_sdw_probe(struct sdw_slave *slave, /* Regmap Initialization */ sdw_regmap = devm_regmap_init_sdw(slave, &rt700_sdw_regmap); - if (!sdw_regmap) - return -EINVAL; + if (IS_ERR(sdw_regmap)) + return PTR_ERR(sdw_regmap); regmap = devm_regmap_init(&slave->dev, NULL, &slave->dev, &rt700_regmap); diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c index 45b928954b58..7efff130a638 100644 --- a/sound/soc/codecs/rt711-sdw.c +++ b/sound/soc/codecs/rt711-sdw.c @@ -452,8 +452,8 @@ static int rt711_sdw_probe(struct sdw_slave *slave, /* Regmap Initialization */ sdw_regmap = devm_regmap_init_sdw(slave, &rt711_sdw_regmap); - if (!sdw_regmap) - return -EINVAL; + if (IS_ERR(sdw_regmap)) + return PTR_ERR(sdw_regmap); regmap = devm_regmap_init(&slave->dev, NULL, &slave->dev, &rt711_regmap); diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c index d11b23d6b240..68a36739f1b0 100644 --- a/sound/soc/codecs/rt715-sdw.c +++ b/sound/soc/codecs/rt715-sdw.c @@ -527,8 +527,8 @@ static int rt715_sdw_probe(struct sdw_slave *slave, /* Regmap Initialization */ sdw_regmap = devm_regmap_init_sdw(slave, &rt715_sdw_regmap); - if (!sdw_regmap) - return -EINVAL; + if (IS_ERR(sdw_regmap)) + return PTR_ERR(sdw_regmap); regmap = devm_regmap_init(&slave->dev, NULL, &slave->dev, &rt715_regmap); diff --git a/sound/soc/codecs/tlv320adcx140.c b/sound/soc/codecs/tlv320adcx140.c index 5cd50d841177..8efe20605f9b 100644 --- a/sound/soc/codecs/tlv320adcx140.c +++ b/sound/soc/codecs/tlv320adcx140.c @@ -842,6 +842,18 @@ static int adcx140_codec_probe(struct snd_soc_component *component) if (ret) goto out; + if (adcx140->supply_areg == NULL) + sleep_cfg_val |= ADCX140_AREG_INTERNAL; + + ret = regmap_write(adcx140->regmap, ADCX140_SLEEP_CFG, sleep_cfg_val); + if (ret) { + dev_err(adcx140->dev, "setting sleep config failed %d\n", ret); + goto out; + } + + /* 8.4.3: Wait >= 1ms after entering active mode. */ + usleep_range(1000, 100000); + pdm_count = device_property_count_u32(adcx140->dev, "ti,pdm-edge-select"); if (pdm_count <= ADCX140_NUM_PDM_EDGES && pdm_count > 0) { @@ -889,18 +901,6 @@ static int adcx140_codec_probe(struct snd_soc_component *component) if (ret) goto out; - if (adcx140->supply_areg == NULL) - sleep_cfg_val |= ADCX140_AREG_INTERNAL; - - ret = regmap_write(adcx140->regmap, ADCX140_SLEEP_CFG, sleep_cfg_val); - if (ret) { - dev_err(adcx140->dev, "setting sleep config failed %d\n", ret); - goto out; - } - - /* 8.4.3: Wait >= 1ms after entering active mode. */ - usleep_range(1000, 100000); - ret = regmap_update_bits(adcx140->regmap, ADCX140_BIAS_CFG, ADCX140_MIC_BIAS_VAL_MSK | ADCX140_MIC_BIAS_VREF_MSK, bias_cfg); @@ -980,6 +980,8 @@ static int adcx140_i2c_probe(struct i2c_client *i2c, if (!adcx140) return -ENOMEM; + adcx140->dev = &i2c->dev; + adcx140->gpio_reset = devm_gpiod_get_optional(adcx140->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(adcx140->gpio_reset)) @@ -1007,7 +1009,7 @@ static int adcx140_i2c_probe(struct i2c_client *i2c, ret); return ret; } - adcx140->dev = &i2c->dev; + i2c_set_clientdata(i2c, adcx140); return devm_snd_soc_register_component(&i2c->dev, diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 038be667c1a6..fc9ea198ac79 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -3514,6 +3514,8 @@ int wm8994_mic_detect(struct snd_soc_component *component, struct snd_soc_jack * return -EINVAL; } + pm_runtime_get_sync(component->dev); + switch (micbias) { case 1: micdet = &wm8994->micdet[0]; @@ -3561,6 +3563,8 @@ int wm8994_mic_detect(struct snd_soc_component *component, struct snd_soc_jack * snd_soc_dapm_sync(dapm); + pm_runtime_put(component->dev); + return 0; } EXPORT_SYMBOL_GPL(wm8994_mic_detect); @@ -3932,6 +3936,8 @@ int wm8958_mic_detect(struct snd_soc_component *component, struct snd_soc_jack * return -EINVAL; } + pm_runtime_get_sync(component->dev); + if (jack) { snd_soc_dapm_force_enable_pin(dapm, "CLK_SYS"); snd_soc_dapm_sync(dapm); @@ -4000,6 +4006,8 @@ int wm8958_mic_detect(struct snd_soc_component *component, struct snd_soc_jack * snd_soc_dapm_sync(dapm); } + pm_runtime_put(component->dev); + return 0; } EXPORT_SYMBOL_GPL(wm8958_mic_detect); @@ -4193,11 +4201,13 @@ static int wm8994_component_probe(struct snd_soc_component *component) wm8994->hubs.dcs_readback_mode = 2; break; } + wm8994->hubs.micd_scthr = true; break; case WM8958: wm8994->hubs.dcs_readback_mode = 1; wm8994->hubs.hp_startup_mode = 1; + wm8994->hubs.micd_scthr = true; switch (control->revision) { case 0: diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 891effe220fe..0c881846f485 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -1223,6 +1223,9 @@ int wm_hubs_handle_analogue_pdata(struct snd_soc_component *component, snd_soc_component_update_bits(component, WM8993_ADDITIONAL_CONTROL, WM8993_LINEOUT2_FB, WM8993_LINEOUT2_FB); + if (!hubs->micd_scthr) + return 0; + snd_soc_component_update_bits(component, WM8993_MICBIAS, WM8993_JD_SCTHR_MASK | WM8993_JD_THR_MASK | WM8993_MICB1_LVL | WM8993_MICB2_LVL, diff --git a/sound/soc/codecs/wm_hubs.h b/sound/soc/codecs/wm_hubs.h index 4b8e5f0d6e32..988b29e63060 100644 --- a/sound/soc/codecs/wm_hubs.h +++ b/sound/soc/codecs/wm_hubs.h @@ -27,6 +27,7 @@ struct wm_hubs_data { int hp_startup_mode; int series_startup; int no_series_update; + bool micd_scthr; bool no_cache_dac_hp_direct; struct list_head dcs_cache; diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index b1cac7abdc0a..fba2c795ce0d 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -333,6 +333,17 @@ static int sst_media_open(struct snd_pcm_substream *substream, if (ret_val < 0) goto out_power_up; + /* + * Make sure the period to be multiple of 1ms to align the + * design of firmware. Apply same rule to buffer size to make + * sure alsa could always find a value for period size + * regardless the buffer size given by user space. + */ + snd_pcm_hw_constraint_step(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 48); + snd_pcm_hw_constraint_step(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 48); + /* Make sure, that the period size is always even */ snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS, 2); diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 479992f4e97a..fc202747ba83 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -591,6 +591,16 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_SSP0_AIF1 | BYT_RT5640_MCLK_EN), }, + { /* MPMAN Converter 9, similar hw as the I.T.Works TW891 2-in-1 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "MPMAN"), + DMI_MATCH(DMI_PRODUCT_NAME, "Converter9"), + }, + .driver_data = (void *)(BYTCR_INPUT_DEFAULTS | + BYT_RT5640_MONO_SPEAKER | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, { /* MPMAN MPWIN895CL */ .matches = { diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index ca4900036ead..bc50eda297ab 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -181,7 +181,7 @@ static void skl_set_hda_codec_autosuspend_delay(struct snd_soc_card *card) struct snd_soc_dai *dai; for_each_card_rtds(card, rtd) { - if (!strstr(rtd->dai_link->codecs->name, "ehdaudio")) + if (!strstr(rtd->dai_link->codecs->name, "ehdaudio0D0")) continue; dai = asoc_rtd_to_codec(rtd, 0); hda_pvt = snd_soc_component_get_drvdata(dai->component); diff --git a/sound/soc/intel/boards/sof_maxim_common.c b/sound/soc/intel/boards/sof_maxim_common.c index 1a6961592029..b6e63ea13d64 100644 --- a/sound/soc/intel/boards/sof_maxim_common.c +++ b/sound/soc/intel/boards/sof_maxim_common.c @@ -66,6 +66,10 @@ int max98373_trigger(struct snd_pcm_substream *substream, int cmd) int j; int ret = 0; + /* set spk pin by playback only */ + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + return 0; + for_each_rtd_codec_dais(rtd, j, codec_dai) { struct snd_soc_component *component = codec_dai->component; struct snd_soc_dapm_context *dapm = @@ -86,9 +90,6 @@ int max98373_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - /* Make sure no streams are active before disable pin */ - if (snd_soc_dai_active(codec_dai) != 1) - break; ret = snd_soc_dapm_disable_pin(dapm, pin_name); if (!ret) snd_soc_dapm_sync(dapm); diff --git a/sound/soc/intel/haswell/sst-haswell-dsp.c b/sound/soc/intel/haswell/sst-haswell-dsp.c index de80e19454c1..88c3f63bded9 100644 --- a/sound/soc/intel/haswell/sst-haswell-dsp.c +++ b/sound/soc/intel/haswell/sst-haswell-dsp.c @@ -243,92 +243,45 @@ static irqreturn_t hsw_irq(int irq, void *context) return ret; } -#define CSR_DEFAULT_VALUE 0x8480040E -#define ISC_DEFAULT_VALUE 0x0 -#define ISD_DEFAULT_VALUE 0x0 -#define IMC_DEFAULT_VALUE 0x7FFF0003 -#define IMD_DEFAULT_VALUE 0x7FFF0003 -#define IPCC_DEFAULT_VALUE 0x0 -#define IPCD_DEFAULT_VALUE 0x0 -#define CLKCTL_DEFAULT_VALUE 0x7FF -#define CSR2_DEFAULT_VALUE 0x0 -#define LTR_CTRL_DEFAULT_VALUE 0x0 -#define HMD_CTRL_DEFAULT_VALUE 0x0 - -static void hsw_set_shim_defaults(struct sst_dsp *sst) -{ - sst_dsp_shim_write_unlocked(sst, SST_CSR, CSR_DEFAULT_VALUE); - sst_dsp_shim_write_unlocked(sst, SST_ISRX, ISC_DEFAULT_VALUE); - sst_dsp_shim_write_unlocked(sst, SST_ISRD, ISD_DEFAULT_VALUE); - sst_dsp_shim_write_unlocked(sst, SST_IMRX, IMC_DEFAULT_VALUE); - sst_dsp_shim_write_unlocked(sst, SST_IMRD, IMD_DEFAULT_VALUE); - sst_dsp_shim_write_unlocked(sst, SST_IPCX, IPCC_DEFAULT_VALUE); - sst_dsp_shim_write_unlocked(sst, SST_IPCD, IPCD_DEFAULT_VALUE); - sst_dsp_shim_write_unlocked(sst, SST_CLKCTL, CLKCTL_DEFAULT_VALUE); - sst_dsp_shim_write_unlocked(sst, SST_CSR2, CSR2_DEFAULT_VALUE); - sst_dsp_shim_write_unlocked(sst, SST_LTRC, LTR_CTRL_DEFAULT_VALUE); - sst_dsp_shim_write_unlocked(sst, SST_HMDC, HMD_CTRL_DEFAULT_VALUE); -} - -/* all clock-gating minus DCLCGE and DTCGE */ -#define SST_VDRTCL2_CG_OTHER 0xB7D - static void hsw_set_dsp_D3(struct sst_dsp *sst) { + u32 val; u32 reg; - /* disable clock core gating */ + /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */ reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); - reg &= ~(SST_VDRTCL2_DCLCGE); + reg &= ~(SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE); writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2); - /* stall, reset and set 24MHz XOSC */ - sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, - SST_CSR_24MHZ_LPCS | SST_CSR_STALL | SST_CSR_RST, - SST_CSR_24MHZ_LPCS | SST_CSR_STALL | SST_CSR_RST); + /* enable power gating and switch off DRAM & IRAM blocks */ + val = readl(sst->addr.pci_cfg + SST_VDRTCTL0); + val |= SST_VDRTCL0_DSRAMPGE_MASK | + SST_VDRTCL0_ISRAMPGE_MASK; + val &= ~(SST_VDRTCL0_D3PGD | SST_VDRTCL0_D3SRAMPGD); + writel(val, sst->addr.pci_cfg + SST_VDRTCTL0); - /* DRAM power gating all */ - reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0); - reg |= SST_VDRTCL0_ISRAMPGE_MASK | - SST_VDRTCL0_DSRAMPGE_MASK; - reg &= ~(SST_VDRTCL0_D3SRAMPGD); - reg |= SST_VDRTCL0_D3PGD; - writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0); - udelay(50); + /* switch off audio PLL */ + val = readl(sst->addr.pci_cfg + SST_VDRTCTL2); + val |= SST_VDRTCL2_APLLSE_MASK; + writel(val, sst->addr.pci_cfg + SST_VDRTCTL2); - /* PLL shutdown enable */ - reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); - reg |= SST_VDRTCL2_APLLSE_MASK; - writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2); - - /* disable MCLK */ + /* disable MCLK(clkctl.smos = 0) */ sst_dsp_shim_update_bits_unlocked(sst, SST_CLKCTL, - SST_CLKCTL_MASK, 0); + SST_CLKCTL_MASK, 0); - /* switch clock gating */ - reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); - reg |= SST_VDRTCL2_CG_OTHER; - reg &= ~(SST_VDRTCL2_DTCGE); - writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2); - /* enable DTCGE separatelly */ - reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); - reg |= SST_VDRTCL2_DTCGE; - writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2); - - /* set shim defaults */ - hsw_set_shim_defaults(sst); - - /* set D3 */ - reg = readl(sst->addr.pci_cfg + SST_PMCS); - reg |= SST_PMCS_PS_MASK; - writel(reg, sst->addr.pci_cfg + SST_PMCS); + /* Set D3 state, delay 50 us */ + val = readl(sst->addr.pci_cfg + SST_PMCS); + val |= SST_PMCS_PS_MASK; + writel(val, sst->addr.pci_cfg + SST_PMCS); udelay(50); - /* enable clock core gating */ + /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */ reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); - reg |= SST_VDRTCL2_DCLCGE; + reg |= SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE; writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2); + udelay(50); + } static void hsw_reset(struct sst_dsp *sst) @@ -346,62 +299,75 @@ static void hsw_reset(struct sst_dsp *sst) SST_CSR_RST | SST_CSR_STALL, SST_CSR_STALL); } -/* recommended CSR state for power-up */ -#define SST_CSR_D0_MASK (0x18A09C0C | SST_CSR_DCS_MASK) - static int hsw_set_dsp_D0(struct sst_dsp *sst) { - u32 reg; + int tries = 10; + u32 reg, fw_dump_bit; - /* disable clock core gating */ + /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */ reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); - reg &= ~(SST_VDRTCL2_DCLCGE); + reg &= ~(SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE); writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2); - /* switch clock gating */ - reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); - reg |= SST_VDRTCL2_CG_OTHER; - reg &= ~(SST_VDRTCL2_DTCGE); - writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2); - - /* set D0 */ - reg = readl(sst->addr.pci_cfg + SST_PMCS); - reg &= ~(SST_PMCS_PS_MASK); - writel(reg, sst->addr.pci_cfg + SST_PMCS); - - /* DRAM power gating none */ + /* Disable D3PG (VDRTCTL0.D3PGD = 1) */ reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0); - reg &= ~(SST_VDRTCL0_ISRAMPGE_MASK | - SST_VDRTCL0_DSRAMPGE_MASK); - reg |= SST_VDRTCL0_D3SRAMPGD; reg |= SST_VDRTCL0_D3PGD; writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0); - mdelay(10); - /* set shim defaults */ - hsw_set_shim_defaults(sst); + /* Set D0 state */ + reg = readl(sst->addr.pci_cfg + SST_PMCS); + reg &= ~SST_PMCS_PS_MASK; + writel(reg, sst->addr.pci_cfg + SST_PMCS); - /* restore MCLK */ + /* check that ADSP shim is enabled */ + while (tries--) { + reg = readl(sst->addr.pci_cfg + SST_PMCS) & SST_PMCS_PS_MASK; + if (reg == 0) + goto finish; + + msleep(1); + } + + return -ENODEV; + +finish: + /* select SSP1 19.2MHz base clock, SSP clock 0, turn off Low Power Clock */ + sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, + SST_CSR_S1IOCS | SST_CSR_SBCS1 | SST_CSR_LPCS, 0x0); + + /* stall DSP core, set clk to 192/96Mhz */ + sst_dsp_shim_update_bits_unlocked(sst, + SST_CSR, SST_CSR_STALL | SST_CSR_DCS_MASK, + SST_CSR_STALL | SST_CSR_DCS(4)); + + /* Set 24MHz MCLK, prevent local clock gating, enable SSP0 clock */ sst_dsp_shim_update_bits_unlocked(sst, SST_CLKCTL, - SST_CLKCTL_MASK, SST_CLKCTL_MASK); + SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0, + SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0); - /* PLL shutdown disable */ + /* Stall and reset core, set CSR */ + hsw_reset(sst); + + /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */ reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); - reg &= ~(SST_VDRTCL2_APLLSE_MASK); + reg |= SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE; writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2); - sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, - SST_CSR_D0_MASK, SST_CSR_SBCS0 | SST_CSR_SBCS1 | - SST_CSR_STALL | SST_CSR_DCS(4)); udelay(50); - /* enable clock core gating */ + /* switch on audio PLL */ reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); - reg |= SST_VDRTCL2_DCLCGE; + reg &= ~SST_VDRTCL2_APLLSE_MASK; writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2); - /* clear reset */ - sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, SST_CSR_RST, 0); + /* set default power gating control, enable power gating control for all blocks. that is, + can't be accessed, please enable each block before accessing. */ + reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0); + reg |= SST_VDRTCL0_DSRAMPGE_MASK | SST_VDRTCL0_ISRAMPGE_MASK; + /* for D0, always enable the block(DSRAM[0]) used for FW dump */ + fw_dump_bit = 1 << SST_VDRTCL0_DSRAMPGE_SHIFT; + writel(reg & ~fw_dump_bit, sst->addr.pci_cfg + SST_VDRTCTL0); + /* disable DMA finish function for SSP0 & SSP1 */ sst_dsp_shim_update_bits_unlocked(sst, SST_CSR2, SST_CSR2_SDFD_SSP1, @@ -418,6 +384,12 @@ static int hsw_set_dsp_D0(struct sst_dsp *sst) sst_dsp_shim_update_bits(sst, SST_IMRD, (SST_IMRD_DONE | SST_IMRD_BUSY | SST_IMRD_SSP0 | SST_IMRD_DMAC), 0x0); + /* clear IPC registers */ + sst_dsp_shim_write(sst, SST_IPCX, 0x0); + sst_dsp_shim_write(sst, SST_IPCD, 0x0); + sst_dsp_shim_write(sst, 0x80, 0x6); + sst_dsp_shim_write(sst, 0xe0, 0x300a); + return 0; } @@ -443,6 +415,11 @@ static void hsw_sleep(struct sst_dsp *sst) { dev_dbg(sst->dev, "HSW_PM dsp runtime suspend\n"); + /* put DSP into reset and stall */ + sst_dsp_shim_update_bits(sst, SST_CSR, + SST_CSR_24MHZ_LPCS | SST_CSR_RST | SST_CSR_STALL, + SST_CSR_RST | SST_CSR_STALL | SST_CSR_24MHZ_LPCS); + hsw_set_dsp_D3(sst); dev_dbg(sst->dev, "HSW_PM dsp runtime suspend exit\n"); } diff --git a/sound/soc/meson/axg-toddr.c b/sound/soc/meson/axg-toddr.c index e711abcf8c12..d6adf7edea41 100644 --- a/sound/soc/meson/axg-toddr.c +++ b/sound/soc/meson/axg-toddr.c @@ -18,6 +18,7 @@ #define CTRL0_TODDR_SEL_RESAMPLE BIT(30) #define CTRL0_TODDR_EXT_SIGNED BIT(29) #define CTRL0_TODDR_PP_MODE BIT(28) +#define CTRL0_TODDR_SYNC_CH BIT(27) #define CTRL0_TODDR_TYPE_MASK GENMASK(15, 13) #define CTRL0_TODDR_TYPE(x) ((x) << 13) #define CTRL0_TODDR_MSB_POS_MASK GENMASK(12, 8) @@ -189,10 +190,31 @@ static const struct axg_fifo_match_data axg_toddr_match_data = { .dai_drv = &axg_toddr_dai_drv }; +static int g12a_toddr_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai); + int ret; + + ret = axg_toddr_dai_startup(substream, dai); + if (ret) + return ret; + + /* + * Make sure the first channel ends up in the at beginning of the output + * As weird as it looks, without this the first channel may be misplaced + * in memory, with a random shift of 2 channels. + */ + regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_TODDR_SYNC_CH, + CTRL0_TODDR_SYNC_CH); + + return 0; +} + static const struct snd_soc_dai_ops g12a_toddr_ops = { .prepare = g12a_toddr_dai_prepare, .hw_params = axg_toddr_dai_hw_params, - .startup = axg_toddr_dai_startup, + .startup = g12a_toddr_dai_startup, .shutdown = axg_toddr_dai_shutdown, }; diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c index 083413abc2f6..575e2aefefe3 100644 --- a/sound/soc/qcom/apq8016_sbc.c +++ b/sound/soc/qcom/apq8016_sbc.c @@ -143,6 +143,7 @@ static int apq8016_sbc_platform_probe(struct platform_device *pdev) card = &data->card; card->dev = dev; + card->owner = THIS_MODULE; card->dapm_widgets = apq8016_sbc_dapm_widgets; card->num_dapm_widgets = ARRAY_SIZE(apq8016_sbc_dapm_widgets); diff --git a/sound/soc/qcom/apq8096.c b/sound/soc/qcom/apq8096.c index 253549600c5a..1a69baefc5ce 100644 --- a/sound/soc/qcom/apq8096.c +++ b/sound/soc/qcom/apq8096.c @@ -114,6 +114,7 @@ static int apq8096_platform_probe(struct platform_device *pdev) return -ENOMEM; card->dev = dev; + card->owner = THIS_MODULE; dev_set_drvdata(dev, card); ret = qcom_snd_parse_of(card); if (ret) diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c index 5194d90ddb96..fd69cf8b1f23 100644 --- a/sound/soc/qcom/common.c +++ b/sound/soc/qcom/common.c @@ -52,8 +52,10 @@ int qcom_snd_parse_of(struct snd_soc_card *card) for_each_child_of_node(dev->of_node, np) { dlc = devm_kzalloc(dev, 2 * sizeof(*dlc), GFP_KERNEL); - if (!dlc) - return -ENOMEM; + if (!dlc) { + ret = -ENOMEM; + goto err; + } link->cpus = &dlc[0]; link->platforms = &dlc[1]; diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c index 0d10fba53945..ab1bf23c21a6 100644 --- a/sound/soc/qcom/sdm845.c +++ b/sound/soc/qcom/sdm845.c @@ -555,6 +555,7 @@ static int sdm845_snd_platform_probe(struct platform_device *pdev) card->dapm_widgets = sdm845_snd_widgets; card->num_dapm_widgets = ARRAY_SIZE(sdm845_snd_widgets); card->dev = dev; + card->owner = THIS_MODULE; dev_set_drvdata(dev, card); ret = qcom_snd_parse_of(card); if (ret) diff --git a/sound/soc/qcom/storm.c b/sound/soc/qcom/storm.c index c0c388d4db82..80c9cf2f254a 100644 --- a/sound/soc/qcom/storm.c +++ b/sound/soc/qcom/storm.c @@ -96,6 +96,7 @@ static int storm_platform_probe(struct platform_device *pdev) return -ENOMEM; card->dev = &pdev->dev; + card->owner = THIS_MODULE; ret = snd_soc_of_parse_card_name(card, "qcom,model"); if (ret) { diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2fe1b2ec7c8f..fe11856d7a63 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -834,6 +834,19 @@ struct snd_soc_dai *snd_soc_find_dai( } EXPORT_SYMBOL_GPL(snd_soc_find_dai); +struct snd_soc_dai *snd_soc_find_dai_with_mutex( + const struct snd_soc_dai_link_component *dlc) +{ + struct snd_soc_dai *dai; + + mutex_lock(&client_mutex); + dai = snd_soc_find_dai(dlc); + mutex_unlock(&client_mutex); + + return dai; +} +EXPORT_SYMBOL_GPL(snd_soc_find_dai_with_mutex); + static int soc_dai_link_sanity_check(struct snd_soc_card *card, struct snd_soc_dai_link *link) { diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 91a2551e4cef..0dbd312aad08 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -412,14 +412,14 @@ void snd_soc_dai_link_set_capabilities(struct snd_soc_dai_link *dai_link) supported_codec = false; for_each_link_cpus(dai_link, i, cpu) { - dai = snd_soc_find_dai(cpu); + dai = snd_soc_find_dai_with_mutex(cpu); if (dai && snd_soc_dai_stream_valid(dai, direction)) { supported_cpu = true; break; } } for_each_link_codecs(dai_link, i, codec) { - dai = snd_soc_find_dai(codec); + dai = snd_soc_find_dai_with_mutex(codec); if (dai && snd_soc_dai_stream_valid(dai, direction)) { supported_codec = true; break; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 00ac1cbf6f88..4c9d4cd8cf0b 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -812,7 +812,7 @@ dynamic: return 0; config_err: - for_each_rtd_dais(rtd, i, dai) + for_each_rtd_dais_rollback(rtd, i, dai) snd_soc_dai_shutdown(dai, substream); snd_soc_link_shutdown(substream); diff --git a/sound/soc/ti/ams-delta.c b/sound/soc/ti/ams-delta.c index 5c47de96c529..57feb473a579 100644 --- a/sound/soc/ti/ams-delta.c +++ b/sound/soc/ti/ams-delta.c @@ -446,12 +446,12 @@ static const struct snd_soc_dai_ops ams_delta_dai_ops = { /* Will be used if the codec ever has its own digital_mute function */ static int ams_delta_startup(struct snd_pcm_substream *substream) { - return ams_delta_digital_mute(NULL, 0, substream->stream); + return ams_delta_mute(NULL, 0, substream->stream); } static void ams_delta_shutdown(struct snd_pcm_substream *substream) { - ams_delta_digital_mute(NULL, 1, substream->stream); + ams_delta_mute(NULL, 1, substream->stream); }