Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/renesas/rcar/msiof.c
29268 views
1
// SPDX-License-Identifier: GPL-2.0
2
//
3
// Renesas R-Car MSIOF (Clock-Synchronized Serial Interface with FIFO) I2S driver
4
//
5
// Copyright (C) 2025 Renesas Solutions Corp.
6
// Author: Kuninori Morimoto <[email protected]>
7
//
8
9
/*
10
* [NOTE-CLOCK-MODE]
11
*
12
* This driver doesn't support Clock/Frame Provider Mode
13
*
14
* Basically MSIOF is created for SPI, but we can use it as I2S (Sound), etc. Because of it, when
15
* we use it as I2S (Sound) with Provider Mode, we need to send dummy TX data even though it was
16
* used for RX. Because SPI HW needs TX Clock/Frame output for RX purpose.
17
* But it makes driver code complex in I2S (Sound).
18
*
19
* And when we use it as I2S (Sound) as Provider Mode, the clock source is [MSO clock] (= 133.33MHz)
20
* SoC internal clock. It is not for 48kHz/44.1kHz base clock. Thus the output/input will not be
21
* accurate sound.
22
*
23
* Because of these reasons, this driver doesn't support Clock/Frame Provider Mode. Use it as
24
* Clock/Frame Consumer Mode.
25
*/
26
27
/*
28
* [NOTE-RESET]
29
*
30
* MSIOF has TXRST/RXRST to reset FIFO, but it shouldn't be used during SYNC signal was asserted,
31
* because it will be cause of HW issue.
32
*
33
* When MSIOF is used as Sound driver, this driver is assuming it is used as clock consumer mode
34
* (= Codec is clock provider). This means, it can't control SYNC signal by itself.
35
*
36
* We need to use SW reset (= reset_control_xxx()) instead of TXRST/RXRST.
37
*/
38
39
/*
40
* [NOTE-BOTH-SETTING]
41
*
42
* SITMDRn / SIRMDRn and some other registers should not be updated during working even though it
43
* was not related the target direction (for example, do TX settings during RX is working),
44
* otherwise it cause a FSERR.
45
*
46
* Setup both direction (Playback/Capture) in the same time.
47
*/
48
49
/*
50
* [NOTE-R/L]
51
*
52
* The data of Captured might be R/L opposite.
53
*
54
* This driver is assuming MSIOF is used as Clock/Frame Consumer Mode, and there is a case that some
55
* Codec (= Clock/Frame Provider) might output Clock/Frame before setup MSIOF. It depends on Codec
56
* driver implementation.
57
*
58
* MSIOF will capture data without checking SYNC signal Hi/Low (= R/L).
59
*
60
* This means, if MSIOF RXE bit was set as 1 in case of SYNC signal was Hi (= R) timing, it will
61
* start capture data since next SYNC low singla (= L). Because Linux assumes sound data is lined
62
* up as R->L->R->L->..., the data R/L will be opposite.
63
*
64
* The only solution in this case is start CLK/SYNC *after* MSIOF settings, but it depends when and
65
* how Codec driver start it.
66
*/
67
68
/*
69
* [NOTE-FSERR]
70
*
71
* We can't remove all FSERR.
72
*
73
* Renesas have tried to minimize the occurrence of FSERR errors as much as possible, but
74
* unfortunately we cannot remove them completely, because MSIOF might setup its register during
75
* CLK/SYNC are inputed. It can be happen because MSIOF is working as Clock/Frame Consumer.
76
*/
77
78
#include <linux/module.h>
79
#include <linux/of.h>
80
#include <linux/of_dma.h>
81
#include <linux/of_graph.h>
82
#include <linux/platform_device.h>
83
#include <linux/pm_runtime.h>
84
#include <linux/reset.h>
85
#include <linux/spi/sh_msiof.h>
86
#include <sound/dmaengine_pcm.h>
87
#include <sound/soc.h>
88
89
/* SISTR */
90
#define SISTR_ERR_TX (SISTR_TFSERR | SISTR_TFOVF | SISTR_TFUDF)
91
#define SISTR_ERR_RX (SISTR_RFSERR | SISTR_RFOVF | SISTR_RFUDF)
92
93
/*
94
* The data on memory in 24bit case is located at <right> side
95
* [ xxxxxx]
96
* [ xxxxxx]
97
* [ xxxxxx]
98
*
99
* HW assuming signal in 24bit case is located at <left> side
100
* ---+ +---------+
101
* +---------+ +---------+...
102
* [xxxxxx ][xxxxxx ][xxxxxx ]
103
*
104
* When we use 24bit data, it will be transferred via 32bit width via DMA,
105
* and MSIOF/DMA doesn't support data shift, we can't use 24bit data correctly.
106
* There is no such issue on 16/32bit data case.
107
*/
108
#define MSIOF_RATES SNDRV_PCM_RATE_8000_192000
109
#define MSIOF_FMTS (SNDRV_PCM_FMTBIT_S16_LE |\
110
SNDRV_PCM_FMTBIT_S32_LE)
111
112
struct msiof_priv {
113
struct device *dev;
114
struct snd_pcm_substream *substream[SNDRV_PCM_STREAM_LAST + 1];
115
struct reset_control *reset;
116
spinlock_t lock;
117
void __iomem *base;
118
resource_size_t phy_addr;
119
120
int count;
121
122
/* for error */
123
int err_syc[SNDRV_PCM_STREAM_LAST + 1];
124
int err_ovf[SNDRV_PCM_STREAM_LAST + 1];
125
int err_udf[SNDRV_PCM_STREAM_LAST + 1];
126
127
/* bit field */
128
u32 flags;
129
#define MSIOF_FLAGS_NEED_DELAY (1 << 0)
130
};
131
#define msiof_flag_has(priv, flag) (priv->flags & flag)
132
#define msiof_flag_set(priv, flag) (priv->flags |= flag)
133
134
#define msiof_is_play(substream) ((substream)->stream == SNDRV_PCM_STREAM_PLAYBACK)
135
#define msiof_read(priv, reg) ioread32((priv)->base + reg)
136
#define msiof_write(priv, reg, val) iowrite32(val, (priv)->base + reg)
137
138
static int msiof_update(struct msiof_priv *priv, u32 reg, u32 mask, u32 val)
139
{
140
u32 old = msiof_read(priv, reg);
141
u32 new = (old & ~mask) | (val & mask);
142
int updated = false;
143
144
if (old != new) {
145
msiof_write(priv, reg, new);
146
updated = true;
147
}
148
149
return updated;
150
}
151
152
static void msiof_update_and_wait(struct msiof_priv *priv, u32 reg, u32 mask, u32 val, u32 expect)
153
{
154
u32 data;
155
int ret;
156
157
ret = msiof_update(priv, reg, mask, val);
158
if (!ret) /* no update */
159
return;
160
161
ret = readl_poll_timeout_atomic(priv->base + reg, data,
162
(data & mask) == expect, 1, 128);
163
if (ret)
164
dev_warn(priv->dev, "write timeout [0x%02x] 0x%08x / 0x%08x\n",
165
reg, data, expect);
166
}
167
168
static int msiof_hw_start(struct snd_soc_component *component,
169
struct snd_pcm_substream *substream, int cmd)
170
{
171
struct msiof_priv *priv = snd_soc_component_get_drvdata(component);
172
struct snd_pcm_runtime *runtime = substream->runtime;
173
int is_play = msiof_is_play(substream);
174
int width = snd_pcm_format_width(runtime->format);
175
u32 val;
176
177
/*
178
* see
179
* [NOTE-CLOCK-MODE] on top of this driver
180
*/
181
/*
182
* see
183
* Datasheet 109.3.6 [Transmit and Receive Procedures]
184
*
185
* TX: Fig 109.14 - Fig 109.23
186
* RX: Fig 109.15
187
*/
188
189
/*
190
* Use reset_control_xx() instead of TXRST/RXRST.
191
* see
192
* [NOTE-RESET]
193
*/
194
if (!priv->count)
195
reset_control_deassert(priv->reset);
196
197
priv->count++;
198
199
/*
200
* Reset errors. ignore 1st FSERR
201
*
202
* see
203
* [NOTE-FSERR]
204
*/
205
priv->err_syc[substream->stream] = -1;
206
priv->err_ovf[substream->stream] =
207
priv->err_udf[substream->stream] = 0;
208
209
/* Start DMAC */
210
snd_dmaengine_pcm_trigger(substream, cmd);
211
212
/*
213
* setup both direction (Playback/Capture) in the same time.
214
* see
215
* above [NOTE-BOTH-SETTING]
216
*/
217
218
/* SITMDRx */
219
val = SITMDR1_PCON | SIMDR1_SYNCAC | SIMDR1_XXSTP |
220
FIELD_PREP(SIMDR1_SYNCMD, SIMDR1_SYNCMD_LR);
221
if (msiof_flag_has(priv, MSIOF_FLAGS_NEED_DELAY))
222
val |= FIELD_PREP(SIMDR1_DTDL, 1);
223
224
msiof_write(priv, SITMDR1, val);
225
226
val = FIELD_PREP(SIMDR2_BITLEN1, width - 1);
227
msiof_write(priv, SITMDR2, val | FIELD_PREP(SIMDR2_GRP, 1));
228
msiof_write(priv, SITMDR3, val);
229
230
/* SIRMDRx */
231
val = SIMDR1_SYNCAC |
232
FIELD_PREP(SIMDR1_SYNCMD, SIMDR1_SYNCMD_LR);
233
if (msiof_flag_has(priv, MSIOF_FLAGS_NEED_DELAY))
234
val |= FIELD_PREP(SIMDR1_DTDL, 1);
235
236
msiof_write(priv, SIRMDR1, val);
237
238
val = FIELD_PREP(SIMDR2_BITLEN1, width - 1);
239
msiof_write(priv, SIRMDR2, val | FIELD_PREP(SIMDR2_GRP, 1));
240
msiof_write(priv, SIRMDR3, val);
241
242
/* SIFCTR */
243
msiof_write(priv, SIFCTR,
244
FIELD_PREP(SIFCTR_TFWM, SIFCTR_TFWM_1) |
245
FIELD_PREP(SIFCTR_RFWM, SIFCTR_RFWM_1));
246
247
/* SIIER */
248
if (is_play)
249
val = SIIER_TDREQE | SIIER_TDMAE | SISTR_ERR_TX;
250
else
251
val = SIIER_RDREQE | SIIER_RDMAE | SISTR_ERR_RX;
252
msiof_update(priv, SIIER, val, val);
253
254
/* clear status */
255
if (is_play)
256
val = SISTR_ERR_TX;
257
else
258
val = SISTR_ERR_RX;
259
msiof_update(priv, SISTR, val, val);
260
261
/* SICTR */
262
val = SICTR_TEDG | SICTR_REDG;
263
if (is_play)
264
val |= SICTR_TXE;
265
else
266
val |= SICTR_RXE;
267
msiof_update_and_wait(priv, SICTR, val, val, val);
268
269
return 0;
270
}
271
272
static int msiof_hw_stop(struct snd_soc_component *component,
273
struct snd_pcm_substream *substream, int cmd)
274
{
275
struct msiof_priv *priv = snd_soc_component_get_drvdata(component);
276
struct device *dev = component->dev;
277
int is_play = msiof_is_play(substream);
278
u32 val;
279
280
/* SIIER */
281
if (is_play)
282
val = SIIER_TDREQE | SIIER_TDMAE | SISTR_ERR_TX;
283
else
284
val = SIIER_RDREQE | SIIER_RDMAE | SISTR_ERR_RX;
285
msiof_update(priv, SIIER, val, 0);
286
287
/* SICTR */
288
if (is_play)
289
val = SICTR_TXE;
290
else
291
val = SICTR_RXE;
292
msiof_update_and_wait(priv, SICTR, val, 0, 0);
293
294
/* Stop DMAC */
295
snd_dmaengine_pcm_trigger(substream, cmd);
296
297
/*
298
* Ignore 1st FSERR
299
*
300
* see
301
* [NOTE-FSERR]
302
*/
303
if (priv->err_syc[substream->stream] < 0)
304
priv->err_syc[substream->stream] = 0;
305
306
/* indicate error status if exist */
307
if (priv->err_syc[substream->stream] ||
308
priv->err_ovf[substream->stream] ||
309
priv->err_udf[substream->stream])
310
dev_warn(dev, "%s: FSERR = %d, FOVF = %d, FUDF = %d\n",
311
snd_pcm_direction_name(substream->stream),
312
priv->err_syc[substream->stream],
313
priv->err_ovf[substream->stream],
314
priv->err_udf[substream->stream]);
315
316
priv->count--;
317
318
if (!priv->count)
319
reset_control_assert(priv->reset);
320
321
return 0;
322
}
323
324
static int msiof_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
325
{
326
struct msiof_priv *priv = snd_soc_dai_get_drvdata(dai);
327
328
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
329
/*
330
* It supports Clock/Frame Consumer Mode only
331
* see
332
* [NOTE] on top of this driver
333
*/
334
case SND_SOC_DAIFMT_BC_FC:
335
break;
336
/* others are error */
337
default:
338
return -EINVAL;
339
}
340
341
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
342
/* it supports NB_NF only */
343
case SND_SOC_DAIFMT_NB_NF:
344
default:
345
break;
346
/* others are error */
347
case SND_SOC_DAIFMT_NB_IF:
348
case SND_SOC_DAIFMT_IB_NF:
349
case SND_SOC_DAIFMT_IB_IF:
350
return -EINVAL;
351
}
352
353
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
354
case SND_SOC_DAIFMT_I2S:
355
msiof_flag_set(priv, MSIOF_FLAGS_NEED_DELAY);
356
break;
357
case SND_SOC_DAIFMT_LEFT_J:
358
break;
359
default:
360
return -EINVAL;
361
}
362
363
return 0;
364
}
365
366
/*
367
* Select below from Sound Card, not auto
368
* SND_SOC_DAIFMT_CBC_CFC
369
* SND_SOC_DAIFMT_CBP_CFP
370
*/
371
static const u64 msiof_dai_formats = SND_SOC_POSSIBLE_DAIFMT_I2S |
372
SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
373
SND_SOC_POSSIBLE_DAIFMT_NB_NF;
374
375
static const struct snd_soc_dai_ops msiof_dai_ops = {
376
.set_fmt = msiof_dai_set_fmt,
377
.auto_selectable_formats = &msiof_dai_formats,
378
.num_auto_selectable_formats = 1,
379
};
380
381
static struct snd_soc_dai_driver msiof_dai_driver = {
382
.name = "msiof-dai",
383
.playback = {
384
.rates = MSIOF_RATES,
385
.formats = MSIOF_FMTS,
386
.channels_min = 2,
387
.channels_max = 2,
388
},
389
.capture = {
390
.rates = MSIOF_RATES,
391
.formats = MSIOF_FMTS,
392
.channels_min = 2,
393
.channels_max = 2,
394
},
395
.ops = &msiof_dai_ops,
396
.symmetric_rate = 1,
397
.symmetric_channels = 1,
398
.symmetric_sample_bits = 1,
399
};
400
401
static struct snd_pcm_hardware msiof_pcm_hardware = {
402
.info = SNDRV_PCM_INFO_INTERLEAVED |
403
SNDRV_PCM_INFO_MMAP |
404
SNDRV_PCM_INFO_MMAP_VALID,
405
.buffer_bytes_max = 64 * 1024,
406
.period_bytes_min = 32,
407
.period_bytes_max = 8192,
408
.periods_min = 1,
409
.periods_max = 32,
410
.fifo_size = 64,
411
};
412
413
static int msiof_open(struct snd_soc_component *component,
414
struct snd_pcm_substream *substream)
415
{
416
struct device *dev = component->dev;
417
struct dma_chan *chan;
418
static const char * const dma_names[] = {"rx", "tx"};
419
int is_play = msiof_is_play(substream);
420
int ret;
421
422
chan = of_dma_request_slave_channel(dev->of_node, dma_names[is_play]);
423
if (IS_ERR(chan))
424
return PTR_ERR(chan);
425
426
ret = snd_dmaengine_pcm_open(substream, chan);
427
if (ret < 0)
428
goto open_err_dma;
429
430
snd_soc_set_runtime_hwparams(substream, &msiof_pcm_hardware);
431
432
ret = snd_pcm_hw_constraint_integer(substream->runtime, SNDRV_PCM_HW_PARAM_PERIODS);
433
434
open_err_dma:
435
if (ret < 0)
436
dma_release_channel(chan);
437
438
return ret;
439
}
440
441
static int msiof_close(struct snd_soc_component *component,
442
struct snd_pcm_substream *substream)
443
{
444
return snd_dmaengine_pcm_close_release_chan(substream);
445
}
446
447
static snd_pcm_uframes_t msiof_pointer(struct snd_soc_component *component,
448
struct snd_pcm_substream *substream)
449
{
450
return snd_dmaengine_pcm_pointer(substream);
451
}
452
453
#define PREALLOC_BUFFER (32 * 1024)
454
#define PREALLOC_BUFFER_MAX (32 * 1024)
455
static int msiof_new(struct snd_soc_component *component,
456
struct snd_soc_pcm_runtime *rtd)
457
{
458
snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
459
rtd->card->snd_card->dev,
460
PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
461
return 0;
462
}
463
464
static int msiof_trigger(struct snd_soc_component *component,
465
struct snd_pcm_substream *substream, int cmd)
466
{
467
struct device *dev = component->dev;
468
struct msiof_priv *priv = dev_get_drvdata(dev);
469
int ret = -EINVAL;
470
471
guard(spinlock_irqsave)(&priv->lock);
472
473
switch (cmd) {
474
case SNDRV_PCM_TRIGGER_START:
475
priv->substream[substream->stream] = substream;
476
fallthrough;
477
case SNDRV_PCM_TRIGGER_RESUME:
478
ret = msiof_hw_start(component, substream, cmd);
479
break;
480
case SNDRV_PCM_TRIGGER_STOP:
481
priv->substream[substream->stream] = NULL;
482
fallthrough;
483
case SNDRV_PCM_TRIGGER_SUSPEND:
484
ret = msiof_hw_stop(component, substream, cmd);
485
break;
486
}
487
488
return ret;
489
}
490
491
static int msiof_hw_params(struct snd_soc_component *component,
492
struct snd_pcm_substream *substream,
493
struct snd_pcm_hw_params *params)
494
{
495
struct msiof_priv *priv = dev_get_drvdata(component->dev);
496
struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
497
struct dma_slave_config cfg = {};
498
int ret;
499
500
guard(spinlock_irqsave)(&priv->lock);
501
502
ret = snd_hwparams_to_dma_slave_config(substream, params, &cfg);
503
if (ret < 0)
504
return ret;
505
506
cfg.dst_addr = priv->phy_addr + SITFDR;
507
cfg.src_addr = priv->phy_addr + SIRFDR;
508
509
return dmaengine_slave_config(chan, &cfg);
510
}
511
512
static const struct snd_soc_component_driver msiof_component_driver = {
513
.name = "msiof",
514
.open = msiof_open,
515
.close = msiof_close,
516
.pointer = msiof_pointer,
517
.pcm_construct = msiof_new,
518
.trigger = msiof_trigger,
519
.hw_params = msiof_hw_params,
520
};
521
522
static irqreturn_t msiof_interrupt(int irq, void *data)
523
{
524
struct msiof_priv *priv = data;
525
struct snd_pcm_substream *substream;
526
u32 sistr;
527
528
scoped_guard(spinlock, &priv->lock) {
529
sistr = msiof_read(priv, SISTR);
530
msiof_write(priv, SISTR, SISTR_ERR_TX | SISTR_ERR_RX);
531
}
532
533
/* overflow/underflow error */
534
substream = priv->substream[SNDRV_PCM_STREAM_PLAYBACK];
535
if (substream && (sistr & SISTR_ERR_TX)) {
536
// snd_pcm_stop_xrun(substream);
537
if (sistr & SISTR_TFSERR)
538
priv->err_syc[SNDRV_PCM_STREAM_PLAYBACK]++;
539
if (sistr & SISTR_TFOVF)
540
priv->err_ovf[SNDRV_PCM_STREAM_PLAYBACK]++;
541
if (sistr & SISTR_TFUDF)
542
priv->err_udf[SNDRV_PCM_STREAM_PLAYBACK]++;
543
}
544
545
substream = priv->substream[SNDRV_PCM_STREAM_CAPTURE];
546
if (substream && (sistr & SISTR_ERR_RX)) {
547
// snd_pcm_stop_xrun(substream);
548
if (sistr & SISTR_RFSERR)
549
priv->err_syc[SNDRV_PCM_STREAM_CAPTURE]++;
550
if (sistr & SISTR_RFOVF)
551
priv->err_ovf[SNDRV_PCM_STREAM_CAPTURE]++;
552
if (sistr & SISTR_RFUDF)
553
priv->err_udf[SNDRV_PCM_STREAM_CAPTURE]++;
554
}
555
556
return IRQ_HANDLED;
557
}
558
559
static int msiof_probe(struct platform_device *pdev)
560
{
561
struct msiof_priv *priv;
562
struct device *dev = &pdev->dev;
563
struct resource *res;
564
int irq, ret;
565
566
/* Check MSIOF as Sound mode or SPI mode */
567
struct device_node *port __free(device_node) = of_graph_get_next_port(dev->of_node, NULL);
568
if (!port)
569
return -ENODEV;
570
571
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
572
if (!res)
573
return -ENODEV;
574
575
irq = platform_get_irq(pdev, 0);
576
if (irq <= 0)
577
return irq;
578
579
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
580
if (!priv)
581
return -ENOMEM;
582
583
priv->base = devm_ioremap_resource(dev, res);
584
if (IS_ERR(priv->base))
585
return PTR_ERR(priv->base);
586
587
priv->reset = devm_reset_control_get_exclusive(dev, NULL);
588
if (IS_ERR(priv->reset))
589
return PTR_ERR(priv->reset);
590
591
reset_control_assert(priv->reset);
592
593
ret = devm_request_irq(dev, irq, msiof_interrupt, 0, dev_name(dev), priv);
594
if (ret)
595
return ret;
596
597
priv->dev = dev;
598
priv->phy_addr = res->start;
599
priv->count = 0;
600
601
spin_lock_init(&priv->lock);
602
platform_set_drvdata(pdev, priv);
603
604
devm_pm_runtime_enable(dev);
605
606
ret = devm_snd_soc_register_component(dev, &msiof_component_driver,
607
&msiof_dai_driver, 1);
608
609
return ret;
610
}
611
612
static const struct of_device_id msiof_of_match[] = {
613
{ .compatible = "renesas,rcar-gen4-msiof", },
614
{},
615
};
616
MODULE_DEVICE_TABLE(of, msiof_of_match);
617
618
static struct platform_driver msiof_driver = {
619
.driver = {
620
.name = "msiof-pcm-audio",
621
.of_match_table = msiof_of_match,
622
},
623
.probe = msiof_probe,
624
};
625
module_platform_driver(msiof_driver);
626
627
MODULE_LICENSE("GPL");
628
MODULE_DESCRIPTION("Renesas R-Car MSIOF I2S audio driver");
629
MODULE_AUTHOR("Kuninori Morimoto <[email protected]>");
630
631