File Index
Files and directories
Sign in
FILE

msiof.c

File preview with syntax highlighting.

linux-6.19.14/sound/soc/renesas/rcar/msiof.c C
  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
112struct 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
138static 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
152static 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
168static 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
272static 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
324static 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 */
371static 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
375static 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
381static 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
401static 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
413static 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
434open_err_dma:
435	if (ret < 0)
436		dma_release_channel(chan);
437
438	return ret;
439}
440
441static 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
447static 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)
455static 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
464static 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
491static 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
512static 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
522static 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
559static 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
612static const struct of_device_id msiof_of_match[] = {
613	{ .compatible = "renesas,rcar-gen4-msiof", },
614	{},
615};
616MODULE_DEVICE_TABLE(of, msiof_of_match);
617
618static 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};
625module_platform_driver(msiof_driver);
626
627MODULE_LICENSE("GPL");
628MODULE_DESCRIPTION("Renesas R-Car MSIOF I2S audio driver");
629MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
~/ Read-only file preview.