sound: starfive: spdif: Fixed playback failed after hibernation
[platform/kernel/linux-starfive.git] / sound / soc / starfive / starfive_spdif_pcm.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  ******************************************************************************
4  * @file  sf_spdif_pcm.c
5  * @author  StarFive Technology
6  * @version  V1.0
7  * @date  05/27/2021
8  * @brief
9  ******************************************************************************
10  * @copy
11  *
12  * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
13  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
14  * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY
15  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
16  * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
17  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
18  *
19  * <h2><center>&copy; COPYRIGHT 20120 Shanghai StarFive Technology Co., Ltd. </center></h2>
20  */
21
22 #include <linux/io.h>
23 #include <linux/rcupdate.h>
24 #include <sound/pcm.h>
25 #include <sound/pcm_params.h>
26 #include "starfive_spdif.h"
27
28 #define BUFFER_BYTES_MAX        (3 * 2 * 8 * PERIOD_BYTES_MIN)
29 #define PERIOD_BYTES_MIN        4096
30 #define PERIODS_MIN             2
31
32 static unsigned int sf_spdif_pcm_tx(struct sf_spdif_dev *dev,
33                 struct snd_pcm_runtime *runtime, unsigned int tx_ptr,
34                 bool *period_elapsed, snd_pcm_format_t format)
35 {
36         u32 data[2];
37         unsigned int period_pos = tx_ptr % runtime->period_size;
38         int i;
39
40         /* two- channel and signal-channel mode */
41         if (dev->channels) {
42                 const u16 (*p16)[2] = (void *)runtime->dma_area;
43                 const u32 (*p32)[2] = (void *)runtime->dma_area;
44
45                 for (i = 0; i < dev->fifo_th; i++) {
46                         if (format == SNDRV_PCM_FORMAT_S16_LE) {
47                                 data[0] = p16[tx_ptr][0];
48                                 data[0] = data[0]<<8;
49                                 data[0] &= 0x00ffff00;
50                                 data[1] = p16[tx_ptr][1];
51                                 data[1] = data[1]<<8;
52                                 data[1] &= 0x00ffff00;
53                         } else if (format == SNDRV_PCM_FORMAT_S24_LE) {
54                                 data[0] = p32[tx_ptr][0];
55                                 data[1] = p32[tx_ptr][1];
56
57                                 /*
58                                  * To adapt S24_3LE and ALSA pass parameter of S24_LE.
59                                  * operation of S24_LE should be same to S24_3LE.
60                                  * So it would wrong when playback S24_LE file.
61                                  * when want to playback S24_LE file, should add in there:
62                                  * data[0] = data[0]>>8;
63                                  * data[1] = data[1]>>8;
64                                  */
65
66                                 data[0] &= 0x00ffffff;
67                                 data[1] &= 0x00ffffff;
68                         } else if (format == SNDRV_PCM_FORMAT_S24_3LE) {
69                                 data[0] = p32[tx_ptr][0];
70                                 data[1] = p32[tx_ptr][1];
71                                 data[0] &= 0x00ffffff;
72                                 data[1] &= 0x00ffffff;
73                         } else if (format == SNDRV_PCM_FORMAT_S32_LE) {
74                                 data[0] = p32[tx_ptr][0];
75                                 data[0] = data[0]>>8;
76                                 data[1] = p32[tx_ptr][1];
77                                 data[1] = data[1]>>8;
78                         }
79
80                         iowrite32(data[0], dev->spdif_base + SPDIF_FIFO_ADDR);
81                         iowrite32(data[1], dev->spdif_base + SPDIF_FIFO_ADDR);
82                         period_pos++;
83                         if (++tx_ptr >= runtime->buffer_size)
84                                 tx_ptr = 0;
85                 }
86         } else {
87                 const u16 (*p16) = (void *)runtime->dma_area;
88                 const u32 (*p32) = (void *)runtime->dma_area;
89
90                 for (i = 0; i < dev->fifo_th; i++) {
91                         if (format == SNDRV_PCM_FORMAT_S16_LE) {
92                                 data[0] = p16[tx_ptr];
93                                 data[0] = data[0]<<8;
94                                 data[0] &= 0x00ffff00;
95                         } else if (format == SNDRV_PCM_FORMAT_S24_LE ||
96                                 format == SNDRV_PCM_FORMAT_S24_3LE) {
97                                 data[0] = p32[tx_ptr];
98                                 data[0] &= 0x00ffffff;
99                         } else if (format == SNDRV_PCM_FORMAT_S32_LE) {
100                                 data[0] = p32[tx_ptr];
101                                 data[0] = data[0]>>8;
102                         }
103
104                         iowrite32(data[0], dev->spdif_base + SPDIF_FIFO_ADDR);
105                         period_pos++;
106                         if (++tx_ptr >= runtime->buffer_size)
107                                 tx_ptr = 0;
108                 }
109         }
110
111         *period_elapsed = period_pos >= runtime->period_size;
112         return tx_ptr;
113 }
114
115 static unsigned int sf_spdif_pcm_rx(struct sf_spdif_dev *dev,
116                 struct snd_pcm_runtime *runtime, unsigned int rx_ptr,
117                 bool *period_elapsed, snd_pcm_format_t format)
118 {
119         u16 (*p16)[2] = (void *)runtime->dma_area;
120         u32 (*p32)[2] = (void *)runtime->dma_area;
121         u32 data[2];
122         unsigned int period_pos = rx_ptr % runtime->period_size;
123         int i;
124
125         for (i = 0; i < dev->fifo_th; i++) {
126                 data[0] = ioread32(dev->spdif_base + SPDIF_FIFO_ADDR);
127                 data[1] = ioread32(dev->spdif_base + SPDIF_FIFO_ADDR);
128                 if (format == SNDRV_PCM_FORMAT_S16_LE) {
129                         p16[rx_ptr][0] = data[0]>>8;
130                         p16[rx_ptr][1] = data[1]>>8;
131                 } else if (format == SNDRV_PCM_FORMAT_S24_LE) {
132                         p32[rx_ptr][0] = data[0];
133                         p32[rx_ptr][1] = data[1];
134                 } else if (format == SNDRV_PCM_FORMAT_S32_LE) {
135                         p32[rx_ptr][0] = data[0]<<8;
136                         p32[rx_ptr][1] = data[1]<<8;
137                 }
138
139                 period_pos++;
140                 if (++rx_ptr >= runtime->buffer_size)
141                         rx_ptr = 0;
142         }
143
144         *period_elapsed = period_pos >= runtime->period_size;
145         return rx_ptr;
146 }
147
148 static const struct snd_pcm_hardware sf_pcm_hardware = {
149         .info = SNDRV_PCM_INFO_INTERLEAVED |
150                 SNDRV_PCM_INFO_MMAP |
151                 SNDRV_PCM_INFO_MMAP_VALID |
152                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
153                 SNDRV_PCM_INFO_PAUSE |
154                 SNDRV_PCM_INFO_RESUME,
155         .rates = SNDRV_PCM_RATE_8000 |
156                 SNDRV_PCM_RATE_11025 |
157                 SNDRV_PCM_RATE_16000 |
158                 SNDRV_PCM_RATE_22050 |
159                 SNDRV_PCM_RATE_32000 |
160                 SNDRV_PCM_RATE_44100 |
161                 SNDRV_PCM_RATE_48000,
162         .rate_min = 8000,
163         .rate_max = 48000,
164         .formats = SNDRV_PCM_FMTBIT_S16_LE |
165                 SNDRV_PCM_FMTBIT_S24_LE |
166                 SNDRV_PCM_FMTBIT_S24_3LE |
167                 SNDRV_PCM_FMTBIT_S32_LE,
168         .channels_min = 1,
169         .channels_max = 2,
170         .buffer_bytes_max = BUFFER_BYTES_MAX,
171         .period_bytes_min = PERIOD_BYTES_MIN,
172         .period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN,
173         .periods_min = PERIODS_MIN,
174         .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
175         .fifo_size = 16,
176 };
177
178 static void sf_spdif_pcm_transfer(struct sf_spdif_dev *dev, bool push)
179 {
180         struct snd_pcm_substream *substream;
181         bool active, period_elapsed;
182
183         rcu_read_lock();
184         if (push)
185                 substream = rcu_dereference(dev->tx_substream);
186         else
187                 substream = rcu_dereference(dev->rx_substream);
188         active = substream && snd_pcm_running(substream);
189         if (active) {
190                 unsigned int ptr;
191                 unsigned int new_ptr;
192
193                 if (push) {
194                         ptr = READ_ONCE(dev->tx_ptr);
195                         new_ptr = dev->tx_fn(dev, substream->runtime, ptr,
196                                         &period_elapsed, dev->format);
197                         cmpxchg(&dev->tx_ptr, ptr, new_ptr);
198                 } else {
199                         ptr = READ_ONCE(dev->rx_ptr);
200                         new_ptr = dev->rx_fn(dev, substream->runtime, ptr,
201                                         &period_elapsed, dev->format);
202                         cmpxchg(&dev->rx_ptr, ptr, new_ptr);
203                 }
204
205                 if (period_elapsed)
206                         snd_pcm_period_elapsed(substream);
207         }
208         rcu_read_unlock();
209 }
210
211 void sf_spdif_pcm_push_tx(struct sf_spdif_dev *dev)
212 {
213         sf_spdif_pcm_transfer(dev, true);
214 }
215
216 void sf_spdif_pcm_pop_rx(struct sf_spdif_dev *dev)
217 {
218         sf_spdif_pcm_transfer(dev, false);
219 }
220
221 static int sf_pcm_open(struct snd_soc_component *component,
222                        struct snd_pcm_substream *substream)
223 {
224         struct snd_pcm_runtime *runtime = substream->runtime;
225         struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
226         struct sf_spdif_dev *dev = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
227
228         snd_soc_set_runtime_hwparams(substream, &sf_pcm_hardware);
229         snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
230         runtime->private_data = dev;
231
232         return 0;
233 }
234
235 static int sf_pcm_close(struct snd_soc_component *component,
236                         struct snd_pcm_substream *substream)
237 {
238         synchronize_rcu();
239         return 0;
240 }
241
242 static int sf_pcm_hw_params(struct snd_soc_component *component,
243                             struct snd_pcm_substream *substream,
244                             struct snd_pcm_hw_params *hw_params)
245 {
246         struct snd_pcm_runtime *runtime = substream->runtime;
247         struct sf_spdif_dev *dev = runtime->private_data;
248
249         switch (params_channels(hw_params)) {
250         case 1:
251         case 2:
252                 break;
253         default:
254                 dev_err(dev->dev, "invalid channels number\n");
255                 return -EINVAL;
256         }
257
258         dev->format = params_format(hw_params);
259         switch (dev->format) {
260         case SNDRV_PCM_FORMAT_S16_LE:
261         case SNDRV_PCM_FORMAT_S24_LE:
262         case SNDRV_PCM_FORMAT_S24_3LE:
263         case SNDRV_PCM_FORMAT_S32_LE:
264                 break;
265         default:
266                 dev_err(dev->dev, "invalid format\n");
267                 return -EINVAL;
268         }
269
270         dev->tx_fn = sf_spdif_pcm_tx;
271         dev->rx_fn = sf_spdif_pcm_rx;
272
273         return 0;
274 }
275
276 static int sf_pcm_trigger(struct snd_soc_component *component,
277                           struct snd_pcm_substream *substream, int cmd)
278 {
279         struct snd_pcm_runtime *runtime = substream->runtime;
280         struct sf_spdif_dev *dev = runtime->private_data;
281         int ret = 0;
282
283         switch (cmd) {
284         case SNDRV_PCM_TRIGGER_START:
285         case SNDRV_PCM_TRIGGER_RESUME:
286         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
287                 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
288                         WRITE_ONCE(dev->tx_ptr, 0);
289                         rcu_assign_pointer(dev->tx_substream, substream);
290                 } else {
291                         WRITE_ONCE(dev->rx_ptr, 0);
292                         rcu_assign_pointer(dev->rx_substream, substream);
293                 }
294                 break;
295         case SNDRV_PCM_TRIGGER_STOP:
296         case SNDRV_PCM_TRIGGER_SUSPEND:
297         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
298                 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
299                         rcu_assign_pointer(dev->tx_substream, NULL);
300                 else
301                         rcu_assign_pointer(dev->rx_substream, NULL);
302                 break;
303         default:
304                 ret = -EINVAL;
305                 break;
306         }
307
308         return ret;
309 }
310
311 static snd_pcm_uframes_t sf_pcm_pointer(struct snd_soc_component *component,
312                                         struct snd_pcm_substream *substream)
313 {
314         struct snd_pcm_runtime *runtime = substream->runtime;
315         struct sf_spdif_dev *dev = runtime->private_data;
316         snd_pcm_uframes_t pos;
317
318         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
319                 pos = READ_ONCE(dev->tx_ptr);
320         else
321                 pos = READ_ONCE(dev->rx_ptr);
322
323         return pos < runtime->buffer_size ? pos : 0;
324 }
325
326 static int sf_pcm_new(struct snd_soc_component *component,
327                       struct snd_soc_pcm_runtime *rtd)
328 {
329         size_t size = sf_pcm_hardware.buffer_bytes_max;
330
331         snd_pcm_set_managed_buffer_all(rtd->pcm,
332                         SNDRV_DMA_TYPE_CONTINUOUS,
333                         NULL, size, size);
334
335         return 0;
336 }
337
338 static const struct snd_soc_component_driver sf_pcm_component = {
339         .open           = sf_pcm_open,
340         .close          = sf_pcm_close,
341         .hw_params      = sf_pcm_hw_params,
342         .trigger        = sf_pcm_trigger,
343         .pointer        = sf_pcm_pointer,
344         .pcm_construct  = sf_pcm_new,
345 };
346
347 int sf_spdif_pcm_register(struct platform_device *pdev)
348 {
349         return devm_snd_soc_register_component(&pdev->dev, &sf_pcm_component,
350                                                NULL, 0);
351 }
352