xref: /linux/sound/soc/spacemit/k1_i2s.c (revision cc4adab164b772a34b3340d644b7c4728498581e)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2025 Troy Mitchell <troy.mitchell@linux.spacemit.com> */
3 
4 #include <linux/bitfield.h>
5 #include <linux/clk.h>
6 #include <linux/reset.h>
7 #include <sound/dmaengine_pcm.h>
8 #include <sound/pcm.h>
9 #include <sound/pcm_params.h>
10 
11 #define SSCR			0x00	/* SPI/I2S top control register */
12 #define SSFCR			0x04	/* SPI/I2S FIFO control register */
13 #define SSINTEN			0x08	/* SPI/I2S interrupt enable register */
14 #define SSDATR			0x10	/* SPI/I2S data register */
15 #define SSPSP			0x18	/* SPI/I2S programmable serial protocol control register */
16 #define SSRWT			0x24	/* SPI/I2S root control register */
17 
18 /* SPI/I2S Work data size, register bits value 0~31 indicated data size 1~32 bits */
19 #define SSCR_FIELD_DSS		GENMASK(9, 5)
20 #define SSCR_DW_8BYTE		FIELD_PREP(SSCR_FIELD_DSS, 0x7)
21 #define SSCR_DW_16BYTE		FIELD_PREP(SSCR_FIELD_DSS, 0xf)
22 #define SSCR_DW_18BYTE		FIELD_PREP(SSCR_FIELD_DSS, 0x11)
23 #define SSCR_DW_32BYTE		FIELD_PREP(SSCR_FIELD_DSS, 0x1f)
24 
25 #define SSCR_SSE		BIT(0)		/* SPI/I2S Enable */
26 #define SSCR_FRF_PSP		GENMASK(2, 1)	/* Frame Format*/
27 #define SSCR_TRAIL		BIT(13)		/* Trailing Byte */
28 
29 #define SSFCR_FIELD_TFT		GENMASK(3, 0)   /* TXFIFO Trigger Threshold */
30 #define SSFCR_FIELD_RFT		GENMASK(8, 5)   /* RXFIFO Trigger Threshold */
31 #define SSFCR_TSRE		BIT(10)		/* Transmit Service Request Enable */
32 #define SSFCR_RSRE		BIT(11)		/* Receive Service Request Enable */
33 
34 #define SSPSP_FSRT		BIT(3)		/* Frame Sync Relative Timing Bit */
35 #define SSPSP_SFRMP		BIT(4)		/* Serial Frame Polarity */
36 #define SSPSP_FIELD_SFRMWDTH	GENMASK(17, 12)	/* Serial Frame Width field  */
37 
38 #define SSRWT_RWOT		BIT(0)		/* Receive Without Transmit */
39 
40 #define SPACEMIT_PCM_RATES	(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \
41 				SNDRV_PCM_RATE_48000)
42 #define SPACEMIT_PCM_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
43 
44 #define SPACEMIT_I2S_PERIOD_SIZE 1024
45 
46 struct spacemit_i2s_dev {
47 	struct device *dev;
48 
49 	void __iomem *base;
50 
51 	struct reset_control *reset;
52 
53 	struct clk *sysclk;
54 	struct clk *bclk;
55 	struct clk *sspa_clk;
56 
57 	struct snd_dmaengine_dai_dma_data capture_dma_data;
58 	struct snd_dmaengine_dai_dma_data playback_dma_data;
59 
60 	bool has_capture;
61 	bool has_playback;
62 
63 	int dai_fmt;
64 
65 	int started_count;
66 };
67 
68 static const struct snd_pcm_hardware spacemit_pcm_hardware = {
69 	.info		  = SNDRV_PCM_INFO_INTERLEAVED |
70 			    SNDRV_PCM_INFO_BATCH,
71 	.formats          = SPACEMIT_PCM_FORMATS,
72 	.rates		  = SPACEMIT_PCM_RATES,
73 	.rate_min         = SNDRV_PCM_RATE_8000,
74 	.rate_max         = SNDRV_PCM_RATE_192000,
75 	.channels_min     = 1,
76 	.channels_max     = 2,
77 	.buffer_bytes_max = SPACEMIT_I2S_PERIOD_SIZE * 4 * 4,
78 	.period_bytes_min = SPACEMIT_I2S_PERIOD_SIZE * 2,
79 	.period_bytes_max = SPACEMIT_I2S_PERIOD_SIZE * 4,
80 	.periods_min	  = 2,
81 	.periods_max	  = 4,
82 };
83 
84 static const struct snd_dmaengine_pcm_config spacemit_dmaengine_pcm_config = {
85 	.pcm_hardware = &spacemit_pcm_hardware,
86 	.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
87 	.chan_names = {"tx", "rx"},
88 	.prealloc_buffer_size = 32 * 1024,
89 };
90 
91 static void spacemit_i2s_init(struct spacemit_i2s_dev *i2s)
92 {
93 	u32 sscr_val, sspsp_val, ssfcr_val, ssrwt_val;
94 
95 	sscr_val = SSCR_TRAIL | SSCR_FRF_PSP;
96 	ssfcr_val = FIELD_PREP(SSFCR_FIELD_TFT, 5) |
97 		    FIELD_PREP(SSFCR_FIELD_RFT, 5) |
98 		    SSFCR_RSRE | SSFCR_TSRE;
99 	ssrwt_val = SSRWT_RWOT;
100 	sspsp_val = SSPSP_SFRMP;
101 
102 	writel(sscr_val, i2s->base + SSCR);
103 	writel(ssfcr_val, i2s->base + SSFCR);
104 	writel(sspsp_val, i2s->base + SSPSP);
105 	writel(ssrwt_val, i2s->base + SSRWT);
106 	writel(0, i2s->base + SSINTEN);
107 }
108 
109 static int spacemit_i2s_hw_params(struct snd_pcm_substream *substream,
110 				  struct snd_pcm_hw_params *params,
111 				  struct snd_soc_dai *dai)
112 {
113 	struct spacemit_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai);
114 	struct snd_dmaengine_dai_dma_data *dma_data;
115 	u32 data_width, data_bits;
116 	unsigned long bclk_rate;
117 	u32 val;
118 	int ret;
119 
120 	val = readl(i2s->base + SSCR);
121 	if (val & SSCR_SSE)
122 		return 0;
123 
124 	dma_data = &i2s->playback_dma_data;
125 
126 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
127 		dma_data = &i2s->capture_dma_data;
128 
129 	switch (params_format(params)) {
130 	case SNDRV_PCM_FORMAT_S8:
131 		data_bits = 8;
132 		data_width = SSCR_DW_8BYTE;
133 		dma_data->maxburst = 8;
134 		dma_data->addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
135 		break;
136 	case SNDRV_PCM_FORMAT_S16_LE:
137 		data_bits = 16;
138 		data_width = SSCR_DW_16BYTE;
139 		dma_data->maxburst = 16;
140 		dma_data->addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
141 		break;
142 	case SNDRV_PCM_FORMAT_S32_LE:
143 		data_bits = 32;
144 		data_width = SSCR_DW_32BYTE;
145 		dma_data->maxburst = 32;
146 		dma_data->addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
147 		break;
148 	default:
149 		dev_dbg(i2s->dev, "unexpected data width type");
150 		return -EINVAL;
151 	}
152 
153 	switch (i2s->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
154 	case SND_SOC_DAIFMT_I2S:
155 		if (data_bits == 16) {
156 			data_width = SSCR_DW_32BYTE;
157 			dma_data->maxburst = 32;
158 			dma_data->addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
159 		}
160 
161 		snd_pcm_hw_constraint_minmax(substream->runtime,
162 					     SNDRV_PCM_HW_PARAM_CHANNELS,
163 					     1, 2);
164 		snd_pcm_hw_constraint_mask64(substream->runtime,
165 					     SNDRV_PCM_HW_PARAM_FORMAT,
166 					     SNDRV_PCM_FMTBIT_S16_LE);
167 		break;
168 	case SND_SOC_DAIFMT_DSP_A:
169 	case SND_SOC_DAIFMT_DSP_B:
170 		snd_pcm_hw_constraint_minmax(substream->runtime,
171 					     SNDRV_PCM_HW_PARAM_CHANNELS,
172 					     1, 1);
173 		snd_pcm_hw_constraint_mask64(substream->runtime,
174 					     SNDRV_PCM_HW_PARAM_FORMAT,
175 					     SNDRV_PCM_FMTBIT_S32_LE);
176 		break;
177 	default:
178 		dev_dbg(i2s->dev, "unexpected format type");
179 		return -EINVAL;
180 
181 	}
182 
183 	val = readl(i2s->base + SSCR);
184 	val &= ~SSCR_DW_32BYTE;
185 	val |= data_width;
186 	writel(val, i2s->base + SSCR);
187 
188 	bclk_rate = params_channels(params) *
189 		    params_rate(params) *
190 		    data_bits;
191 
192 	ret = clk_set_rate(i2s->bclk, bclk_rate);
193 	if (ret)
194 		return ret;
195 
196 	return clk_set_rate(i2s->sspa_clk, bclk_rate);
197 }
198 
199 static int spacemit_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
200 				   unsigned int freq, int dir)
201 {
202 	struct spacemit_i2s_dev *i2s = dev_get_drvdata(cpu_dai->dev);
203 
204 	if (freq == 0)
205 		return 0;
206 
207 	return clk_set_rate(i2s->sysclk, freq);
208 }
209 
210 static int spacemit_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
211 				unsigned int fmt)
212 {
213 	struct spacemit_i2s_dev *i2s = dev_get_drvdata(cpu_dai->dev);
214 	u32 sspsp_val;
215 
216 	sspsp_val = readl(i2s->base + SSPSP);
217 	sspsp_val &= ~SSPSP_FIELD_SFRMWDTH;
218 	sspsp_val |= SSPSP_FSRT;
219 
220 	i2s->dai_fmt = fmt;
221 
222 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
223 	case SND_SOC_DAIFMT_I2S:
224 		sspsp_val |= FIELD_PREP(SSPSP_FIELD_SFRMWDTH, 0x10);
225 		break;
226 	case SND_SOC_DAIFMT_DSP_B:
227 		/* DSP_B: next frame asserted after previous frame end, so clear FSRT */
228 		sspsp_val &= ~SSPSP_FSRT;
229 		fallthrough;
230 	case SND_SOC_DAIFMT_DSP_A:
231 		sspsp_val |= FIELD_PREP(SSPSP_FIELD_SFRMWDTH, 0x1);
232 		break;
233 	default:
234 		dev_dbg(i2s->dev, "unexpected format type");
235 		return -EINVAL;
236 	}
237 
238 	writel(sspsp_val, i2s->base + SSPSP);
239 
240 	return 0;
241 }
242 
243 static int spacemit_i2s_trigger(struct snd_pcm_substream *substream,
244 				int cmd, struct snd_soc_dai *dai)
245 {
246 	struct spacemit_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai);
247 	u32 val;
248 
249 	switch (cmd) {
250 	case SNDRV_PCM_TRIGGER_START:
251 	case SNDRV_PCM_TRIGGER_RESUME:
252 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
253 		if (!i2s->started_count) {
254 			val = readl(i2s->base + SSCR);
255 			val |= SSCR_SSE;
256 			writel(val, i2s->base + SSCR);
257 		}
258 		i2s->started_count++;
259 		break;
260 	case SNDRV_PCM_TRIGGER_STOP:
261 	case SNDRV_PCM_TRIGGER_SUSPEND:
262 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
263 		if (i2s->started_count)
264 			i2s->started_count--;
265 
266 		if (!i2s->started_count) {
267 			val = readl(i2s->base + SSCR);
268 			val &= ~SSCR_SSE;
269 			writel(val, i2s->base + SSCR);
270 		}
271 		break;
272 	default:
273 		return -EINVAL;
274 	}
275 
276 	return 0;
277 }
278 
279 static int spacemit_i2s_dai_probe(struct snd_soc_dai *dai)
280 {
281 	struct spacemit_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai);
282 
283 	snd_soc_dai_init_dma_data(dai,
284 				  i2s->has_playback ? &i2s->playback_dma_data : NULL,
285 				  i2s->has_capture ? &i2s->capture_dma_data : NULL);
286 
287 	reset_control_deassert(i2s->reset);
288 
289 	spacemit_i2s_init(i2s);
290 
291 	return 0;
292 }
293 
294 static int spacemit_i2s_dai_remove(struct snd_soc_dai *dai)
295 {
296 	struct spacemit_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai);
297 
298 	reset_control_assert(i2s->reset);
299 
300 	return 0;
301 }
302 
303 static const struct snd_soc_dai_ops spacemit_i2s_dai_ops = {
304 	.probe = spacemit_i2s_dai_probe,
305 	.remove = spacemit_i2s_dai_remove,
306 	.hw_params = spacemit_i2s_hw_params,
307 	.set_sysclk = spacemit_i2s_set_sysclk,
308 	.set_fmt = spacemit_i2s_set_fmt,
309 	.trigger = spacemit_i2s_trigger,
310 };
311 
312 static struct snd_soc_dai_driver spacemit_i2s_dai = {
313 	.ops = &spacemit_i2s_dai_ops,
314 	.playback = {
315 		.channels_min = 1,
316 		.channels_max = 2,
317 		.rates = SPACEMIT_PCM_RATES,
318 		.rate_min = SNDRV_PCM_RATE_8000,
319 		.rate_max = SNDRV_PCM_RATE_48000,
320 		.formats = SPACEMIT_PCM_FORMATS,
321 	},
322 	.capture = {
323 		.channels_min = 1,
324 		.channels_max = 2,
325 		.rates = SPACEMIT_PCM_RATES,
326 		.rate_min = SNDRV_PCM_RATE_8000,
327 		.rate_max = SNDRV_PCM_RATE_48000,
328 		.formats = SPACEMIT_PCM_FORMATS,
329 	},
330 	.symmetric_rate = 1,
331 };
332 
333 static int spacemit_i2s_init_dai(struct spacemit_i2s_dev *i2s,
334 				 struct snd_soc_dai_driver **dp,
335 				 dma_addr_t addr)
336 {
337 	struct device_node *node = i2s->dev->of_node;
338 	struct snd_soc_dai_driver *dai;
339 	struct property *dma_names;
340 	const char *dma_name;
341 
342 	of_property_for_each_string(node, "dma-names", dma_names, dma_name) {
343 		if (!strcmp(dma_name, "tx"))
344 			i2s->has_playback = true;
345 		if (!strcmp(dma_name, "rx"))
346 			i2s->has_capture = true;
347 	}
348 
349 	dai = devm_kmemdup(i2s->dev, &spacemit_i2s_dai,
350 			   sizeof(*dai), GFP_KERNEL);
351 	if (!dai)
352 		return -ENOMEM;
353 
354 	if (i2s->has_playback) {
355 		dai->playback.stream_name = "Playback";
356 		dai->playback.channels_min = 1;
357 		dai->playback.channels_max = 2;
358 		dai->playback.rates = SPACEMIT_PCM_RATES;
359 		dai->playback.formats = SPACEMIT_PCM_FORMATS;
360 
361 		i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
362 		i2s->playback_dma_data.maxburst = 32;
363 		i2s->playback_dma_data.addr = addr;
364 	}
365 
366 	if (i2s->has_capture) {
367 		dai->capture.stream_name = "Capture";
368 		dai->capture.channels_min = 1;
369 		dai->capture.channels_max = 2;
370 		dai->capture.rates = SPACEMIT_PCM_RATES;
371 		dai->capture.formats = SPACEMIT_PCM_FORMATS;
372 
373 		i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
374 		i2s->capture_dma_data.maxburst = 32;
375 		i2s->capture_dma_data.addr = addr;
376 	}
377 
378 	if (dp)
379 		*dp = dai;
380 
381 	return 0;
382 }
383 
384 static const struct snd_soc_component_driver spacemit_i2s_component = {
385 	.name = "i2s-k1",
386 	.legacy_dai_naming = 1,
387 };
388 
389 static int spacemit_i2s_probe(struct platform_device *pdev)
390 {
391 	struct snd_soc_dai_driver *dai;
392 	struct spacemit_i2s_dev *i2s;
393 	struct resource *res;
394 	struct clk *clk;
395 	int ret;
396 
397 	i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
398 	if (!i2s)
399 		return -ENOMEM;
400 
401 	i2s->dev = &pdev->dev;
402 
403 	i2s->sysclk = devm_clk_get_enabled(i2s->dev, "sysclk");
404 	if (IS_ERR(i2s->sysclk))
405 		return dev_err_probe(i2s->dev, PTR_ERR(i2s->sysclk),
406 				     "failed to enable sysbase clock\n");
407 
408 	i2s->bclk = devm_clk_get_enabled(i2s->dev, "bclk");
409 	if (IS_ERR(i2s->bclk))
410 		return dev_err_probe(i2s->dev, PTR_ERR(i2s->bclk), "failed to enable bit clock\n");
411 
412 	clk = devm_clk_get_enabled(i2s->dev, "sspa_bus");
413 	if (IS_ERR(clk))
414 		return dev_err_probe(i2s->dev, PTR_ERR(clk), "failed to enable sspa_bus clock\n");
415 
416 	i2s->sspa_clk = devm_clk_get_enabled(i2s->dev, "sspa");
417 	if (IS_ERR(i2s->sspa_clk))
418 		return dev_err_probe(i2s->dev, PTR_ERR(i2s->sspa_clk),
419 				     "failed to enable sspa clock\n");
420 
421 	i2s->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
422 	if (IS_ERR(i2s->base))
423 		return dev_err_probe(i2s->dev, PTR_ERR(i2s->base), "failed to map registers\n");
424 
425 	i2s->reset = devm_reset_control_get_exclusive(&pdev->dev, NULL);
426 	if (IS_ERR(i2s->reset))
427 		return dev_err_probe(i2s->dev, PTR_ERR(i2s->reset),
428 				     "failed to get reset control");
429 
430 	dev_set_drvdata(i2s->dev, i2s);
431 
432 	ret = spacemit_i2s_init_dai(i2s, &dai, res->start + SSDATR);
433 	if (ret)
434 		return ret;
435 
436 	ret = devm_snd_soc_register_component(i2s->dev,
437 					      &spacemit_i2s_component,
438 					      dai, 1);
439 	if (ret)
440 		return dev_err_probe(i2s->dev, ret, "failed to register component");
441 
442 	return devm_snd_dmaengine_pcm_register(&pdev->dev, &spacemit_dmaengine_pcm_config, 0);
443 }
444 
445 static const struct of_device_id spacemit_i2s_of_match[] = {
446 	{ .compatible = "spacemit,k1-i2s", },
447 	{ /* sentinel */ }
448 };
449 MODULE_DEVICE_TABLE(of, spacemit_i2s_of_match);
450 
451 static struct platform_driver spacemit_i2s_driver = {
452 	.probe = spacemit_i2s_probe,
453 	.driver = {
454 		.name = "i2s-k1",
455 		.of_match_table = spacemit_i2s_of_match,
456 	},
457 };
458 module_platform_driver(spacemit_i2s_driver);
459 
460 MODULE_LICENSE("GPL");
461 MODULE_DESCRIPTION("I2S bus driver for SpacemiT K1 SoC");
462