xref: /linux/sound/soc/spacemit/k1_i2s.c (revision 19cbc75c56c0ed4fa3f637e3c41a98895a68dfae)
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 
spacemit_i2s_init(struct spacemit_i2s_dev * i2s)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, 0xF) |
97 		    FIELD_PREP(SSFCR_FIELD_RFT, 0xF) |
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 
spacemit_i2s_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)109 static int spacemit_i2s_startup(struct snd_pcm_substream *substream,
110 	struct snd_soc_dai *dai)
111 {
112 	struct spacemit_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai);
113 
114 	switch (i2s->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
115 	case SND_SOC_DAIFMT_I2S:
116 		snd_pcm_hw_constraint_minmax(substream->runtime,
117 					     SNDRV_PCM_HW_PARAM_CHANNELS,
118 					     2, 2);
119 		snd_pcm_hw_constraint_mask64(substream->runtime,
120 					     SNDRV_PCM_HW_PARAM_FORMAT,
121 					     SNDRV_PCM_FMTBIT_S16_LE);
122 		break;
123 	case SND_SOC_DAIFMT_DSP_A:
124 	case SND_SOC_DAIFMT_DSP_B:
125 		snd_pcm_hw_constraint_minmax(substream->runtime,
126 					     SNDRV_PCM_HW_PARAM_CHANNELS,
127 					     1, 1);
128 		snd_pcm_hw_constraint_mask64(substream->runtime,
129 					     SNDRV_PCM_HW_PARAM_FORMAT,
130 					     SNDRV_PCM_FMTBIT_S32_LE);
131 		break;
132 	default:
133 		dev_dbg(i2s->dev, "unexpected format type");
134 		return -EINVAL;
135 	}
136 
137 	return 0;
138 }
139 
spacemit_i2s_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)140 static int spacemit_i2s_hw_params(struct snd_pcm_substream *substream,
141 				  struct snd_pcm_hw_params *params,
142 				  struct snd_soc_dai *dai)
143 {
144 	struct spacemit_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai);
145 	struct snd_dmaengine_dai_dma_data *dma_data;
146 	u32 data_width, data_bits;
147 	unsigned long bclk_rate;
148 	u32 val;
149 	int ret;
150 
151 	dma_data = &i2s->playback_dma_data;
152 
153 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
154 		dma_data = &i2s->capture_dma_data;
155 
156 	switch (params_format(params)) {
157 	case SNDRV_PCM_FORMAT_S8:
158 		data_bits = 8;
159 		data_width = SSCR_DW_8BYTE;
160 		dma_data->maxburst = 8;
161 		dma_data->addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
162 		break;
163 	case SNDRV_PCM_FORMAT_S16_LE:
164 		data_bits = 16;
165 		data_width = SSCR_DW_16BYTE;
166 		dma_data->maxburst = 16;
167 		dma_data->addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
168 		break;
169 	case SNDRV_PCM_FORMAT_S32_LE:
170 		data_bits = 32;
171 		data_width = SSCR_DW_32BYTE;
172 		dma_data->maxburst = 32;
173 		dma_data->addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
174 		break;
175 	default:
176 		dev_dbg(i2s->dev, "unexpected data width type");
177 		return -EINVAL;
178 	}
179 
180 	switch (i2s->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
181 	case SND_SOC_DAIFMT_I2S:
182 		if (data_bits == 16) {
183 			data_width = SSCR_DW_32BYTE;
184 			dma_data->maxburst = 32;
185 			dma_data->addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
186 		}
187 		break;
188 	case SND_SOC_DAIFMT_DSP_A:
189 	case SND_SOC_DAIFMT_DSP_B:
190 		break;
191 	default:
192 		dev_dbg(i2s->dev, "unexpected format type");
193 		return -EINVAL;
194 
195 	}
196 
197 	val = readl(i2s->base + SSCR);
198 	if (val & SSCR_SSE)
199 		return 0;
200 
201 	val &= ~SSCR_DW_32BYTE;
202 	val |= data_width;
203 	writel(val, i2s->base + SSCR);
204 
205 	bclk_rate = params_channels(params) *
206 		    params_rate(params) *
207 		    data_bits;
208 
209 	ret = clk_set_rate(i2s->bclk, bclk_rate);
210 	if (ret)
211 		return ret;
212 
213 	return clk_set_rate(i2s->sspa_clk, bclk_rate);
214 }
215 
spacemit_i2s_set_sysclk(struct snd_soc_dai * cpu_dai,int clk_id,unsigned int freq,int dir)216 static int spacemit_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
217 				   unsigned int freq, int dir)
218 {
219 	struct spacemit_i2s_dev *i2s = dev_get_drvdata(cpu_dai->dev);
220 
221 	if (freq == 0)
222 		return 0;
223 
224 	return clk_set_rate(i2s->sysclk, freq);
225 }
226 
spacemit_i2s_set_fmt(struct snd_soc_dai * cpu_dai,unsigned int fmt)227 static int spacemit_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
228 				unsigned int fmt)
229 {
230 	struct spacemit_i2s_dev *i2s = dev_get_drvdata(cpu_dai->dev);
231 	u32 sspsp_val;
232 
233 	sspsp_val = readl(i2s->base + SSPSP);
234 	sspsp_val &= ~SSPSP_FIELD_SFRMWDTH;
235 	sspsp_val |= SSPSP_FSRT;
236 
237 	i2s->dai_fmt = fmt;
238 
239 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
240 	case SND_SOC_DAIFMT_I2S:
241 		sspsp_val |= FIELD_PREP(SSPSP_FIELD_SFRMWDTH, 0x10);
242 		break;
243 	case SND_SOC_DAIFMT_DSP_B:
244 		/* DSP_B: next frame asserted after previous frame end, so clear FSRT */
245 		sspsp_val &= ~SSPSP_FSRT;
246 		fallthrough;
247 	case SND_SOC_DAIFMT_DSP_A:
248 		sspsp_val |= FIELD_PREP(SSPSP_FIELD_SFRMWDTH, 0x1);
249 		break;
250 	default:
251 		dev_dbg(i2s->dev, "unexpected format type");
252 		return -EINVAL;
253 	}
254 
255 	writel(sspsp_val, i2s->base + SSPSP);
256 
257 	return 0;
258 }
259 
spacemit_i2s_trigger(struct snd_pcm_substream * substream,int cmd,struct snd_soc_dai * dai)260 static int spacemit_i2s_trigger(struct snd_pcm_substream *substream,
261 				int cmd, struct snd_soc_dai *dai)
262 {
263 	struct spacemit_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai);
264 	u32 val;
265 
266 	switch (cmd) {
267 	case SNDRV_PCM_TRIGGER_START:
268 	case SNDRV_PCM_TRIGGER_RESUME:
269 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
270 		if (!i2s->started_count) {
271 			val = readl(i2s->base + SSCR);
272 			val |= SSCR_SSE;
273 			writel(val, i2s->base + SSCR);
274 		}
275 		i2s->started_count++;
276 		break;
277 	case SNDRV_PCM_TRIGGER_STOP:
278 	case SNDRV_PCM_TRIGGER_SUSPEND:
279 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
280 		if (i2s->started_count)
281 			i2s->started_count--;
282 
283 		if (!i2s->started_count) {
284 			val = readl(i2s->base + SSCR);
285 			val &= ~SSCR_SSE;
286 			writel(val, i2s->base + SSCR);
287 		}
288 		break;
289 	default:
290 		return -EINVAL;
291 	}
292 
293 	return 0;
294 }
295 
spacemit_i2s_dai_probe(struct snd_soc_dai * dai)296 static int spacemit_i2s_dai_probe(struct snd_soc_dai *dai)
297 {
298 	struct spacemit_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai);
299 
300 	snd_soc_dai_init_dma_data(dai,
301 				  i2s->has_playback ? &i2s->playback_dma_data : NULL,
302 				  i2s->has_capture ? &i2s->capture_dma_data : NULL);
303 
304 	reset_control_deassert(i2s->reset);
305 
306 	spacemit_i2s_init(i2s);
307 
308 	return 0;
309 }
310 
spacemit_i2s_dai_remove(struct snd_soc_dai * dai)311 static int spacemit_i2s_dai_remove(struct snd_soc_dai *dai)
312 {
313 	struct spacemit_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai);
314 
315 	reset_control_assert(i2s->reset);
316 
317 	return 0;
318 }
319 
320 static const struct snd_soc_dai_ops spacemit_i2s_dai_ops = {
321 	.probe = spacemit_i2s_dai_probe,
322 	.remove = spacemit_i2s_dai_remove,
323 	.startup = spacemit_i2s_startup,
324 	.hw_params = spacemit_i2s_hw_params,
325 	.set_sysclk = spacemit_i2s_set_sysclk,
326 	.set_fmt = spacemit_i2s_set_fmt,
327 	.trigger = spacemit_i2s_trigger,
328 };
329 
330 static struct snd_soc_dai_driver spacemit_i2s_dai = {
331 	.ops = &spacemit_i2s_dai_ops,
332 	.playback = {
333 		.channels_min = 1,
334 		.channels_max = 2,
335 		.rates = SPACEMIT_PCM_RATES,
336 		.rate_min = SNDRV_PCM_RATE_8000,
337 		.rate_max = SNDRV_PCM_RATE_48000,
338 		.formats = SPACEMIT_PCM_FORMATS,
339 	},
340 	.capture = {
341 		.channels_min = 1,
342 		.channels_max = 2,
343 		.rates = SPACEMIT_PCM_RATES,
344 		.rate_min = SNDRV_PCM_RATE_8000,
345 		.rate_max = SNDRV_PCM_RATE_48000,
346 		.formats = SPACEMIT_PCM_FORMATS,
347 	},
348 	.symmetric_rate = 1,
349 };
350 
spacemit_i2s_init_dai(struct spacemit_i2s_dev * i2s,struct snd_soc_dai_driver ** dp,dma_addr_t addr)351 static int spacemit_i2s_init_dai(struct spacemit_i2s_dev *i2s,
352 				 struct snd_soc_dai_driver **dp,
353 				 dma_addr_t addr)
354 {
355 	struct device_node *node = i2s->dev->of_node;
356 	struct snd_soc_dai_driver *dai;
357 	struct property *dma_names;
358 	const char *dma_name;
359 
360 	of_property_for_each_string(node, "dma-names", dma_names, dma_name) {
361 		if (!strcmp(dma_name, "tx"))
362 			i2s->has_playback = true;
363 		if (!strcmp(dma_name, "rx"))
364 			i2s->has_capture = true;
365 	}
366 
367 	dai = devm_kmemdup(i2s->dev, &spacemit_i2s_dai,
368 			   sizeof(*dai), GFP_KERNEL);
369 	if (!dai)
370 		return -ENOMEM;
371 
372 	if (i2s->has_playback) {
373 		dai->playback.stream_name = "Playback";
374 		dai->playback.channels_min = 1;
375 		dai->playback.channels_max = 2;
376 		dai->playback.rates = SPACEMIT_PCM_RATES;
377 		dai->playback.formats = SPACEMIT_PCM_FORMATS;
378 
379 		i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
380 		i2s->playback_dma_data.maxburst = 32;
381 		i2s->playback_dma_data.addr = addr;
382 	}
383 
384 	if (i2s->has_capture) {
385 		dai->capture.stream_name = "Capture";
386 		dai->capture.channels_min = 1;
387 		dai->capture.channels_max = 2;
388 		dai->capture.rates = SPACEMIT_PCM_RATES;
389 		dai->capture.formats = SPACEMIT_PCM_FORMATS;
390 
391 		i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
392 		i2s->capture_dma_data.maxburst = 32;
393 		i2s->capture_dma_data.addr = addr;
394 	}
395 
396 	if (dp)
397 		*dp = dai;
398 
399 	return 0;
400 }
401 
402 static const struct snd_soc_component_driver spacemit_i2s_component = {
403 	.name = "i2s-k1",
404 	.legacy_dai_naming = 1,
405 };
406 
spacemit_i2s_probe(struct platform_device * pdev)407 static int spacemit_i2s_probe(struct platform_device *pdev)
408 {
409 	struct snd_soc_dai_driver *dai;
410 	struct spacemit_i2s_dev *i2s;
411 	struct resource *res;
412 	struct clk *clk;
413 	int ret;
414 
415 	i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
416 	if (!i2s)
417 		return -ENOMEM;
418 
419 	i2s->dev = &pdev->dev;
420 
421 	i2s->sysclk = devm_clk_get_enabled(i2s->dev, "sysclk");
422 	if (IS_ERR(i2s->sysclk))
423 		return dev_err_probe(i2s->dev, PTR_ERR(i2s->sysclk),
424 				     "failed to enable sysbase clock\n");
425 
426 	i2s->bclk = devm_clk_get_enabled(i2s->dev, "bclk");
427 	if (IS_ERR(i2s->bclk))
428 		return dev_err_probe(i2s->dev, PTR_ERR(i2s->bclk), "failed to enable bit clock\n");
429 
430 	clk = devm_clk_get_enabled(i2s->dev, "sspa_bus");
431 	if (IS_ERR(clk))
432 		return dev_err_probe(i2s->dev, PTR_ERR(clk), "failed to enable sspa_bus clock\n");
433 
434 	i2s->sspa_clk = devm_clk_get_enabled(i2s->dev, "sspa");
435 	if (IS_ERR(i2s->sspa_clk))
436 		return dev_err_probe(i2s->dev, PTR_ERR(i2s->sspa_clk),
437 				     "failed to enable sspa clock\n");
438 
439 	i2s->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
440 	if (IS_ERR(i2s->base))
441 		return dev_err_probe(i2s->dev, PTR_ERR(i2s->base), "failed to map registers\n");
442 
443 	i2s->reset = devm_reset_control_get_exclusive(&pdev->dev, NULL);
444 	if (IS_ERR(i2s->reset))
445 		return dev_err_probe(i2s->dev, PTR_ERR(i2s->reset),
446 				     "failed to get reset control");
447 
448 	dev_set_drvdata(i2s->dev, i2s);
449 
450 	ret = spacemit_i2s_init_dai(i2s, &dai, res->start + SSDATR);
451 	if (ret)
452 		return ret;
453 
454 	ret = devm_snd_soc_register_component(i2s->dev,
455 					      &spacemit_i2s_component,
456 					      dai, 1);
457 	if (ret)
458 		return dev_err_probe(i2s->dev, ret, "failed to register component");
459 
460 	return devm_snd_dmaengine_pcm_register(&pdev->dev, &spacemit_dmaengine_pcm_config, 0);
461 }
462 
463 static const struct of_device_id spacemit_i2s_of_match[] = {
464 	{ .compatible = "spacemit,k1-i2s", },
465 	{ /* sentinel */ }
466 };
467 MODULE_DEVICE_TABLE(of, spacemit_i2s_of_match);
468 
469 static struct platform_driver spacemit_i2s_driver = {
470 	.probe = spacemit_i2s_probe,
471 	.driver = {
472 		.name = "i2s-k1",
473 		.of_match_table = spacemit_i2s_of_match,
474 	},
475 };
476 module_platform_driver(spacemit_i2s_driver);
477 
478 MODULE_LICENSE("GPL");
479 MODULE_DESCRIPTION("I2S bus driver for SpacemiT K1 SoC");
480