diff options
author | Zhu Yingjiang <yingjiang.zhu@linux.intel.com> | 2019-06-12 12:23:43 -0500 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2019-06-17 13:45:19 +0100 |
commit | 13063a2ccf79d232889491105a7bd9d552e417fc (patch) | |
tree | 1275e0cadea5429bdc50725f7e62836574328c10 /sound/soc/sof/intel/hda-ctrl.c | |
parent | 24b6ff686fce808346c129bce52836c3339733bf (diff) | |
download | linux-13063a2ccf79d232889491105a7bd9d552e417fc.tar.bz2 |
ASoC: SOF: Intel: hda: add function for hda stop chip
Add common hda_dsp_ctrl_stop_chip() function to stop controller with
the same function handling both HDA and non-HDA cases. This function
disables IRQs and clears status masks. When CONFIG_SND_SOC_SOF_HDA
is defined, also disables the CORB/RIRB, and stops i/o.
Signed-off-by: Zhu Yingjiang <yingjiang.zhu@linux.intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/sof/intel/hda-ctrl.c')
-rw-r--r-- | sound/soc/sof/intel/hda-ctrl.c | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index 07bc123112c9..688ab8d895a9 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -263,3 +263,70 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset) return ret; } + +void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_stream *stream; + int sd_offset; + + if (!bus->chip_init) + return; + + /* disable interrupts in stream descriptor */ + list_for_each_entry(stream, &bus->stream_list, list) { + sd_offset = SOF_STREAM_SD_OFFSET(stream); + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + sd_offset + + SOF_HDA_ADSP_REG_CL_SD_CTL, + SOF_HDA_CL_DMA_SD_INT_MASK, + 0); + } + + /* disable SIE for all streams */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, + SOF_HDA_INT_ALL_STREAM, 0); + + /* disable controller CIE and GIE */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, + SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, + 0); + + /* clear stream status */ + list_for_each_entry(stream, &bus->stream_list, list) { + sd_offset = SOF_STREAM_SD_OFFSET(stream); + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + sd_offset + + SOF_HDA_ADSP_REG_CL_SD_STS, + SOF_HDA_CL_DMA_SD_INT_MASK, + SOF_HDA_CL_DMA_SD_INT_MASK); + } + + /* clear WAKESTS */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, + SOF_HDA_WAKESTS_INT_MASK, + SOF_HDA_WAKESTS_INT_MASK); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* clear rirb status */ + snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK); +#endif + + /* clear interrupt status register */ + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS, + SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* disable CORB/RIRB */ + snd_hdac_bus_stop_cmd_io(bus); +#endif + /* disable position buffer */ + if (bus->posbuf.addr) { + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, + SOF_HDA_ADSP_DPLBASE, 0); + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, + SOF_HDA_ADSP_DPUBASE, 0); + } + + bus->chip_init = false; +} |