Re: [PATCH 6/7] ASoC: renesas: add MSIOF sound support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Morimoto-san,

On Wed, 9 Apr 2025 at 03:05, Kuninori Morimoto
<kuninori.morimoto.gx@xxxxxxxxxxx> wrote:
> Renesas MSIOF (Clock-Synchronized Serial Interface with FIFO) can work as
> both SPI and I2S. Adds MSIOF-I2S driver.
>
> MSIOF-SPI/I2S are using same DT compatible properties.
> MSIOF-I2S         uses Of-Graph for Audio-Graph-Card/Card2,
> MSIOF-SPI doesn't use  Of-Graph.
>
> Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@xxxxxxxxxxx>

Thanks for your patch!

> --- a/sound/soc/renesas/Kconfig
> +++ b/sound/soc/renesas/Kconfig
> @@ -46,6 +46,13 @@ config SND_SOC_RCAR
>         help
>           This option enables R-Car SRU/SCU/SSIU/SSI sound support
>
> +config SND_SOC_MSIOF
> +       tristate "R-Car series MSIOF support"
> +       depends on OF

depends on ARCH_RENESAS || COMPILE_TEST

> +       select SND_DMAENGINE_PCM
> +       help
> +         This option enables R-Car MSIOF sound support
> +
>  config SND_SOC_RZ
>         tristate "RZ/G2L series SSIF-2 support"
>         depends on ARCH_RZG2L || COMPILE_TEST
> diff --git a/sound/soc/renesas/rcar/Makefile b/sound/soc/renesas/rcar/Makefile
> index 45eb875a912a..3a2c875595bd 100644
> --- a/sound/soc/renesas/rcar/Makefile
> +++ b/sound/soc/renesas/rcar/Makefile
> @@ -1,3 +1,6 @@
>  # SPDX-License-Identifier: GPL-2.0
>  snd-soc-rcar-y         := core.o gen.o dma.o adg.o ssi.o ssiu.o src.o ctu.o mix.o dvc.o cmd.o debugfs.o
>  obj-$(CONFIG_SND_SOC_RCAR)     += snd-soc-rcar.o
> +
> +snd-soc-msiof-y                        := msiof.o
> +obj-$(CONFIG_SND_SOC_MSIOF)    += snd-soc-msiof.o
> diff --git a/sound/soc/renesas/rcar/msiof.c b/sound/soc/renesas/rcar/msiof.c
> new file mode 100644
> index 000000000000..de8de3468402
> --- /dev/null
> +++ b/sound/soc/renesas/rcar/msiof.c
> @@ -0,0 +1,579 @@
> +// SPDX-License-Identifier: GPL-2.0
> +//
> +// Renesas R-Car MSIOF (Clock-Synchronized Serial Interface with FIFO) I2S driver
> +//
> +// Copyright (C) 2025 Renesas Solutions Corp.
> +// Author: Kuninori Morimoto <kuninori.morimoto.gx@xxxxxxxxxxx>
> +//
> +
> +/*
> + * [NOTE]
> + *
> + * This driver doesn't support Clock/Frame Provider Mode
> + *
> + * Basically MSIOF is created for SPI, but we can use it as I2S (Sound). Because of it, when we use
> + * it as I2S (Sound) with Provider Mode, we need to send dummy TX data even though it is used for
> + * RX. Because SPI HW needs TX Clock/Frame output for RX purpose also. It makes driver code complex.
> + *
> + * And when we use MSIOF (Sound) as Provider Mode, the clock source is [MSO clock] (= 133.33MHz)
> + * SoC internal clock. It is not for 48kHz/44.1kHz base clock. Thus the output/input will not be
> + * accurate sound.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_dma.h>
> +#include <linux/of_graph.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +#include <sound/dmaengine_pcm.h>
> +#include <sound/soc.h>
> +
> +/* register */
> +#define SITMDR1                0x00
> +#define SITMDR2                0x04
> +#define SITMDR3                0x08
> +#define SIRMDR1                0x10
> +#define SIRMDR2                0x14
> +#define SIRMDR3                0x18
> +#define SITSCR         0x20
> +#define SICTR          0x28
> +#define SIFCTR         0x30
> +#define SISTR          0x40
> +#define SIIER          0x44
> +#define SITFDR         0x50
> +#define SIRFDR         0x60

[...]

Perhaps the register definitions can be shared with spi-sh-msiof.c,
by extracting them into a shared header file?

Note that I have already converted drivers/spi/spi-sh-msiof.c locally
to use FIELD_PREP() (which requires changes to some macros), so we
may want to implement the sharing later.

