GNU Linux-libre 5.19-rc6-gnu
[releases.git] / sound / soc / amd / raven / acp3x-i2s.c
1 // SPDX-License-Identifier: GPL-2.0+
2 //
3 // AMD ALSA SoC PCM Driver
4 //
5 //Copyright 2016 Advanced Micro Devices, Inc.
6
7 #include <linux/platform_device.h>
8 #include <linux/module.h>
9 #include <linux/err.h>
10 #include <linux/io.h>
11 #include <sound/pcm_params.h>
12 #include <sound/soc.h>
13 #include <sound/soc-dai.h>
14 #include <linux/dma-mapping.h>
15
16 #include "acp3x.h"
17
18 #define DRV_NAME "acp3x_i2s_playcap"
19
20 static int acp3x_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
21                                         unsigned int fmt)
22 {
23         struct i2s_dev_data *adata;
24         int mode;
25
26         adata = snd_soc_dai_get_drvdata(cpu_dai);
27         mode = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
28         switch (mode) {
29         case SND_SOC_DAIFMT_I2S:
30                 adata->tdm_mode = TDM_DISABLE;
31                 break;
32         case SND_SOC_DAIFMT_DSP_A:
33                 adata->tdm_mode = TDM_ENABLE;
34                 break;
35         default:
36                 return -EINVAL;
37         }
38         return 0;
39 }
40
41 static int acp3x_i2s_set_tdm_slot(struct snd_soc_dai *cpu_dai,
42                 u32 tx_mask, u32 rx_mask, int slots, int slot_width)
43 {
44         struct i2s_dev_data *adata;
45         u32 frm_len;
46         u16 slot_len;
47
48         adata = snd_soc_dai_get_drvdata(cpu_dai);
49
50         /* These values are as per Hardware Spec */
51         switch (slot_width) {
52         case SLOT_WIDTH_8:
53                 slot_len = 8;
54                 break;
55         case SLOT_WIDTH_16:
56                 slot_len = 16;
57                 break;
58         case SLOT_WIDTH_24:
59                 slot_len = 24;
60                 break;
61         case SLOT_WIDTH_32:
62                 slot_len = 0;
63                 break;
64         default:
65                 return -EINVAL;
66         }
67         frm_len = FRM_LEN | (slots << 15) | (slot_len << 18);
68         adata->tdm_fmt = frm_len;
69         return 0;
70 }
71
72 static int acp3x_i2s_hwparams(struct snd_pcm_substream *substream,
73         struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
74 {
75         struct i2s_stream_instance *rtd;
76         struct snd_soc_pcm_runtime *prtd;
77         struct snd_soc_card *card;
78         struct acp3x_platform_info *pinfo;
79         struct i2s_dev_data *adata;
80         u32 val;
81         u32 reg_val, frmt_reg;
82
83         prtd = asoc_substream_to_rtd(substream);
84         rtd = substream->runtime->private_data;
85         card = prtd->card;
86         adata = snd_soc_dai_get_drvdata(dai);
87         pinfo = snd_soc_card_get_drvdata(card);
88         if (pinfo) {
89                 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
90                         rtd->i2s_instance = pinfo->play_i2s_instance;
91                 else
92                         rtd->i2s_instance = pinfo->cap_i2s_instance;
93         }
94
95         /* These values are as per Hardware Spec */
96         switch (params_format(params)) {
97         case SNDRV_PCM_FORMAT_U8:
98         case SNDRV_PCM_FORMAT_S8:
99                 rtd->xfer_resolution = 0x0;
100                 break;
101         case SNDRV_PCM_FORMAT_S16_LE:
102                 rtd->xfer_resolution = 0x02;
103                 break;
104         case SNDRV_PCM_FORMAT_S24_LE:
105                 rtd->xfer_resolution = 0x04;
106                 break;
107         case SNDRV_PCM_FORMAT_S32_LE:
108                 rtd->xfer_resolution = 0x05;
109                 break;
110         default:
111                 return -EINVAL;
112         }
113         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
114                 switch (rtd->i2s_instance) {
115                 case I2S_BT_INSTANCE:
116                         reg_val = mmACP_BTTDM_ITER;
117                         frmt_reg = mmACP_BTTDM_TXFRMT;
118                         break;
119                 case I2S_SP_INSTANCE:
120                 default:
121                         reg_val = mmACP_I2STDM_ITER;
122                         frmt_reg = mmACP_I2STDM_TXFRMT;
123                 }
124         } else {
125                 switch (rtd->i2s_instance) {
126                 case I2S_BT_INSTANCE:
127                         reg_val = mmACP_BTTDM_IRER;
128                         frmt_reg = mmACP_BTTDM_RXFRMT;
129                         break;
130                 case I2S_SP_INSTANCE:
131                 default:
132                         reg_val = mmACP_I2STDM_IRER;
133                         frmt_reg = mmACP_I2STDM_RXFRMT;
134                 }
135         }
136         if (adata->tdm_mode) {
137                 val = rv_readl(rtd->acp3x_base + reg_val);
138                 rv_writel(val | 0x2, rtd->acp3x_base + reg_val);
139                 rv_writel(adata->tdm_fmt, rtd->acp3x_base + frmt_reg);
140         }
141         val = rv_readl(rtd->acp3x_base + reg_val);
142         val &= ~ACP3x_ITER_IRER_SAMP_LEN_MASK;
143         val = val | (rtd->xfer_resolution  << 3);
144         rv_writel(val, rtd->acp3x_base + reg_val);
145         return 0;
146 }
147
148 static int acp3x_i2s_trigger(struct snd_pcm_substream *substream,
149                                 int cmd, struct snd_soc_dai *dai)
150 {
151         struct i2s_stream_instance *rtd;
152         u32 ret, val, period_bytes, reg_val, ier_val, water_val;
153         u32 buf_size, buf_reg;
154
155         rtd = substream->runtime->private_data;
156         period_bytes = frames_to_bytes(substream->runtime,
157                         substream->runtime->period_size);
158         buf_size = frames_to_bytes(substream->runtime,
159                         substream->runtime->buffer_size);
160         switch (cmd) {
161         case SNDRV_PCM_TRIGGER_START:
162         case SNDRV_PCM_TRIGGER_RESUME:
163         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
164                 rtd->bytescount = acp_get_byte_count(rtd,
165                                                 substream->stream);
166                 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
167                         switch (rtd->i2s_instance) {
168                         case I2S_BT_INSTANCE:
169                                 water_val =
170                                         mmACP_BT_TX_INTR_WATERMARK_SIZE;
171                                 reg_val = mmACP_BTTDM_ITER;
172                                 ier_val = mmACP_BTTDM_IER;
173                                 buf_reg = mmACP_BT_TX_RINGBUFSIZE;
174                                 break;
175                         case I2S_SP_INSTANCE:
176                         default:
177                                 water_val =
178                                         mmACP_I2S_TX_INTR_WATERMARK_SIZE;
179                                 reg_val = mmACP_I2STDM_ITER;
180                                 ier_val = mmACP_I2STDM_IER;
181                                 buf_reg = mmACP_I2S_TX_RINGBUFSIZE;
182                         }
183                 } else {
184                         switch (rtd->i2s_instance) {
185                         case I2S_BT_INSTANCE:
186                                 water_val =
187                                         mmACP_BT_RX_INTR_WATERMARK_SIZE;
188                                 reg_val = mmACP_BTTDM_IRER;
189                                 ier_val = mmACP_BTTDM_IER;
190                                 buf_reg = mmACP_BT_RX_RINGBUFSIZE;
191                                 break;
192                         case I2S_SP_INSTANCE:
193                         default:
194                                 water_val =
195                                         mmACP_I2S_RX_INTR_WATERMARK_SIZE;
196                                 reg_val = mmACP_I2STDM_IRER;
197                                 ier_val = mmACP_I2STDM_IER;
198                                 buf_reg = mmACP_I2S_RX_RINGBUFSIZE;
199                         }
200                 }
201                 rv_writel(period_bytes, rtd->acp3x_base + water_val);
202                 rv_writel(buf_size, rtd->acp3x_base + buf_reg);
203                 val = rv_readl(rtd->acp3x_base + reg_val);
204                 val = val | BIT(0);
205                 rv_writel(val, rtd->acp3x_base + reg_val);
206                 rv_writel(1, rtd->acp3x_base + ier_val);
207                 ret = 0;
208                 break;
209         case SNDRV_PCM_TRIGGER_STOP:
210         case SNDRV_PCM_TRIGGER_SUSPEND:
211         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
212                 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
213                         switch (rtd->i2s_instance) {
214                         case I2S_BT_INSTANCE:
215                                 reg_val = mmACP_BTTDM_ITER;
216                                 break;
217                         case I2S_SP_INSTANCE:
218                         default:
219                                 reg_val = mmACP_I2STDM_ITER;
220                         }
221
222                 } else {
223                         switch (rtd->i2s_instance) {
224                         case I2S_BT_INSTANCE:
225                                 reg_val = mmACP_BTTDM_IRER;
226                                 break;
227                         case I2S_SP_INSTANCE:
228                         default:
229                                 reg_val = mmACP_I2STDM_IRER;
230                         }
231                 }
232                 val = rv_readl(rtd->acp3x_base + reg_val);
233                 val = val & ~BIT(0);
234                 rv_writel(val, rtd->acp3x_base + reg_val);
235
236                 if (!(rv_readl(rtd->acp3x_base + mmACP_BTTDM_ITER) & BIT(0)) &&
237                      !(rv_readl(rtd->acp3x_base + mmACP_BTTDM_IRER) & BIT(0)))
238                         rv_writel(0, rtd->acp3x_base + mmACP_BTTDM_IER);
239                 if (!(rv_readl(rtd->acp3x_base + mmACP_I2STDM_ITER) & BIT(0)) &&
240                      !(rv_readl(rtd->acp3x_base + mmACP_I2STDM_IRER) & BIT(0)))
241                         rv_writel(0, rtd->acp3x_base + mmACP_I2STDM_IER);
242                 ret = 0;
243                 break;
244         default:
245                 ret = -EINVAL;
246                 break;
247         }
248
249         return ret;
250 }
251
252 static const struct snd_soc_dai_ops acp3x_i2s_dai_ops = {
253         .hw_params = acp3x_i2s_hwparams,
254         .trigger = acp3x_i2s_trigger,
255         .set_fmt = acp3x_i2s_set_fmt,
256         .set_tdm_slot = acp3x_i2s_set_tdm_slot,
257 };
258
259 static const struct snd_soc_component_driver acp3x_dai_component = {
260         .name           = DRV_NAME,
261 };
262
263 static struct snd_soc_dai_driver acp3x_i2s_dai = {
264         .playback = {
265                 .rates = SNDRV_PCM_RATE_8000_96000,
266                 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
267                         SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
268                 .channels_min = 2,
269                 .channels_max = 8,
270                 .rate_min = 8000,
271                 .rate_max = 96000,
272         },
273         .capture = {
274                 .rates = SNDRV_PCM_RATE_8000_48000,
275                 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
276                         SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
277                 .channels_min = 2,
278                 .channels_max = 2,
279                 .rate_min = 8000,
280                 .rate_max = 48000,
281         },
282         .ops = &acp3x_i2s_dai_ops,
283 };
284
285 static int acp3x_dai_probe(struct platform_device *pdev)
286 {
287         struct resource *res;
288         struct i2s_dev_data *adata;
289         int ret;
290
291         adata = devm_kzalloc(&pdev->dev, sizeof(struct i2s_dev_data),
292                         GFP_KERNEL);
293         if (!adata)
294                 return -ENOMEM;
295
296         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
297         if (!res) {
298                 dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n");
299                 return -ENOMEM;
300         }
301         adata->acp3x_base = devm_ioremap(&pdev->dev, res->start,
302                                                 resource_size(res));
303         if (!adata->acp3x_base)
304                 return -ENOMEM;
305
306         adata->i2s_irq = res->start;
307         dev_set_drvdata(&pdev->dev, adata);
308         ret = devm_snd_soc_register_component(&pdev->dev,
309                         &acp3x_dai_component, &acp3x_i2s_dai, 1);
310         if (ret) {
311                 dev_err(&pdev->dev, "Fail to register acp i2s dai\n");
312                 return -ENODEV;
313         }
314         return 0;
315 }
316
317 static int acp3x_dai_remove(struct platform_device *pdev)
318 {
319         /* As we use devm_ memory alloc there is nothing TBD here */
320
321         return 0;
322 }
323
324 static struct platform_driver acp3x_dai_driver = {
325         .probe = acp3x_dai_probe,
326         .remove = acp3x_dai_remove,
327         .driver = {
328                 .name = "acp3x_i2s_playcap",
329         },
330 };
331
332 module_platform_driver(acp3x_dai_driver);
333
334 MODULE_AUTHOR("Vishnuvardhanrao.Ravulapati@amd.com");
335 MODULE_DESCRIPTION("AMD ACP 3.x PCM Driver");
336 MODULE_LICENSE("GPL v2");
337 MODULE_ALIAS("platform:"DRV_NAME);