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