arm64: zynqmp: Make zynqmp_firmware driver optional
[linux-2.6-microblaze.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"
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 val, reg_val, frmt_reg, 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
68         /* Enable I2S/BT channels TDM, respective TX/RX frame lengths.*/
69
70         frm_len = FRM_LEN | (slots << 15) | (slot_len << 18);
71         if (adata->substream_type == SNDRV_PCM_STREAM_PLAYBACK) {
72                 switch (adata->i2s_instance) {
73                 case I2S_BT_INSTANCE:
74                         reg_val = mmACP_BTTDM_ITER;
75                         frmt_reg = mmACP_BTTDM_TXFRMT;
76                         break;
77                 case I2S_SP_INSTANCE:
78                 default:
79                         reg_val = mmACP_I2STDM_ITER;
80                         frmt_reg = mmACP_I2STDM_TXFRMT;
81                 }
82         } else {
83                 switch (adata->i2s_instance) {
84                 case I2S_BT_INSTANCE:
85                         reg_val = mmACP_BTTDM_IRER;
86                         frmt_reg = mmACP_BTTDM_RXFRMT;
87                         break;
88                 case I2S_SP_INSTANCE:
89                 default:
90                         reg_val = mmACP_I2STDM_IRER;
91                         frmt_reg = mmACP_I2STDM_RXFRMT;
92                 }
93         }
94         val = rv_readl(adata->acp3x_base + reg_val);
95         rv_writel(val | 0x2, adata->acp3x_base + reg_val);
96         rv_writel(frm_len, adata->acp3x_base + frmt_reg);
97         adata->tdm_fmt = frm_len;
98         return 0;
99 }
100
101 static int acp3x_i2s_hwparams(struct snd_pcm_substream *substream,
102         struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
103 {
104         struct i2s_stream_instance *rtd;
105         struct snd_soc_pcm_runtime *prtd;
106         struct snd_soc_card *card;
107         struct acp3x_platform_info *pinfo;
108         u32 val;
109         u32 reg_val;
110
111         prtd = substream->private_data;
112         rtd = substream->runtime->private_data;
113         card = prtd->card;
114         pinfo = snd_soc_card_get_drvdata(card);
115         if (pinfo) {
116                 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
117                         rtd->i2s_instance = pinfo->play_i2s_instance;
118                 else
119                         rtd->i2s_instance = pinfo->cap_i2s_instance;
120         }
121
122         /* These values are as per Hardware Spec */
123         switch (params_format(params)) {
124         case SNDRV_PCM_FORMAT_U8:
125         case SNDRV_PCM_FORMAT_S8:
126                 rtd->xfer_resolution = 0x0;
127                 break;
128         case SNDRV_PCM_FORMAT_S16_LE:
129                 rtd->xfer_resolution = 0x02;
130                 break;
131         case SNDRV_PCM_FORMAT_S24_LE:
132                 rtd->xfer_resolution = 0x04;
133                 break;
134         case SNDRV_PCM_FORMAT_S32_LE:
135                 rtd->xfer_resolution = 0x05;
136                 break;
137         default:
138                 return -EINVAL;
139         }
140         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
141                 switch (rtd->i2s_instance) {
142                 case I2S_BT_INSTANCE:
143                         reg_val = mmACP_BTTDM_ITER;
144                         break;
145                 case I2S_SP_INSTANCE:
146                 default:
147                         reg_val = mmACP_I2STDM_ITER;
148                 }
149         } else {
150                 switch (rtd->i2s_instance) {
151                 case I2S_BT_INSTANCE:
152                         reg_val = mmACP_BTTDM_IRER;
153                         break;
154                 case I2S_SP_INSTANCE:
155                 default:
156                         reg_val = mmACP_I2STDM_IRER;
157                 }
158         }
159         val = rv_readl(rtd->acp3x_base + reg_val);
160         val = val | (rtd->xfer_resolution  << 3);
161         rv_writel(val, rtd->acp3x_base + reg_val);
162         return 0;
163 }
164
165 static int acp3x_i2s_trigger(struct snd_pcm_substream *substream,
166                                 int cmd, struct snd_soc_dai *dai)
167 {
168         struct i2s_stream_instance *rtd;
169         struct snd_soc_pcm_runtime *prtd;
170         struct snd_soc_card *card;
171         struct acp3x_platform_info *pinfo;
172         u32 ret, val, period_bytes, reg_val, ier_val, water_val;
173
174         prtd = substream->private_data;
175         rtd = substream->runtime->private_data;
176         card = prtd->card;
177         pinfo = snd_soc_card_get_drvdata(card);
178         if (pinfo) {
179                 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
180                         rtd->i2s_instance = pinfo->play_i2s_instance;
181                 else
182                         rtd->i2s_instance = pinfo->cap_i2s_instance;
183         }
184         period_bytes = frames_to_bytes(substream->runtime,
185                         substream->runtime->period_size);
186         switch (cmd) {
187         case SNDRV_PCM_TRIGGER_START:
188         case SNDRV_PCM_TRIGGER_RESUME:
189         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
190                 rtd->bytescount = acp_get_byte_count(rtd,
191                                                 substream->stream);
192                 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
193                         switch (rtd->i2s_instance) {
194                         case I2S_BT_INSTANCE:
195                                 water_val =
196                                         mmACP_BT_TX_INTR_WATERMARK_SIZE;
197                                 reg_val = mmACP_BTTDM_ITER;
198                                 ier_val = mmACP_BTTDM_IER;
199                                 break;
200                         case I2S_SP_INSTANCE:
201                         default:
202                                 water_val =
203                                         mmACP_I2S_TX_INTR_WATERMARK_SIZE;
204                                 reg_val = mmACP_I2STDM_ITER;
205                                 ier_val = mmACP_I2STDM_IER;
206                         }
207                 } else {
208                         switch (rtd->i2s_instance) {
209                         case I2S_BT_INSTANCE:
210                                 water_val =
211                                         mmACP_BT_RX_INTR_WATERMARK_SIZE;
212                                 reg_val = mmACP_BTTDM_IRER;
213                                 ier_val = mmACP_BTTDM_IER;
214                                 break;
215                         case I2S_SP_INSTANCE:
216                         default:
217                                 water_val =
218                                         mmACP_I2S_RX_INTR_WATERMARK_SIZE;
219                                 reg_val = mmACP_I2STDM_IRER;
220                                 ier_val = mmACP_I2STDM_IER;
221                         }
222                 }
223                 rv_writel(period_bytes, rtd->acp3x_base + water_val);
224                 val = rv_readl(rtd->acp3x_base + reg_val);
225                 val = val | BIT(0);
226                 rv_writel(val, rtd->acp3x_base + reg_val);
227                 rv_writel(1, rtd->acp3x_base + ier_val);
228                 ret = 0;
229                 break;
230         case SNDRV_PCM_TRIGGER_STOP:
231         case SNDRV_PCM_TRIGGER_SUSPEND:
232         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
233                 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
234                         switch (rtd->i2s_instance) {
235                         case I2S_BT_INSTANCE:
236                                 reg_val = mmACP_BTTDM_ITER;
237                                 break;
238                         case I2S_SP_INSTANCE:
239                         default:
240                                 reg_val = mmACP_I2STDM_ITER;
241                         }
242
243                 } else {
244                         switch (rtd->i2s_instance) {
245                         case I2S_BT_INSTANCE:
246                                 reg_val = mmACP_BTTDM_IRER;
247                                 break;
248                         case I2S_SP_INSTANCE:
249                         default:
250                                 reg_val = mmACP_I2STDM_IRER;
251                         }
252                 }
253                 val = rv_readl(rtd->acp3x_base + reg_val);
254                 val = val & ~BIT(0);
255                 rv_writel(val, rtd->acp3x_base + reg_val);
256
257                 if (!(rv_readl(rtd->acp3x_base + mmACP_BTTDM_ITER) & BIT(0)) &&
258                      !(rv_readl(rtd->acp3x_base + mmACP_BTTDM_IRER) & BIT(0)))
259                         rv_writel(0, rtd->acp3x_base + mmACP_BTTDM_IER);
260                 if (!(rv_readl(rtd->acp3x_base + mmACP_I2STDM_ITER) & BIT(0)) &&
261                      !(rv_readl(rtd->acp3x_base + mmACP_I2STDM_IRER) & BIT(0)))
262                         rv_writel(0, rtd->acp3x_base + mmACP_I2STDM_IER);
263                 ret = 0;
264                 break;
265         default:
266                 ret = -EINVAL;
267                 break;
268         }
269
270         return ret;
271 }
272
273 static struct snd_soc_dai_ops acp3x_i2s_dai_ops = {
274         .hw_params = acp3x_i2s_hwparams,
275         .trigger = acp3x_i2s_trigger,
276         .set_fmt = acp3x_i2s_set_fmt,
277         .set_tdm_slot = acp3x_i2s_set_tdm_slot,
278 };
279
280 static const struct snd_soc_component_driver acp3x_dai_component = {
281         .name           = "acp3x-i2s",
282 };
283
284 static struct snd_soc_dai_driver acp3x_i2s_dai = {
285         .playback = {
286                 .rates = SNDRV_PCM_RATE_8000_96000,
287                 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
288                         SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE |
289                         SNDRV_PCM_FMTBIT_S32_LE,
290                 .channels_min = 2,
291                 .channels_max = 8,
292                 .rate_min = 8000,
293                 .rate_max = 96000,
294         },
295         .capture = {
296                 .rates = SNDRV_PCM_RATE_8000_48000,
297                 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
298                         SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE |
299                         SNDRV_PCM_FMTBIT_S32_LE,
300                 .channels_min = 2,
301                 .channels_max = 2,
302                 .rate_min = 8000,
303                 .rate_max = 48000,
304         },
305         .ops = &acp3x_i2s_dai_ops,
306 };
307
308 static int acp3x_dai_probe(struct platform_device *pdev)
309 {
310         struct resource *res;
311         struct i2s_dev_data *adata;
312         int ret;
313
314         adata = devm_kzalloc(&pdev->dev, sizeof(struct i2s_dev_data),
315                         GFP_KERNEL);
316         if (!adata)
317                 return -ENOMEM;
318
319         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
320         if (!res) {
321                 dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n");
322                 return -ENOMEM;
323         }
324         adata->acp3x_base = devm_ioremap(&pdev->dev, res->start,
325                                                 resource_size(res));
326         if (!adata->acp3x_base)
327                 return -ENOMEM;
328
329         adata->i2s_irq = res->start;
330         dev_set_drvdata(&pdev->dev, adata);
331         ret = devm_snd_soc_register_component(&pdev->dev,
332                         &acp3x_dai_component, &acp3x_i2s_dai, 1);
333         if (ret) {
334                 dev_err(&pdev->dev, "Fail to register acp i2s dai\n");
335                 return -ENODEV;
336         }
337         return 0;
338 }
339
340 static int acp3x_dai_remove(struct platform_device *pdev)
341 {
342         /* As we use devm_ memory alloc there is nothing TBD here */
343
344         return 0;
345 }
346
347 static struct platform_driver acp3x_dai_driver = {
348         .probe = acp3x_dai_probe,
349         .remove = acp3x_dai_remove,
350         .driver = {
351                 .name = "acp3x_i2s_playcap",
352         },
353 };
354
355 module_platform_driver(acp3x_dai_driver);
356
357 MODULE_AUTHOR("Vishnuvardhanrao.Ravulapati@amd.com");
358 MODULE_DESCRIPTION("AMD ACP 3.x PCM Driver");
359 MODULE_LICENSE("GPL v2");
360 MODULE_ALIAS("platform:" DRV_NAME);