xref: /linux/sound/soc/amd/raven/acp3x-i2s.c (revision e0ad4d68548005adb54cc7c35fd9abf760a2a050)
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 	u32 buf_size, buf_reg;
174 
175 	prtd = substream->private_data;
176 	rtd = substream->runtime->private_data;
177 	card = prtd->card;
178 	pinfo = snd_soc_card_get_drvdata(card);
179 	if (pinfo) {
180 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
181 			rtd->i2s_instance = pinfo->play_i2s_instance;
182 		else
183 			rtd->i2s_instance = pinfo->cap_i2s_instance;
184 	}
185 	period_bytes = frames_to_bytes(substream->runtime,
186 			substream->runtime->period_size);
187 	buf_size = frames_to_bytes(substream->runtime,
188 			substream->runtime->buffer_size);
189 	switch (cmd) {
190 	case SNDRV_PCM_TRIGGER_START:
191 	case SNDRV_PCM_TRIGGER_RESUME:
192 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
193 		rtd->bytescount = acp_get_byte_count(rtd,
194 						substream->stream);
195 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
196 			switch (rtd->i2s_instance) {
197 			case I2S_BT_INSTANCE:
198 				water_val =
199 					mmACP_BT_TX_INTR_WATERMARK_SIZE;
200 				reg_val = mmACP_BTTDM_ITER;
201 				ier_val = mmACP_BTTDM_IER;
202 				buf_reg = mmACP_BT_TX_RINGBUFSIZE;
203 				break;
204 			case I2S_SP_INSTANCE:
205 			default:
206 				water_val =
207 					mmACP_I2S_TX_INTR_WATERMARK_SIZE;
208 				reg_val = mmACP_I2STDM_ITER;
209 				ier_val = mmACP_I2STDM_IER;
210 				buf_reg = mmACP_I2S_TX_RINGBUFSIZE;
211 			}
212 		} else {
213 			switch (rtd->i2s_instance) {
214 			case I2S_BT_INSTANCE:
215 				water_val =
216 					mmACP_BT_RX_INTR_WATERMARK_SIZE;
217 				reg_val = mmACP_BTTDM_IRER;
218 				ier_val = mmACP_BTTDM_IER;
219 				buf_reg = mmACP_BT_RX_RINGBUFSIZE;
220 				break;
221 			case I2S_SP_INSTANCE:
222 			default:
223 				water_val =
224 					mmACP_I2S_RX_INTR_WATERMARK_SIZE;
225 				reg_val = mmACP_I2STDM_IRER;
226 				ier_val = mmACP_I2STDM_IER;
227 				buf_reg = mmACP_I2S_RX_RINGBUFSIZE;
228 			}
229 		}
230 		rv_writel(period_bytes, rtd->acp3x_base + water_val);
231 		rv_writel(buf_size, rtd->acp3x_base + buf_reg);
232 		val = rv_readl(rtd->acp3x_base + reg_val);
233 		val = val | BIT(0);
234 		rv_writel(val, rtd->acp3x_base + reg_val);
235 		rv_writel(1, rtd->acp3x_base + ier_val);
236 		ret = 0;
237 		break;
238 	case SNDRV_PCM_TRIGGER_STOP:
239 	case SNDRV_PCM_TRIGGER_SUSPEND:
240 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
241 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
242 			switch (rtd->i2s_instance) {
243 			case I2S_BT_INSTANCE:
244 				reg_val = mmACP_BTTDM_ITER;
245 				break;
246 			case I2S_SP_INSTANCE:
247 			default:
248 				reg_val = mmACP_I2STDM_ITER;
249 			}
250 
251 		} else {
252 			switch (rtd->i2s_instance) {
253 			case I2S_BT_INSTANCE:
254 				reg_val = mmACP_BTTDM_IRER;
255 				break;
256 			case I2S_SP_INSTANCE:
257 			default:
258 				reg_val = mmACP_I2STDM_IRER;
259 			}
260 		}
261 		val = rv_readl(rtd->acp3x_base + reg_val);
262 		val = val & ~BIT(0);
263 		rv_writel(val, rtd->acp3x_base + reg_val);
264 
265 		if (!(rv_readl(rtd->acp3x_base + mmACP_BTTDM_ITER) & BIT(0)) &&
266 		     !(rv_readl(rtd->acp3x_base + mmACP_BTTDM_IRER) & BIT(0)))
267 			rv_writel(0, rtd->acp3x_base + mmACP_BTTDM_IER);
268 		if (!(rv_readl(rtd->acp3x_base + mmACP_I2STDM_ITER) & BIT(0)) &&
269 		     !(rv_readl(rtd->acp3x_base + mmACP_I2STDM_IRER) & BIT(0)))
270 			rv_writel(0, rtd->acp3x_base + mmACP_I2STDM_IER);
271 		ret = 0;
272 		break;
273 	default:
274 		ret = -EINVAL;
275 		break;
276 	}
277 
278 	return ret;
279 }
280 
281 static struct snd_soc_dai_ops acp3x_i2s_dai_ops = {
282 	.hw_params = acp3x_i2s_hwparams,
283 	.trigger = acp3x_i2s_trigger,
284 	.set_fmt = acp3x_i2s_set_fmt,
285 	.set_tdm_slot = acp3x_i2s_set_tdm_slot,
286 };
287 
288 static const struct snd_soc_component_driver acp3x_dai_component = {
289 	.name           = "acp3x-i2s",
290 };
291 
292 static struct snd_soc_dai_driver acp3x_i2s_dai = {
293 	.playback = {
294 		.rates = SNDRV_PCM_RATE_8000_96000,
295 		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
296 			SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE |
297 			SNDRV_PCM_FMTBIT_S32_LE,
298 		.channels_min = 2,
299 		.channels_max = 8,
300 		.rate_min = 8000,
301 		.rate_max = 96000,
302 	},
303 	.capture = {
304 		.rates = SNDRV_PCM_RATE_8000_48000,
305 		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
306 			SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE |
307 			SNDRV_PCM_FMTBIT_S32_LE,
308 		.channels_min = 2,
309 		.channels_max = 2,
310 		.rate_min = 8000,
311 		.rate_max = 48000,
312 	},
313 	.ops = &acp3x_i2s_dai_ops,
314 };
315 
316 static int acp3x_dai_probe(struct platform_device *pdev)
317 {
318 	struct resource *res;
319 	struct i2s_dev_data *adata;
320 	int ret;
321 
322 	adata = devm_kzalloc(&pdev->dev, sizeof(struct i2s_dev_data),
323 			GFP_KERNEL);
324 	if (!adata)
325 		return -ENOMEM;
326 
327 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
328 	if (!res) {
329 		dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n");
330 		return -ENOMEM;
331 	}
332 	adata->acp3x_base = devm_ioremap(&pdev->dev, res->start,
333 						resource_size(res));
334 	if (!adata->acp3x_base)
335 		return -ENOMEM;
336 
337 	adata->i2s_irq = res->start;
338 	dev_set_drvdata(&pdev->dev, adata);
339 	ret = devm_snd_soc_register_component(&pdev->dev,
340 			&acp3x_dai_component, &acp3x_i2s_dai, 1);
341 	if (ret) {
342 		dev_err(&pdev->dev, "Fail to register acp i2s dai\n");
343 		return -ENODEV;
344 	}
345 	return 0;
346 }
347 
348 static int acp3x_dai_remove(struct platform_device *pdev)
349 {
350 	/* As we use devm_ memory alloc there is nothing TBD here */
351 
352 	return 0;
353 }
354 
355 static struct platform_driver acp3x_dai_driver = {
356 	.probe = acp3x_dai_probe,
357 	.remove = acp3x_dai_remove,
358 	.driver = {
359 		.name = "acp3x_i2s_playcap",
360 	},
361 };
362 
363 module_platform_driver(acp3x_dai_driver);
364 
365 MODULE_AUTHOR("Vishnuvardhanrao.Ravulapati@amd.com");
366 MODULE_DESCRIPTION("AMD ACP 3.x PCM Driver");
367 MODULE_LICENSE("GPL v2");
368 MODULE_ALIAS("platform:" DRV_NAME);
369