Lines Matching +full:gx +full:- +full:sound +full:- +full:card

1 // SPDX-License-Identifier: GPL-2.0
3 // Renesas R-Car MSIOF (Clock-Synchronized Serial Interface with FIFO) I2S driver
6 // Author: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
10 * [NOTE-CLOCK-MODE]
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
17 * But it makes driver code complex in I2S (Sound).
19 * And when we use it as I2S (Sound) as Provider Mode, the clock source is [MSO clock] (= 133.33MHz)
21 * accurate sound.
28 * [NOTE-RESET]
33 * When MSIOF is used as Sound driver, this driver is assuming it is used as clock consumer mode
40 * [NOTE-BOTH-SETTING]
50 * [NOTE-R/L]
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.
69 * [NOTE-FSERR]
86 #include <sound/dmaengine_pcm.h>
87 #include <sound/soc.h>
100 * ---+ +---------+
101 * +---------+ +---------+...
131 #define msiof_flag_has(priv, flag) (priv->flags & flag)
132 #define msiof_flag_set(priv, flag) (priv->flags |= flag)
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)
161 ret = readl_poll_timeout_atomic(priv->base + reg, data,
164 dev_warn(priv->dev, "write timeout [0x%02x] 0x%08x / 0x%08x\n",
172 struct snd_pcm_runtime *runtime = substream->runtime;
174 int width = snd_pcm_format_width(runtime->format);
179 * [NOTE-CLOCK-MODE] on top of this driver
185 * TX: Fig 109.14 - Fig 109.23
192 * [NOTE-RESET]
194 if (!priv->count)
195 reset_control_deassert(priv->reset);
197 priv->count++;
203 * [NOTE-FSERR]
205 priv->err_syc[substream->stream] = -1;
206 priv->err_ovf[substream->stream] =
207 priv->err_udf[substream->stream] = 0;
215 * above [NOTE-BOTH-SETTING]
226 val = FIELD_PREP(SIMDR2_BITLEN1, width - 1);
238 val = FIELD_PREP(SIMDR2_BITLEN1, width - 1);
276 struct device *dev = component->dev;
301 * [NOTE-FSERR]
303 if (priv->err_syc[substream->stream] < 0)
304 priv->err_syc[substream->stream] = 0;
307 if (priv->err_syc[substream->stream] ||
308 priv->err_ovf[substream->stream] ||
309 priv->err_udf[substream->stream])
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]);
316 priv->count--;
318 if (!priv->count)
319 reset_control_assert(priv->reset);
338 return -EINVAL;
350 return -EINVAL;
360 return -EINVAL;
367 * Select below from Sound Card, not auto
382 .name = "msiof-dai",
416 struct device *dev = component->dev;
422 chan = of_dma_request_slave_channel(dev->of_node, dma_names[is_play]);
432 ret = snd_pcm_hw_constraint_integer(substream->runtime, SNDRV_PCM_HW_PARAM_PERIODS);
458 snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
459 rtd->card->snd_card->dev,
467 struct device *dev = component->dev;
469 int ret = -EINVAL;
471 guard(spinlock_irqsave)(&priv->lock);
475 priv->substream[substream->stream] = substream;
481 priv->substream[substream->stream] = NULL;
495 struct msiof_priv *priv = dev_get_drvdata(component->dev);
500 guard(spinlock_irqsave)(&priv->lock);
506 cfg.dst_addr = priv->phy_addr + SITFDR;
507 cfg.src_addr = priv->phy_addr + SIRFDR;
528 scoped_guard(spinlock, &priv->lock) {
534 substream = priv->substream[SNDRV_PCM_STREAM_PLAYBACK];
538 priv->err_syc[SNDRV_PCM_STREAM_PLAYBACK]++;
540 priv->err_ovf[SNDRV_PCM_STREAM_PLAYBACK]++;
542 priv->err_udf[SNDRV_PCM_STREAM_PLAYBACK]++;
545 substream = priv->substream[SNDRV_PCM_STREAM_CAPTURE];
549 priv->err_syc[SNDRV_PCM_STREAM_CAPTURE]++;
551 priv->err_ovf[SNDRV_PCM_STREAM_CAPTURE]++;
553 priv->err_udf[SNDRV_PCM_STREAM_CAPTURE]++;
562 struct device *dev = &pdev->dev;
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);
569 return -ENODEV;
573 return -ENODEV;
581 return -ENOMEM;
583 priv->base = devm_ioremap_resource(dev, res);
584 if (IS_ERR(priv->base))
585 return PTR_ERR(priv->base);
587 priv->reset = devm_reset_control_get_exclusive(dev, NULL);
588 if (IS_ERR(priv->reset))
589 return PTR_ERR(priv->reset);
591 reset_control_assert(priv->reset);
597 priv->dev = dev;
598 priv->phy_addr = res->start;
599 priv->count = 0;
601 spin_lock_init(&priv->lock);
613 { .compatible = "renesas,rcar-gen4-msiof", },
620 .name = "msiof-pcm-audio",
628 MODULE_DESCRIPTION("Renesas R-Car MSIOF I2S audio driver");
629 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");