> +static int msiof_hw_start(struct snd_soc_component *component,
> +                         struct snd_pcm_substream *substream, int cmd)
> +{
> +       struct msiof_priv *priv = snd_soc_component_get_drvdata(component);
> +       struct snd_pcm_runtime *runtime = substream->runtime;
> +       int is_play = msiof_is_play(substream);
> +       int width = snd_pcm_format_width(runtime->format);
> +       u32 val;
> +
> +       /*
> +        * see
> +        *      Datasheet 109.3.6 [Transmit and Receive Procedures]
> +        *
> +        *      TX: Fig 109.14  - Fig 109.23
> +        *      RX: Fig 109.15
> +        */
> +
> +       /* reset errors */
> +       priv->err_syc[substream->stream] =
> +       priv->err_ovf[substream->stream] =
> +       priv->err_udf[substream->stream] = 0;
> +
> +       /* SITMDRx */
> +       if (is_play) {
> +               val = PCON | SYNCMD_LR | SYNCAC | TXSTP;
> +               if (msiof_flag_has(priv, MSIOF_FLAGS_NEED_DELAY))
> +                       val |= DTDL_1;
> +
> +               msiof_write(priv, SITMDR1, val);
> +
> +               val = BITLEN1(width);
> +               msiof_write(priv, SITMDR2, val | GRP);
> +               msiof_write(priv, SITMDR3, val);
> +

Don't you have to initialize SITMDR[123] unconditionally, as reception
requires transmitting dummy data on R-Car (cfr. SPI_CONTROLLER_MUST_TX)?

> +       }
> +       /* SIRMDRx */
> +       else {
> +               val = SYNCMD_LR | SYNCAC;
> +               if (msiof_flag_has(priv, MSIOF_FLAGS_NEED_DELAY))
> +                       val |= DTDL_1;
> +
> +               msiof_write(priv, SIRMDR1, val);
> +
> +               val = BITLEN1(width);
> +               msiof_write(priv, SIRMDR2, val | GRP);
> +               msiof_write(priv, SIRMDR3, val);
> +       }
> +
> +       /* SIIER */
> +       if (is_play)
> +               val = TDREQE | TDMAE | SISTR_ERR_TX;
> +       else
> +               val = RDREQE | RDMAE | SISTR_ERR_RX;

Likewise for transmit control flags.

> +       msiof_update(priv, SIIER, val, val);
> +
> +       /* SICTR */
> +       if (is_play)
> +               val = TXE | TEDG;
> +       else
> +               val = RXE | REDG;

Likewise,

> +       msiof_update_and_wait(priv, SICTR, val, val, val);
> +
> +       msiof_status_clear(priv);
> +
> +       /* Start DMAC */
> +       snd_dmaengine_pcm_trigger(substream, cmd);
> +
> +       return 0;
> +}
> +
> +static int msiof_hw_stop(struct snd_soc_component *component,
> +                        struct snd_pcm_substream *substream, int cmd)
> +{
> +       struct msiof_priv *priv = snd_soc_component_get_drvdata(component);
> +       struct device *dev = component->dev;
> +       int is_play = msiof_is_play(substream);
> +       u32 val;
> +
> +       /* SIIER */
> +       if (is_play)
> +               val = TDREQE | TDMAE | SISTR_ERR_TX;
> +       else
> +               val = RDREQE | RDMAE | SISTR_ERR_RX;

Likewise.

> +       msiof_update(priv, SIIER, val, 0);
> +
> +       /* Stop DMAC */
> +       snd_dmaengine_pcm_trigger(substream, cmd);
> +
> +       /* SICTR */
> +       if (is_play)
> +               val = TXE;
> +       else
> +               val = RXE;

Likewise.

> +       msiof_update_and_wait(priv, SICTR, val, 0, 0);
> +
> +       /* indicate error status if exist */
> +       if (priv->err_syc[substream->stream] ||
> +           priv->err_ovf[substream->stream] ||
> +           priv->err_udf[substream->stream])
> +               dev_warn(dev, "FSERR(%s) = %d, FOVF = %d, FUDF = %d\n",
> +                        snd_pcm_direction_name(substream->stream),
> +                        priv->err_syc[substream->stream],
> +                        priv->err_ovf[substream->stream],
> +                        priv->err_udf[substream->stream]);
> +
> +       return 0;
> +}

> +static int msiof_probe(struct platform_device *pdev)
> +{
> +       struct msiof_priv *priv;
> +       struct device *dev = &pdev->dev;
> +       struct resource *res;
> +       struct device_node *port;
> +       int irq, ret;
> +
> +       /* Check MSIOF as Sound mode or SPI mode */
> +       port = of_graph_get_next_port(dev->of_node, NULL);
> +       if (!port)
> +               return -ENODEV;
> +       of_node_put(port);

Just wondering: don't you need to use port? Or is that handled
elsewhere, in common sound code?

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@xxxxxxxxxxxxxx

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds




[Index of Archives]     [Linux Samsung SOC]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux