xref: /linux/sound/soc/renesas/rcar/msiof.c (revision 68a052239fc4b351e961f698b824f7654a346091)
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 <kuninori.morimoto.gx@renesas.com>
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 <kuninori.morimoto.gx@renesas.com>");
630