bcm27xx: update 6.1 patches to latest version
[openwrt/staging/svanheule.git] / target / linux / bcm27xx / patches-6.1 / 950-0894-ASOC-dwc-Improve-DMA-shutdown.patch
1 From e6baee4502c0228c79408b047096a1259a84353f Mon Sep 17 00:00:00 2001
2 From: Phil Elwell <phil@raspberrypi.com>
3 Date: Mon, 3 Jul 2023 10:14:43 +0100
4 Subject: [PATCH] ASOC: dwc: Improve DMA shutdown
5
6 Disabling the I2S interface with outstanding transfers prevents the
7 DMAC from shutting down, so keep it partially active after a stop.
8
9 Signed-off-by: Phil Elwell <phil@raspberrypi.com>
10 ---
11 sound/soc/dwc/dwc-i2s.c | 72 ++++++++++++++++++++++++++++++++++++-----
12 1 file changed, 64 insertions(+), 8 deletions(-)
13
14 --- a/sound/soc/dwc/dwc-i2s.c
15 +++ b/sound/soc/dwc/dwc-i2s.c
16 @@ -165,24 +165,26 @@ static void i2s_start(struct dw_i2s_dev
17 i2s_write_reg(dev->i2s_base, CER, 1);
18 }
19
20 -static void i2s_stop(struct dw_i2s_dev *dev,
21 - struct snd_pcm_substream *substream)
22 +static void i2s_pause(struct dw_i2s_dev *dev, struct snd_pcm_substream *substream)
23 {
24
25 i2s_clear_irqs(dev, substream->stream);
26 - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
27 - i2s_write_reg(dev->i2s_base, ITER, 0);
28 - else
29 - i2s_write_reg(dev->i2s_base, IRER, 0);
30
31 i2s_disable_irqs(dev, substream->stream, 8);
32
33 if (!dev->active) {
34 i2s_write_reg(dev->i2s_base, CER, 0);
35 - i2s_write_reg(dev->i2s_base, IER, 0);
36 + /* Keep the device enabled until the shutdown - do not clear IER */
37 }
38 }
39
40 +static void i2s_stop(struct dw_i2s_dev *dev, struct snd_pcm_substream *substream)
41 +{
42 + i2s_clear_irqs(dev, substream->stream);
43 +
44 + i2s_disable_irqs(dev, substream->stream, 8);
45 +}
46 +
47 static void dw_i2s_config(struct dw_i2s_dev *dev, int stream)
48 {
49 struct i2s_clk_config_data *config = &dev->config;
50 @@ -288,6 +290,55 @@ static int dw_i2s_hw_params(struct snd_p
51 return 0;
52 }
53
54 +static int dw_i2s_startup(struct snd_pcm_substream *substream,
55 + struct snd_soc_dai *cpu_dai)
56 +{
57 + struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
58 + union dw_i2s_snd_dma_data *dma_data = NULL;
59 + u32 dmacr;
60 +
61 + dev_dbg(dev->dev, "%s(%s)\n", __func__, substream->name);
62 + if (!(dev->capability & DWC_I2S_RECORD) &&
63 + substream->stream == SNDRV_PCM_STREAM_CAPTURE)
64 + return -EINVAL;
65 +
66 + if (!(dev->capability & DWC_I2S_PLAY) &&
67 + substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
68 + return -EINVAL;
69 +
70 + dw_i2s_config(dev, substream->stream);
71 + dmacr = i2s_read_reg(dev->i2s_base, DMACR);
72 + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
73 + dma_data = &dev->play_dma_data;
74 + else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
75 + dma_data = &dev->capture_dma_data;
76 +
77 + snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)dma_data);
78 + i2s_write_reg(dev->i2s_base, DMACR, dmacr);
79 +
80 + return 0;
81 +}
82 +
83 +static void dw_i2s_shutdown(struct snd_pcm_substream *substream,
84 + struct snd_soc_dai *dai)
85 +{
86 + struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
87 +
88 + dev_dbg(dev->dev, "%s(%s)\n", __func__, substream->name);
89 + i2s_disable_channels(dev, substream->stream);
90 + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
91 + i2s_write_reg(dev->i2s_base, ITER, 0);
92 + else
93 + i2s_write_reg(dev->i2s_base, IRER, 0);
94 +
95 + i2s_disable_irqs(dev, substream->stream, 8);
96 +
97 + if (!dev->active) {
98 + i2s_write_reg(dev->i2s_base, CER, 0);
99 + i2s_write_reg(dev->i2s_base, IER, 0);
100 + }
101 +}
102 +
103 static int dw_i2s_prepare(struct snd_pcm_substream *substream,
104 struct snd_soc_dai *dai)
105 {
106 @@ -315,9 +366,12 @@ static int dw_i2s_trigger(struct snd_pcm
107 i2s_start(dev, substream);
108 break;
109
110 + case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
111 + dev->active--;
112 + i2s_pause(dev, substream);
113 + break;
114 case SNDRV_PCM_TRIGGER_STOP:
115 case SNDRV_PCM_TRIGGER_SUSPEND:
116 - case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
117 dev->active--;
118 i2s_stop(dev, substream);
119 break;
120 @@ -394,6 +448,8 @@ static int dw_i2s_set_bclk_ratio(struct
121
122 static const struct snd_soc_dai_ops dw_i2s_dai_ops = {
123 .hw_params = dw_i2s_hw_params,
124 + .startup = dw_i2s_startup,
125 + .shutdown = dw_i2s_shutdown,
126 .prepare = dw_i2s_prepare,
127 .trigger = dw_i2s_trigger,
128 .set_fmt = dw_i2s_set_fmt,