[PATCH v1 0/2] Add Cadence I2S controller driver for the
The Cadence I2S Controller implements a function of the multi-channel (up to 8-channel) bus. Each stereo channel combines functions of a transmitter and a receiver, and can switch freely between them. Each channel has independent gating, clock and interruption control. It also support some of these channels are used as playback and others can also be used as record in the same time.
Four I2S controllers are used on the StarFive JH8100 SoC. Two of the I2S controllers use two stereo channels, one of them use four channels, and one use eight. It had tested on the fpga with WM8960.
Xingyu Wu (2): dt-bindings: ASoC: Add Cadence I2S controller for StarFive JH8100 SoC ASoC: starfive: Add drivers of Cadence Multi-Channel I2S Controller
.../bindings/sound/cdns,jh8100-i2s.yaml | 100 +++ MAINTAINERS | 7 + sound/soc/starfive/Kconfig | 18 + sound/soc/starfive/Makefile | 4 + sound/soc/starfive/cdns-jh8100-i2s-pcm.c | 262 +++++++ sound/soc/starfive/cdns-jh8100-i2s.c | 727 ++++++++++++++++++ sound/soc/starfive/cdns-jh8100-i2s.h | 171 ++++ 7 files changed, 1289 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/cdns,jh8100-i2s.yaml create mode 100644 sound/soc/starfive/cdns-jh8100-i2s-pcm.c create mode 100644 sound/soc/starfive/cdns-jh8100-i2s.c create mode 100644 sound/soc/starfive/cdns-jh8100-i2s.h
Add the drivers of Cadence Multi-Channel I2S Controller on the StarFive JH8100 SoC.
The Cadence I2S Controller implements a function of the multi-channel (up to 8-channel) bus. Each stereo channel combines functions of a transmitter and a receiver. Each channel has independent gating, clock and interruption control. It alos support some of these channels are used as playback and others can also be used as record in the same time.
Signed-off-by: Xingyu Wu xingyu.wu@starfivetech.com --- MAINTAINERS | 7 + sound/soc/starfive/Kconfig | 18 + sound/soc/starfive/Makefile | 4 + sound/soc/starfive/cdns-jh8100-i2s-pcm.c | 262 ++++++++ sound/soc/starfive/cdns-jh8100-i2s.c | 727 +++++++++++++++++++++++ sound/soc/starfive/cdns-jh8100-i2s.h | 171 ++++++ 6 files changed, 1189 insertions(+) create mode 100644 sound/soc/starfive/cdns-jh8100-i2s-pcm.c create mode 100644 sound/soc/starfive/cdns-jh8100-i2s.c create mode 100644 sound/soc/starfive/cdns-jh8100-i2s.h
diff --git a/MAINTAINERS b/MAINTAINERS index 9104430e148e..f920297e1594 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20658,6 +20658,13 @@ F: Documentation/devicetree/bindings/power/starfive* F: drivers/pmdomain/starfive/ F: include/dt-bindings/power/starfive,jh7110-pmu.h
+STARFIVE JH8100 CDNS I2S CONTROLLER DRIVER +M: Xingyu Wu xingyu.wu@starfivetech.com +M: Walker Chen walker.chen@starfivetech.com +S: Supported +F: Documentation/devicetree/bindings/sound/cdns,jh8100-i2s.yaml +F: sound/soc/starfive/cdns-jh8100-i2s* + STARFIVE SOC DRIVERS M: Conor Dooley conor@kernel.org S: Maintained diff --git a/sound/soc/starfive/Kconfig b/sound/soc/starfive/Kconfig index 279ac5c1d309..f2ee72e8536d 100644 --- a/sound/soc/starfive/Kconfig +++ b/sound/soc/starfive/Kconfig @@ -22,3 +22,21 @@ config SND_SOC_JH7110_TDM select SND_SOC_GENERIC_DMAENGINE_PCM help Say Y or M if you want to add support for StarFive TDM driver. + +config SND_SOC_JH8100_CADENCE_I2S + tristate "Cadence I2S Controller Device Driver for StarFive JH8100 SoC" + depends on HAVE_CLK && SND_SOC_STARFIVE + select SND_SOC_GENERIC_DMAENGINE_PCM + help + Say Y or M if you want to add support for I2S driver for the + StarFive JH8100 Cadence Multi-Channel I2S Controller device. + + +config SND_SOC_JH8100_CADENCE_I2S_PCM + bool "PCM PIO extension for CDNS I2S driver on the StarFive JH8100 SoC" + depends on SND_SOC_JH8100_CADENCE_I2S + help + Say Y or N if you want to add a custom ALSA extension that registers + a PCM and uses PIO to transfer data. + This functionality is specially suited for I2S devices that don't have + DMA support. diff --git a/sound/soc/starfive/Makefile b/sound/soc/starfive/Makefile index 9e958f70ef51..9f8fd0ad6187 100644 --- a/sound/soc/starfive/Makefile +++ b/sound/soc/starfive/Makefile @@ -1,3 +1,7 @@ # StarFive Platform Support obj-$(CONFIG_SND_SOC_JH7110_PWMDAC) += jh7110_pwmdac.o obj-$(CONFIG_SND_SOC_JH7110_TDM) += jh7110_tdm.o + +obj-$(CONFIG_SND_SOC_JH8100_CADENCE_I2S) += jh8100-i2s.o +jh8100-i2s-y := cdns-jh8100-i2s.o +jh8100-i2s-$(CONFIG_SND_SOC_JH8100_CADENCE_I2S_PCM) += cdns-jh8100-i2s-pcm.o diff --git a/sound/soc/starfive/cdns-jh8100-i2s-pcm.c b/sound/soc/starfive/cdns-jh8100-i2s-pcm.c new file mode 100644 index 000000000000..e0172d109925 --- /dev/null +++ b/sound/soc/starfive/cdns-jh8100-i2s-pcm.c @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence Multi-Channel I2S controller PCM driver + * + * Copyright (c) 2022-2023 StarFive Technology Co., Ltd. + */ + +#include <linux/io.h> +#include <linux/rcupdate.h> +#include <sound/pcm_params.h> +#include "cdns-jh8100-i2s.h" + +#define PERIOD_BYTES_MIN 4096 +#define BUFFER_BYTES_MAX (3 * 2 * 8 * PERIOD_BYTES_MIN) +#define PERIODS_MIN 2 + +static unsigned int cdns_jh8100_i2s_pcm_tx(struct cdns_jh8100_i2s_dev *dev, + struct snd_pcm_runtime *runtime, + unsigned int tx_ptr, bool *period_elapsed, + snd_pcm_format_t format) +{ + unsigned int period_pos = tx_ptr % runtime->period_size; + const u16 (*p16)[2] = (void *)runtime->dma_area; + const u32 (*p32)[2] = (void *)runtime->dma_area; + u32 data[2]; + int i; + + for (i = 0; i < CDNS_JH8100_I2S_FIFO_DEPTH; i++) { + if (format == SNDRV_PCM_FORMAT_S16_LE) { + data[0] = p16[tx_ptr][0]; + data[1] = p16[tx_ptr][1]; + } else if (format == SNDRV_PCM_FORMAT_S32_LE) { + data[0] = p32[tx_ptr][0]; + data[1] = p32[tx_ptr][1]; + } + + iowrite32(data[0], dev->base + CDNS_JH8100_FIFO_MEM); + iowrite32(data[1], dev->base + CDNS_JH8100_FIFO_MEM); + period_pos++; + if (++tx_ptr >= runtime->buffer_size) + tx_ptr = 0; + } + + *period_elapsed = period_pos >= runtime->period_size; + return tx_ptr; +} + +static unsigned int cdns_jh8100_i2s_pcm_rx(struct cdns_jh8100_i2s_dev *dev, + struct snd_pcm_runtime *runtime, + unsigned int rx_ptr, bool *period_elapsed, + snd_pcm_format_t format) +{ + unsigned int period_pos = rx_ptr % runtime->period_size; + u16 (*p16)[2] = (void *)runtime->dma_area; + u32 (*p32)[2] = (void *)runtime->dma_area; + u32 data[2]; + int i; + + for (i = 0; i < CDNS_JH8100_I2S_FIFO_DEPTH; i++) { + data[0] = ioread32(dev->base + CDNS_JH8100_FIFO_MEM); + data[1] = ioread32(dev->base + CDNS_JH8100_FIFO_MEM); + if (format == SNDRV_PCM_FORMAT_S16_LE) { + p16[rx_ptr][0] = data[0]; + p16[rx_ptr][1] = data[1]; + } else if (format == SNDRV_PCM_FORMAT_S32_LE) { + p32[rx_ptr][0] = data[0]; + p32[rx_ptr][1] = data[1]; + } + + period_pos++; + if (++rx_ptr >= runtime->buffer_size) + rx_ptr = 0; + } + + *period_elapsed = period_pos >= runtime->period_size; + return rx_ptr; +} + +static const struct snd_pcm_hardware cdns_jh8100_i2s_pcm_hardware = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME, + .rates = SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_11025 | + SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_22050 | + SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000, + .rate_min = 8000, + .rate_max = 48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = BUFFER_BYTES_MAX, + .period_bytes_min = PERIOD_BYTES_MIN, + .period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN, + .periods_min = PERIODS_MIN, + .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, + .fifo_size = 16, +}; + +static void cdns_jh8100_i2s_pcm_transfer(struct cdns_jh8100_i2s_dev *dev, bool push) +{ + struct snd_pcm_substream *substream; + bool active, period_elapsed; + + rcu_read_lock(); + if (push) + substream = rcu_dereference(dev->tx_substream); + else + substream = rcu_dereference(dev->rx_substream); + + active = substream && snd_pcm_running(substream); + if (active) { + unsigned int ptr; + unsigned int new_ptr; + + if (push) { + ptr = READ_ONCE(dev->tx_ptr); + new_ptr = dev->tx_fn(dev, substream->runtime, ptr, + &period_elapsed, dev->format); + cmpxchg(&dev->tx_ptr, ptr, new_ptr); + } else { + ptr = READ_ONCE(dev->rx_ptr); + new_ptr = dev->rx_fn(dev, substream->runtime, ptr, + &period_elapsed, dev->format); + cmpxchg(&dev->rx_ptr, ptr, new_ptr); + } + + if (period_elapsed) + snd_pcm_period_elapsed(substream); + } + rcu_read_unlock(); +} + +void cdns_jh8100_i2s_pcm_push_tx(struct cdns_jh8100_i2s_dev *dev) +{ + cdns_jh8100_i2s_pcm_transfer(dev, true); +} + +void cdns_jh8100_i2s_pcm_pop_rx(struct cdns_jh8100_i2s_dev *dev) +{ + cdns_jh8100_i2s_pcm_transfer(dev, false); +} + +static int cdns_jh8100_i2s_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct cdns_jh8100_i2s_dev *dev = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0)); + + snd_soc_set_runtime_hwparams(substream, &cdns_jh8100_i2s_pcm_hardware); + snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + runtime->private_data = dev; + + return 0; +} + +static int cdns_jh8100_i2s_pcm_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + synchronize_rcu(); + return 0; +} + +static int cdns_jh8100_i2s_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct cdns_jh8100_i2s_dev *dev = runtime->private_data; + + dev->format = params_format(hw_params); + dev->tx_fn = cdns_jh8100_i2s_pcm_tx; + dev->rx_fn = cdns_jh8100_i2s_pcm_rx; + + return 0; +} + +static int cdns_jh8100_i2s_pcm_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct cdns_jh8100_i2s_dev *dev = runtime->private_data; + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + WRITE_ONCE(dev->tx_ptr, 0); + rcu_assign_pointer(dev->tx_substream, substream); + } else { + WRITE_ONCE(dev->rx_ptr, 0); + rcu_assign_pointer(dev->rx_substream, substream); + } + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + rcu_assign_pointer(dev->tx_substream, NULL); + else + rcu_assign_pointer(dev->rx_substream, NULL); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static snd_pcm_uframes_t cdns_jh8100_i2s_pcm_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct cdns_jh8100_i2s_dev *dev = runtime->private_data; + snd_pcm_uframes_t pos; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + pos = READ_ONCE(dev->tx_ptr); + else + pos = READ_ONCE(dev->rx_ptr); + + return pos < runtime->buffer_size ? pos : 0; +} + +static int cdns_jh8100_i2s_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) +{ + size_t size = cdns_jh8100_i2s_pcm_hardware.buffer_bytes_max; + + snd_pcm_set_managed_buffer_all(rtd->pcm, + SNDRV_DMA_TYPE_CONTINUOUS, + NULL, size, size); + + return 0; +} + +static const struct snd_soc_component_driver cdns_jh8100_i2s_pcm_component = { + .open = cdns_jh8100_i2s_pcm_open, + .close = cdns_jh8100_i2s_pcm_close, + .hw_params = cdns_jh8100_i2s_pcm_hw_params, + .trigger = cdns_jh8100_i2s_pcm_trigger, + .pointer = cdns_jh8100_i2s_pcm_pointer, + .pcm_construct = cdns_jh8100_i2s_pcm_new, +}; + +int cdns_jh8100_i2s_pcm_register(struct platform_device *pdev) +{ + return devm_snd_soc_register_component(&pdev->dev, + &cdns_jh8100_i2s_pcm_component, + NULL, 0); +} diff --git a/sound/soc/starfive/cdns-jh8100-i2s.c b/sound/soc/starfive/cdns-jh8100-i2s.c new file mode 100644 index 000000000000..924f12af9f3a --- /dev/null +++ b/sound/soc/starfive/cdns-jh8100-i2s.c @@ -0,0 +1,727 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence Multi-Channel I2S controller driver on the StarFive JH8100 SoC + * + * Copyright (c) 2023 StarFive Technology Co., Ltd. + */ + +#include <linux/bitfield.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/reset.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include "cdns-jh8100-i2s.h" + +static void cdns_jh8100_i2s_set_fifo_mask(struct cdns_jh8100_i2s_dev *i2s, u32 type) +{ + unsigned int temp = readl(i2s->base + CDNS_JH8100_CID_CTRL); + + temp &= ~CDNS_JH8100_I2S_IT_ALL; + temp |= type; + writel(temp, i2s->base + CDNS_JH8100_CID_CTRL); +} + +static inline void cdns_jh8100_i2s_clear_int(struct cdns_jh8100_i2s_dev *i2s) +{ + writel(0, i2s->base + CDNS_JH8100_I2S_INTR_STAT); +} + +static int cdns_jh8100_i2s_reset_mask(struct cdns_jh8100_i2s_dev *i2s, u32 mask) +{ + unsigned int val = readl(i2s->base + CDNS_JH8100_I2S_CTRL); + + val &= ~mask; + writel(val, i2s->base + CDNS_JH8100_I2S_CTRL); + + /* Wait for the reset bit to done and is set to 1 */ + return readl_poll_timeout_atomic(i2s->base + CDNS_JH8100_I2S_CTRL, val, + (val & mask), 0, + CDNS_JH8100_FIFO_ACK_TIMEOUT_US); +} + +/* Reset for TX and RX control unit */ +static void cdns_jh8100_i2s_reset_txrx_unit(struct cdns_jh8100_i2s_dev *i2s) +{ + unsigned int val = readl(i2s->base + CDNS_JH8100_I2S_CTRL); + + val |= CDNS_JH8100_I2S_CTRL_TXRX_RST; + writel(val, i2s->base + CDNS_JH8100_I2S_CTRL); +} + +static void cdns_jh8100_i2s_set_ms_mode(struct cdns_jh8100_i2s_dev *i2s) +{ + unsigned int val = readl(i2s->base + CDNS_JH8100_I2S_CTRL); + + val &= ~(CDNS_JH8100_I2S_CTRL_T_MS_MASK | CDNS_JH8100_I2S_CTRL_R_MS_MASK); + val |= (FIELD_PREP(CDNS_JH8100_I2S_CTRL_T_MS_MASK, i2s->tx_sync_ms_mode) | + FIELD_PREP(CDNS_JH8100_I2S_CTRL_R_MS_MASK, i2s->rx_sync_ms_mode)); + + writel(val, i2s->base + CDNS_JH8100_I2S_CTRL); +} + +/* The threshold of almost empty & full config */ +static void cdns_jh8100_i2s_set_aempty_afull_th(struct cdns_jh8100_i2s_dev *i2s, + unsigned int aempty, + unsigned int afull) +{ + unsigned int val = aempty | (afull << CDNS_TRFIFO_CTRL_AFULL_THRESHOLD_SHIFT); + + writel(val, i2s->base + CDNS_JH8100_TFIFO_CTRL); + writel(val, i2s->base + CDNS_JH8100_RFIFO_CTRL); +} + +static void cdns_jh8100_i2s_set_channel_strobes(struct cdns_jh8100_i2s_dev *i2s, + u32 ch, bool strobe) +{ + unsigned int val = readl(i2s->base + CDNS_JH8100_CID_CTRL); + + /* Active Low */ + if (strobe) + val &= ~ch; + else + val |= ch; + + writel(val, i2s->base + CDNS_JH8100_CID_CTRL); +} + +/* Enable TX or RX clock */ +static void cdns_jh8100_i2s_enable_clock(struct cdns_jh8100_i2s_dev *i2s, + bool is_rx) +{ + unsigned int val = readl(i2s->base + CDNS_JH8100_CID_CTRL); + unsigned int mask = (is_rx ? CDNS_JH8100_CID_CTRL_STROBE_TX : + CDNS_JH8100_CID_CTRL_STROBE_RX); + + /* Active Low */ + val &= ~mask; + writel(val, i2s->base + CDNS_JH8100_CID_CTRL); +} + +static void cdns_jh8100_i2s_set_transmitter_receiver(struct cdns_jh8100_i2s_dev *i2s, + u32 ch, bool is_transmit) +{ + unsigned int val = readl(i2s->base + CDNS_JH8100_I2S_CTRL); + + /* 1: Transmitter, 0: Receiver */ + if (is_transmit) + val |= (ch << CDNS_JH8100_I2S_CTRL_TR_CFG_0_SHIFT); + else + val &= ~(ch << CDNS_JH8100_I2S_CTRL_TR_CFG_0_SHIFT); + + writel(val, i2s->base + CDNS_JH8100_I2S_CTRL); +} + +static irqreturn_t cdns_jh8100_i2s_irq_handler(int irq, void *data) +{ + struct cdns_jh8100_i2s_dev *i2s = data; + unsigned int val = readl(i2s->base + CDNS_JH8100_I2S_INTR_STAT); + irqreturn_t ret = IRQ_NONE; + + cdns_jh8100_i2s_clear_int(i2s); + + if (val & CDNS_JH8100_I2S_STAT_TX_UNDERRUN) + dev_err(i2s->dev, "TX underrun on channel %ld!\n", + FIELD_GET(CDNS_JH8100_I2S_STAT_UNDERR_CODE, val)); + + if (val & CDNS_JH8100_I2S_STAT_RX_OVERRUN) + dev_err(i2s->dev, "RX overrun on channel %ld!\n", + FIELD_GET(CDNS_JH8100_I2S_STAT_OVERR_CODE, val)); + + /* FIFO is empty when playback start and I2S also need to push the data. */ + if (val & (CDNS_JH8100_I2S_STAT_TFIFO_AEMPTY | CDNS_JH8100_I2S_STAT_TFIFO_EMPTY)) { + cdns_jh8100_i2s_pcm_push_tx(i2s); + ret = IRQ_HANDLED; + } + + if (val & CDNS_JH8100_I2S_STAT_RFIFO_AFULL) { + cdns_jh8100_i2s_pcm_pop_rx(i2s); + ret = IRQ_HANDLED; + } + + return ret; +} + +static void cdns_jh8100_i2s_enable_channel(struct cdns_jh8100_i2s_dev *i2s, + u32 ch, bool enable) +{ + unsigned int val = readl(i2s->base + CDNS_JH8100_I2S_CTRL); + + /* Active High */ + if (enable) + val |= ch; + else + val &= ~ch; + + writel(val, i2s->base + CDNS_JH8100_I2S_CTRL); +} + +/* Bit masking all interrupt requests */ +static void cdns_jh8100_i2s_set_all_irq_mask(struct cdns_jh8100_i2s_dev *i2s, bool mask) +{ + unsigned int val = readl(i2s->base + CDNS_JH8100_CID_CTRL); + + /* Active Low: IRQ are masked */ + if (mask) + val &= ~CDNS_JH8100_CID_CTRL_INTREQ_MASK; + else + val |= CDNS_JH8100_CID_CTRL_INTREQ_MASK; + + writel(val, i2s->base + CDNS_JH8100_CID_CTRL); +} + +static void cdns_jh8100_i2s_enable_channel_int(struct cdns_jh8100_i2s_dev *i2s, + u32 ch, bool enable) +{ + unsigned int val = readl(i2s->base + CDNS_JH8100_CID_CTRL); + + /* Active High */ + if (enable) + val |= (ch << CDNS_JH8100_CID_CTRL_I2S_MASK_0_SHIFT); + else + val &= ~(ch << CDNS_JH8100_CID_CTRL_I2S_MASK_0_SHIFT); + + writel(val, i2s->base + CDNS_JH8100_CID_CTRL); +} + +static void cdns_jh8100_i2s_channel_start(struct cdns_jh8100_i2s_dev *i2s, + u32 ch, bool is_transmit) +{ + cdns_jh8100_i2s_set_transmitter_receiver(i2s, ch, is_transmit); + cdns_jh8100_i2s_enable_channel(i2s, ch, true); + cdns_jh8100_i2s_set_channel_strobes(i2s, ch, true); + if (i2s->irq >= 0) + cdns_jh8100_i2s_enable_channel_int(i2s, ch, true); +} + +static void cdns_jh8100_i2s_channel_stop(struct cdns_jh8100_i2s_dev *i2s, u32 ch) +{ + cdns_jh8100_i2s_enable_channel(i2s, ch, false); + if (i2s->irq >= 0) + cdns_jh8100_i2s_enable_channel_int(i2s, ch, false); +} + +static int cdns_jh8100_i2s_start(struct cdns_jh8100_i2s_dev *i2s, + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + unsigned char max_ch = i2s->max_channels; + unsigned char i2s_ch; + int i; + + /* Each channel is stereo */ + i2s_ch = runtime->channels / 2; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if ((i2s_ch + i2s->rx_using_channels) > max_ch) { + dev_err(i2s->dev, + "Max %d channels: using %d for RX, do not support %d for TX\n", + max_ch, i2s->rx_using_channels, i2s_ch); + return -ENOMEM; + } + + i2s->tx_using_channels = i2s_ch; + /* Enable channels from 0 to 'max_ch' as tx */ + for (i = 0; i < i2s_ch; i++) + cdns_jh8100_i2s_channel_start(i2s, CDNS_JH8100_I2S_CM_0 << i, + CDNS_JH8100_I2S_TC_TRANSMITTER); + + } else { + if ((i2s_ch + i2s->tx_using_channels) > max_ch) { + dev_err(i2s->dev, + "Max %d channels: using %d for TX, do not support %d for RX\n", + max_ch, i2s->tx_using_channels, i2s_ch); + return -ENOMEM; + } + + i2s->rx_using_channels = i2s_ch; + /* Enable channels from 'max_ch' to 0 as rx */ + for (i = (max_ch - 1); i > (max_ch - i2s_ch - 1); i--) { + if (i < 0) + return -EINVAL; + + cdns_jh8100_i2s_channel_start(i2s, CDNS_JH8100_I2S_CM_0 << i, + CDNS_JH8100_I2S_TC_RECEIVER); + } + } + cdns_jh8100_i2s_enable_clock(i2s, substream->stream); + + if (i2s->irq >= 0) + cdns_jh8100_i2s_set_all_irq_mask(i2s, false); + + cdns_jh8100_i2s_clear_int(i2s); + + return 0; +} + +static int cdns_jh8100_i2s_stop(struct cdns_jh8100_i2s_dev *i2s, + struct snd_pcm_substream *substream) +{ + unsigned char i2s_ch; + int i; + + cdns_jh8100_i2s_clear_int(i2s); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + i2s_ch = i2s->tx_using_channels; + for (i = 0; i < i2s_ch; i++) + cdns_jh8100_i2s_channel_stop(i2s, (CDNS_JH8100_I2S_CM_0 << i)); + + i2s->tx_using_channels = 0; + } else { + unsigned char max_ch = i2s->max_channels; + + i2s_ch = i2s->rx_using_channels; + for (i = (max_ch - 1); i > (max_ch - i2s_ch - 1); i--) { + if (i < 0) + return -EINVAL; + + cdns_jh8100_i2s_channel_stop(i2s, (CDNS_JH8100_I2S_CM_0 << i)); + } + + i2s->rx_using_channels = 0; + } + + if (i2s->irq >= 0 && !i2s->tx_using_channels && !i2s->rx_using_channels) + cdns_jh8100_i2s_set_all_irq_mask(i2s, true); + + return 0; +} + +static int cdns_jh8100_i2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct cdns_jh8100_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai_link *dai_link = rtd->dai_link; + + if (i2s->irq < 0) + dai_link->trigger_stop = SND_SOC_TRIGGER_ORDER_LDC; + + return 0; +} + +static void cdns_jh8100_i2s_config(struct cdns_jh8100_i2s_dev *i2s, int stream) +{ + unsigned int val = readl(i2s->base + CDNS_JH8100_I2S_SRR); + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + val &= ~(CDNS_JH8100_I2S_SRR_TRATE_MASK | CDNS_JH8100_I2S_SRR_TRESOLUTION_MASK); + val |= (FIELD_PREP(CDNS_JH8100_I2S_SRR_TRATE_MASK, i2s->sample_rate_param) | + FIELD_PREP(CDNS_JH8100_I2S_SRR_TRESOLUTION_MASK, (i2s->resolution - 1))); + } else { + val &= ~(CDNS_JH8100_I2S_SRR_RRATE_MASK | CDNS_JH8100_I2S_SRR_RRESOLUTION_MASK); + val |= (FIELD_PREP(CDNS_JH8100_I2S_SRR_RRATE_MASK, i2s->sample_rate_param) | + FIELD_PREP(CDNS_JH8100_I2S_SRR_RRESOLUTION_MASK, (i2s->resolution - 1))); + } + + writel(val, i2s->base + CDNS_JH8100_I2S_SRR); +} + +static int cdns_jh8100_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct cdns_jh8100_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai); + unsigned int sample_rate = params_rate(params); + unsigned int channels = params_channels(params); + unsigned int fclk_hz = clk_get_rate(i2s->clks[2].clk); /* mclk_inner */ + unsigned int bclk_rate; + int ret; + struct snd_dmaengine_dai_dma_data *dma_data; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + dma_data = &i2s->tx_dma_data; + else + dma_data = &i2s->rx_dma_data; + + switch (sample_rate) { + case 8000: + bclk_rate = 512000; + break; + case 11025: + bclk_rate = 705600; + break; + case 16000: + bclk_rate = 1024000; + break; + case 22050: + bclk_rate = 1411200; + break; + case 32000: + bclk_rate = 2048000; + break; + case 44100: + bclk_rate = 2822400; + break; + case 48000: + bclk_rate = 3072000; + break; + default: + dev_err(dai->dev, "%d rate not supported\n", sample_rate); + return -EINVAL; + } + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + dma_data->addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + break; + case SNDRV_PCM_FORMAT_S32_LE: + dma_data->addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + break; + default: + dev_err(i2s->dev, "unsupported PCM fmt\n"); + return -EINVAL; + } + + ret = clk_set_rate(i2s->clks[0].clk, bclk_rate); /* bclk */ + if (ret < 0) { + dev_err(i2s->dev, "Can't set i2s bclk: %d\n", ret); + return ret; + } + + i2s->resolution = params_width(params); + i2s->sample_rate_param = fclk_hz / (sample_rate * channels * 32); + cdns_jh8100_i2s_config(i2s, substream->stream); + + if (i2s->irq < 0) + snd_soc_dai_set_dma_data(dai, substream, dma_data); + + return 0; +} + +static int cdns_jh8100_i2s_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct cdns_jh8100_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai); + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ret = cdns_jh8100_i2s_start(i2s, substream); + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + ret = cdns_jh8100_i2s_stop(i2s, substream); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int cdns_jh8100_i2s_set_fmt(struct snd_soc_dai *cpu_dai, + unsigned int fmt) +{ + struct cdns_jh8100_i2s_dev *i2s = snd_soc_dai_get_drvdata(cpu_dai); + int ret = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + i2s->tx_sync_ms_mode = CDNS_JH8100_I2S_MASTER_MODE; + i2s->rx_sync_ms_mode = CDNS_JH8100_I2S_MASTER_MODE; + cdns_jh8100_i2s_set_ms_mode(i2s); + break; + case SND_SOC_DAIFMT_CBS_CFS: + i2s->tx_sync_ms_mode = CDNS_JH8100_I2S_SLAVE_MODE; + i2s->rx_sync_ms_mode = CDNS_JH8100_I2S_SLAVE_MODE; + cdns_jh8100_i2s_set_ms_mode(i2s); + break; + case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBS_CFM: + ret = -EINVAL; + break; + default: + dev_dbg(i2s->dev, "Invalid master/slave format\n"); + ret = -EINVAL; + break; + } + return ret; +} + +static int cdns_jh8100_i2s_dai_probe(struct snd_soc_dai *dai) +{ + struct cdns_jh8100_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai); + struct snd_dmaengine_dai_dma_data *tx = &i2s->tx_dma_data; + struct snd_dmaengine_dai_dma_data *rx = &i2s->rx_dma_data; + + if (i2s->irq >= 0) + return 0; + + /* Buswidth will be set by framework */ + tx->addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED; + tx->addr = i2s->phybase + CDNS_JH8100_FIFO_MEM; + tx->maxburst = 16; + tx->fifo_size = 16; + + rx->addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED; + rx->addr = i2s->phybase + CDNS_JH8100_FIFO_MEM; + rx->maxburst = 16; + rx->fifo_size = 16; + + snd_soc_dai_init_dma_data(dai, tx, rx); + + return 0; +} + +static const struct snd_soc_component_driver cdns_jh8100_i2s_component = { + .name = "cdns-jh8100-i2s", +}; + +static const struct snd_soc_dai_ops cdns_jh8100_i2s_dai_ops = { + .probe = cdns_jh8100_i2s_dai_probe, + .startup = cdns_jh8100_i2s_startup, + .hw_params = cdns_jh8100_i2s_hw_params, + .trigger = cdns_jh8100_i2s_trigger, + .set_fmt = cdns_jh8100_i2s_set_fmt, +}; + +static struct snd_soc_dai_driver cdns_jh8100_i2s_dai = { + .name = "cdns-jh8100-i2s", + .id = 0, + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &cdns_jh8100_i2s_dai_ops, + .symmetric_rate = 1, +}; + +static int cdns_jh8100_i2s_runtime_suspend(struct device *dev) +{ + struct cdns_jh8100_i2s_dev *i2s = dev_get_drvdata(dev); + + clk_disable_unprepare(i2s->clks[1].clk); /* ICG clock */ + return 0; +} + +static int cdns_jh8100_i2s_runtime_resume(struct device *dev) +{ + struct cdns_jh8100_i2s_dev *i2s = dev_get_drvdata(dev); + + return clk_prepare_enable(i2s->clks[1].clk); /* ICG clock */ +} + +static int cdns_jh8100_i2s_crg_init(struct cdns_jh8100_i2s_dev *i2s) +{ + struct reset_control *reset = devm_reset_control_get_exclusive(i2s->dev, NULL); + int ret; + + if (IS_ERR(reset)) + return dev_err_probe(i2s->dev, PTR_ERR(reset), "failed to get i2s resets\n"); + + i2s->clks[0].id = "bclk"; + i2s->clks[1].id = "icg"; + i2s->clks[2].id = "mclk_inner"; + + ret = devm_clk_bulk_get(i2s->dev, ARRAY_SIZE(i2s->clks), i2s->clks); + if (ret) + return dev_err_probe(i2s->dev, ret, "failed to get i2s clocks\n"); + + ret = clk_prepare_enable(i2s->clks[1].clk); /* ICG clock */ + if (ret) + return dev_err_probe(i2s->dev, ret, "failed to enable icg clock\n"); + + ret = reset_control_deassert(reset); + if (ret) + goto rst_err; + + return 0; + +rst_err: + clk_disable_unprepare(i2s->clks[1].clk); + return ret; +} + +static int cdns_jh8100_i2s_init(struct cdns_jh8100_i2s_dev *i2s) +{ + int ret = cdns_jh8100_i2s_crg_init(i2s); + unsigned int tmp; + + if (ret) + return ret; + + /* Software reset i2s controller */ + ret = cdns_jh8100_i2s_reset_mask(i2s, CDNS_JH8100_I2S_CTRL_SFR_RST_MASK); + if (ret) { + dev_err(i2s->dev, "Failed to reset I2S.\n"); + return ret; + } + + /* reset TX FIFO */ + ret = cdns_jh8100_i2s_reset_mask(i2s, CDNS_JH8100_I2S_CTRL_TFIFO_RST_MASK); + if (ret) { + dev_err(i2s->dev, "Failed to reset tx fifo.\n"); + return ret; + } + + /* reset RX FIFO */ + ret = cdns_jh8100_i2s_reset_mask(i2s, CDNS_JH8100_I2S_CTRL_RFIFO_RST_MASK); + if (ret) { + dev_err(i2s->dev, "Failed to reset rx fifo.\n"); + return ret; + } + + /* default master mode to init */ + i2s->tx_sync_ms_mode = CDNS_JH8100_I2S_MASTER_MODE; + i2s->rx_sync_ms_mode = CDNS_JH8100_I2S_MASTER_MODE; + cdns_jh8100_i2s_set_ms_mode(i2s); + + /* Should do it after setting Master/Slave mode */ + cdns_jh8100_i2s_reset_txrx_unit(i2s); + cdns_jh8100_i2s_clear_int(i2s); + + cdns_jh8100_i2s_set_aempty_afull_th(i2s, (CDNS_JH8100_I2S_FIFO_DEPTH / 4), + (CDNS_JH8100_I2S_FIFO_DEPTH / 4 * 3)); + cdns_jh8100_i2s_set_fifo_mask(i2s, CDNS_JH8100_I2S_IT_TFIFO_AEMPTY | + CDNS_JH8100_I2S_IT_RFIFO_AFULL); + + i2s->rx_using_channels = 0; + i2s->tx_using_channels = 0; + + /* cdns,i2s-max-channels is optional property and default 8 */ + ret = device_property_read_u32(i2s->dev, "cdns,i2s-max-channels", &tmp); + if (ret) { + i2s->max_channels = CDNS_JH8100_I2S_CHANNEL_MAX; + } else { + if (tmp > CDNS_JH8100_I2S_CHANNEL_MAX) { + dev_err(i2s->dev, + "The number %d of max channels from DTS is out of range!\n", + tmp); + return -EINVAL; + } + + i2s->max_channels = tmp; + } + + return 0; +} + +static int cdns_jh8100_i2s_probe(struct platform_device *pdev) +{ + struct cdns_jh8100_i2s_dev *i2s; + struct resource *res; + int ret; + + i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); + if (!i2s) { + ret = -ENOMEM; + goto err; + } + platform_set_drvdata(pdev, i2s); + + i2s->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(i2s->base)) { + ret = PTR_ERR(i2s->base); + goto err; + } + + i2s->dev = &pdev->dev; + i2s->phybase = res->start; + + ret = cdns_jh8100_i2s_init(i2s); + if (ret) + goto err; + + i2s->irq = platform_get_irq(pdev, 0); + if (i2s->irq >= 0) { + ret = devm_request_irq(&pdev->dev, i2s->irq, cdns_jh8100_i2s_irq_handler, + 0, pdev->name, i2s); + if (ret < 0) { + dev_err(&pdev->dev, "request_irq failed\n"); + goto err; + } + } + + ret = devm_snd_soc_register_component(&pdev->dev, + &cdns_jh8100_i2s_component, + &cdns_jh8100_i2s_dai, 1); + if (ret < 0) { + dev_err(&pdev->dev, "couldn't register component\n"); + goto err; + } + + if (i2s->irq >= 0) + ret = cdns_jh8100_i2s_pcm_register(pdev); + else + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + + if (ret) { + dev_err(&pdev->dev, "could not register pcm: %d\n", ret); + goto err; + } + + pm_runtime_enable(&pdev->dev); + if (pm_runtime_enabled(&pdev->dev)) + cdns_jh8100_i2s_runtime_suspend(&pdev->dev); + + dev_info(&pdev->dev, "I2S supports %d stereo channels with %s.\n", + i2s->max_channels, ((i2s->irq < 0) ? "dma" : "interrupt")); + + return 0; + +err: + return ret; +} + +static int cdns_jh8100_i2s_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + cdns_jh8100_i2s_runtime_suspend(&pdev->dev); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id cdns_jh8100_i2s_of_match[] = { + { .compatible = "starfive,jh8100-i2s", }, + {}, +}; +MODULE_DEVICE_TABLE(of, cdns_jh8100_i2s_of_match); +#endif + +static const struct dev_pm_ops cdns_jh8100_i2s_pm_ops = { + SET_RUNTIME_PM_OPS(cdns_jh8100_i2s_runtime_suspend, + cdns_jh8100_i2s_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static struct platform_driver cdns_jh8100_i2s_driver = { + .probe = cdns_jh8100_i2s_probe, + .remove = cdns_jh8100_i2s_remove, + .driver = { + .name = "cdns-jh8100-i2s", + .of_match_table = of_match_ptr(cdns_jh8100_i2s_of_match), + .pm = &cdns_jh8100_i2s_pm_ops, + }, +}; + +module_platform_driver(cdns_jh8100_i2s_driver); + +MODULE_AUTHOR("Xingyu Wu xingyu.wu@starfivetech.com"); +MODULE_AUTHOR("Walker Chen walker.chen@starfivetech.com"); +MODULE_DESCRIPTION("Cadence Multi-Channel I2S controller driver for StarFive JH8100 SoC"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/starfive/cdns-jh8100-i2s.h b/sound/soc/starfive/cdns-jh8100-i2s.h new file mode 100644 index 000000000000..d4e0350de7bf --- /dev/null +++ b/sound/soc/starfive/cdns-jh8100-i2s.h @@ -0,0 +1,171 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Cadence Multi-Channel I2S Controller driver header file for StarFive JH8100 SoC + * + * Copyright (c) 2023 StarFive Technology Co., Ltd. + * Author: Walker Chen walker.chen@starfivetech.com + * Xingyu Wu xingyu.wu@starfivetech.com + */ + +#ifndef __CDNS_JH8100_I2S_MC_H +#define __CDNS_JH8100_I2S_MC_H + +#include <linux/clk.h> +#include <sound/dmaengine_pcm.h> +#include <sound/pcm.h> + +#define CDNS_JH8100_I2S_FIFO_DEPTH 128 +#define CDNS_JH8100_FIFO_ACK_TIMEOUT_US 200 +#define CDNS_JH8100_I2S_CHANNEL_MAX 8 + +/* I2S REGS */ +#define CDNS_JH8100_I2S_CTRL 0x00 +#define CDNS_JH8100_I2S_INTR_STAT 0x04 +#define CDNS_JH8100_I2S_SRR 0x08 +#define CDNS_JH8100_CID_CTRL 0x0c +#define CDNS_JH8100_TFIFO_CTRL 0x18 +#define CDNS_JH8100_RFIFO_CTRL 0x1c +#define CDNS_JH8100_FIFO_MEM 0x3c + +/* + * I2S_CTRL: I2S transceiver control register + */ +#define CDNS_JH8100_I2S_CTRL_TR_CFG_0_SHIFT 8 +#define CDNS_JH8100_I2S_CTRL_SFR_RST_MASK BIT(20) +#define CDNS_JH8100_I2S_CTRL_T_MS_MASK BIT(21) +#define CDNS_JH8100_I2S_CTRL_R_MS_MASK BIT(22) +#define CDNS_JH8100_I2S_CTRL_TFIFO_RST_MASK BIT(23) +#define CDNS_JH8100_I2S_CTRL_RFIFO_RST_MASK BIT(24) +#define CDNS_JH8100_I2S_CTRL_TXRX_RST GENMASK(26, 25) + +/* + * I2S_INTR_STAT: I2S Interrupt status register + */ +#define CDNS_JH8100_I2S_STAT_TX_UNDERRUN BIT(0) +#define CDNS_JH8100_I2S_STAT_UNDERR_CODE GENMASK(3, 1) +#define CDNS_JH8100_I2S_STAT_RX_OVERRUN BIT(4) +#define CDNS_JH8100_I2S_STAT_OVERR_CODE GENMASK(7, 5) +#define CDNS_JH8100_I2S_STAT_TFIFO_EMPTY BIT(8) +#define CDNS_JH8100_I2S_STAT_TFIFO_AEMPTY BIT(9) +#define CDNS_JH8100_I2S_STAT_RFIFO_AFULL BIT(15) + +/* + * CID_CTRL: Clock strobes and interrupt masks control register + */ +#define CDNS_JH8100_CID_CTRL_STROBE_TX BIT(8) +#define CDNS_JH8100_CID_CTRL_STROBE_RX BIT(9) +#define CDNS_JH8100_CID_CTRL_INTREQ_MASK BIT(15) +#define CDNS_JH8100_CID_CTRL_I2S_MASK_0_SHIFT 16 + +/* + * I2S_SRR: Sample rate and resolution control register + */ +#define CDNS_JH8100_I2S_SRR_TRATE_MASK GENMASK(9, 0) +#define CDNS_JH8100_I2S_SRR_RRATE_MASK GENMASK(25, 16) +#define CDNS_JH8100_I2S_SRR_TRESOLUTION_MASK GENMASK(15, 11) +#define CDNS_JH8100_I2S_SRR_RRESOLUTION_MASK GENMASK(31, 27) + +/* + * TFIFO_CTRL & RFIFO_CTRL: The FIFO thresholds control register + * AEMPTY: [15:0] + * AFULL: [31:16] + */ +#define CDNS_TRFIFO_CTRL_AFULL_THRESHOLD_SHIFT 16 + +enum cdns_jh8100_i2s_channel_mask { + CDNS_JH8100_I2S_CM_0 = BIT(0), + CDNS_JH8100_I2S_CM_1 = BIT(1), + CDNS_JH8100_I2S_CM_2 = BIT(2), + CDNS_JH8100_I2S_CM_3 = BIT(3), + CDNS_JH8100_I2S_CM_4 = BIT(4), + CDNS_JH8100_I2S_CM_5 = BIT(5), + CDNS_JH8100_I2S_CM_6 = BIT(6), + CDNS_JH8100_I2S_CM_7 = BIT(7), + CDNS_JH8100_I2S_CM_ALL = GENMASK(7, 0), +}; + +enum i2s_int_type { + CDNS_JH8100_I2S_IT_TFIFO_EMPTY = BIT(24), + CDNS_JH8100_I2S_IT_TFIFO_AEMPTY = BIT(25), + CDNS_JH8100_I2S_IT_TFIFO_FULL = BIT(26), + CDNS_JH8100_I2S_IT_TFIFO_AFULL = BIT(27), + CDNS_JH8100_I2S_IT_RFIFO_EMPTY = BIT(28), + CDNS_JH8100_I2S_IT_RFIFO_AEMPTY = BIT(29), + CDNS_JH8100_I2S_IT_RFIFO_FULL = BIT(30), + CDNS_JH8100_I2S_IT_RFIFO_AFULL = BIT(31), + CDNS_JH8100_I2S_IT_ALL = GENMASK(31, 24), +}; + +enum cdns_jh8100_i2s_master_slave_mode { + CDNS_JH8100_I2S_SLAVE_MODE = 0, + CDNS_JH8100_I2S_MASTER_MODE = 1, +}; + +enum cdns_jh8100_i2s_transmit_config { + CDNS_JH8100_I2S_TC_RECEIVER = 0, + CDNS_JH8100_I2S_TC_TRANSMITTER = 1, +}; + +struct cdns_jh8100_i2s_dev { + struct device *dev; + struct clk_bulk_data clks[3]; + void __iomem *base; + resource_size_t phybase; /* the physical memory */ + int irq; + unsigned int sample_rate_param; + unsigned char resolution; + unsigned char max_channels /* up to CDNS_JH8100_I2S_CHANNEL_MAX */; + unsigned char tx_using_channels; + unsigned char rx_using_channels; + + /* + * Master (value '1') or slave (value '0') configuration bit + * for unit synchronizing all transmitters(receivers) with I2S bus + */ + bool tx_sync_ms_mode; + bool rx_sync_ms_mode; + +#if IS_ENABLED(CONFIG_SND_SOC_JH8100_CADENCE_I2S_PCM) + /* current playback substream. NULL if not playing. + * + * Access to that field is synchronized between the interrupt handler + * and userspace through RCU. + * + * Interrupt handler (threaded part) does PIO on substream data in RCU + * read-side critical section. Trigger callback sets and clears the + * pointer when the playback is started and stopped with + * rcu_assign_pointer. When userspace is about to free the playback + * stream in the pcm_close callback it synchronizes with the interrupt + * handler by means of synchronize_rcu call. + */ + struct snd_pcm_substream __rcu *tx_substream; + struct snd_pcm_substream __rcu *rx_substream; + unsigned int (*tx_fn)(struct cdns_jh8100_i2s_dev *i2s, + struct snd_pcm_runtime *runtime, unsigned int tx_ptr, + bool *period_elapsed, snd_pcm_format_t format); + unsigned int (*rx_fn)(struct cdns_jh8100_i2s_dev *dev, + struct snd_pcm_runtime *runtime, unsigned int rx_ptr, + bool *period_elapsed, snd_pcm_format_t format); + snd_pcm_format_t format; + unsigned int tx_ptr; /* next frame index in the sample buffer */ + unsigned int rx_ptr; +#endif + + struct snd_dmaengine_dai_dma_data tx_dma_data; + struct snd_dmaengine_dai_dma_data rx_dma_data; +}; + +#if IS_ENABLED(CONFIG_SND_SOC_JH8100_CADENCE_I2S_PCM) +void cdns_jh8100_i2s_pcm_push_tx(struct cdns_jh8100_i2s_dev *dev); +void cdns_jh8100_i2s_pcm_pop_rx(struct cdns_jh8100_i2s_dev *dev); +int cdns_jh8100_i2s_pcm_register(struct platform_device *pdev); +#else +void cdns_jh8100_i2s_pcm_push_tx(struct cdns_jh8100_i2s_dev *dev) { } +void cdns_jh8100_i2s_pcm_pop_rx(struct cdns_jh8100_i2s_dev *dev) { } +int cdns_jh8100_i2s_pcm_register(struct platform_device *pdev) +{ + return -EINVAL; +} +#endif + +#endif /* __CDNS_JH8100_I2S_MC_H */
On Thu, Dec 21, 2023 at 11:32:23AM +0800, Xingyu Wu wrote:
sound/soc/starfive/cdns-jh8100-i2s-pcm.c | 262 ++++++++ sound/soc/starfive/cdns-jh8100-i2s.c | 727 +++++++++++++++++++++++ sound/soc/starfive/cdns-jh8100-i2s.h | 171 ++++++
If this is a Cadence IP why is the entire driver SoC specific?
On 2023/12/21 20:55, Mark Brown wrote:
On Thu, Dec 21, 2023 at 11:32:23AM +0800, Xingyu Wu wrote:
sound/soc/starfive/cdns-jh8100-i2s-pcm.c | 262 ++++++++ sound/soc/starfive/cdns-jh8100-i2s.c | 727 +++++++++++++++++++++++ sound/soc/starfive/cdns-jh8100-i2s.h | 171 ++++++
If this is a Cadence IP why is the entire driver SoC specific?
This a new driver about this Cadence I2S controller. Should I create a new folder and file like this:
sound/soc/cdns/cdns-i2s*
and I use different compatible to support other SoC like JH8100?
Best regards, Xingyu Wu
On Fri, Dec 22, 2023 at 05:11:17PM +0800, Xingyu Wu wrote:
On 2023/12/21 20:55, Mark Brown wrote:
On Thu, Dec 21, 2023 at 11:32:23AM +0800, Xingyu Wu wrote:
sound/soc/starfive/cdns-jh8100-i2s-pcm.c | 262 ++++++++ sound/soc/starfive/cdns-jh8100-i2s.c | 727 +++++++++++++++++++++++ sound/soc/starfive/cdns-jh8100-i2s.h | 171 ++++++
If this is a Cadence IP why is the entire driver SoC specific?
This a new driver about this Cadence I2S controller. Should I create a new folder and file like this:
sound/soc/cdns/cdns-i2s*
and I use different compatible to support other SoC like JH8100?
Yes, that seems more what I'd expect - with a fallback compatible for things that don't need any special quirks.
Hi Xingyu,
kernel test robot noticed the following build warnings:
[auto build test WARNING on broonie-sound/for-next] [also build test WARNING on robh/for-next linus/master v6.7-rc6 next-20231222] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Xingyu-Wu/dt-bindings-ASoC-Ad... base: https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next patch link: https://lore.kernel.org/r/20231221033223.73201-3-xingyu.wu%40starfivetech.co... patch subject: [PATCH v1 2/2] ASoC: starfive: Add drivers of Cadence Multi-Channel I2S Controller config: parisc-allyesconfig (https://download.01.org/0day-ci/archive/20231223/202312230525.gch9VlZT-lkp@i...) compiler: hppa-linux-gcc (GCC) 13.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231223/202312230525.gch9VlZT-lkp@i...)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot lkp@intel.com | Closes: https://lore.kernel.org/oe-kbuild-all/202312230525.gch9VlZT-lkp@intel.com/
All warnings (new ones prefixed by >>):
sound/soc/starfive/cdns-jh8100-i2s.c:519:12: warning: 'cdns_jh8100_i2s_runtime_resume' defined but not used [-Wunused-function]
519 | static int cdns_jh8100_i2s_runtime_resume(struct device *dev) | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
vim +/cdns_jh8100_i2s_runtime_resume +519 sound/soc/starfive/cdns-jh8100-i2s.c
518
519 static int cdns_jh8100_i2s_runtime_resume(struct device *dev)
520 { 521 struct cdns_jh8100_i2s_dev *i2s = dev_get_drvdata(dev); 522 523 return clk_prepare_enable(i2s->clks[1].clk); /* ICG clock */ 524 } 525
Hi Xingyu,
kernel test robot noticed the following build warnings:
[auto build test WARNING on broonie-sound/for-next] [also build test WARNING on robh/for-next linus/master v6.7-rc6 next-20231222] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Xingyu-Wu/dt-bindings-ASoC-Ad... base: https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next patch link: https://lore.kernel.org/r/20231221033223.73201-3-xingyu.wu%40starfivetech.co... patch subject: [PATCH v1 2/2] ASoC: starfive: Add drivers of Cadence Multi-Channel I2S Controller config: sparc64-randconfig-r071-20231223 (https://download.01.org/0day-ci/archive/20231223/202312231911.DFYqQ9Gl-lkp@i...) compiler: sparc64-linux-gcc (GCC) 13.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231223/202312231911.DFYqQ9Gl-lkp@i...)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot lkp@intel.com | Closes: https://lore.kernel.org/oe-kbuild-all/202312231911.DFYqQ9Gl-lkp@intel.com/
All warnings (new ones prefixed by >>):
In file included from sound/soc/starfive/cdns-jh8100-i2s.c:18:
sound/soc/starfive/cdns-jh8100-i2s.h:163:6: warning: no previous prototype for 'cdns_jh8100_i2s_pcm_push_tx' [-Wmissing-prototypes]
163 | void cdns_jh8100_i2s_pcm_push_tx(struct cdns_jh8100_i2s_dev *dev) { } | ^~~~~~~~~~~~~~~~~~~~~~~~~~~
sound/soc/starfive/cdns-jh8100-i2s.h:164:6: warning: no previous prototype for 'cdns_jh8100_i2s_pcm_pop_rx' [-Wmissing-prototypes]
164 | void cdns_jh8100_i2s_pcm_pop_rx(struct cdns_jh8100_i2s_dev *dev) { } | ^~~~~~~~~~~~~~~~~~~~~~~~~~
sound/soc/starfive/cdns-jh8100-i2s.h:165:5: warning: no previous prototype for 'cdns_jh8100_i2s_pcm_register' [-Wmissing-prototypes]
165 | int cdns_jh8100_i2s_pcm_register(struct platform_device *pdev) | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
vim +/cdns_jh8100_i2s_pcm_push_tx +163 sound/soc/starfive/cdns-jh8100-i2s.h
157 158 #if IS_ENABLED(CONFIG_SND_SOC_JH8100_CADENCE_I2S_PCM) 159 void cdns_jh8100_i2s_pcm_push_tx(struct cdns_jh8100_i2s_dev *dev); 160 void cdns_jh8100_i2s_pcm_pop_rx(struct cdns_jh8100_i2s_dev *dev); 161 int cdns_jh8100_i2s_pcm_register(struct platform_device *pdev); 162 #else
163 void cdns_jh8100_i2s_pcm_push_tx(struct cdns_jh8100_i2s_dev *dev) { } 164 void cdns_jh8100_i2s_pcm_pop_rx(struct cdns_jh8100_i2s_dev *dev) { } 165 int cdns_jh8100_i2s_pcm_register(struct platform_device *pdev)
166 { 167 return -EINVAL; 168 } 169 #endif 170
Add bindings for the Multi-Channel I2S controller of Cadence on the StarFive JH8100 SoC.
Signed-off-by: Xingyu Wu xingyu.wu@starfivetech.com --- .../bindings/sound/cdns,jh8100-i2s.yaml | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/cdns,jh8100-i2s.yaml
diff --git a/Documentation/devicetree/bindings/sound/cdns,jh8100-i2s.yaml b/Documentation/devicetree/bindings/sound/cdns,jh8100-i2s.yaml new file mode 100644 index 000000000000..5d95d9ab3e45 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cdns,jh8100-i2s.yaml @@ -0,0 +1,100 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/cdns,jh8100-i2s.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Cadence multi-channel I2S controller for StarFive JH8100 SoC + +description: | + The Cadence I2S Controller implements a function of the multi-channel + (up to 8-channel) bus. It combines functions of a transmitter and a receiver. + It is used in the StarFive JH8100 SoC. + +maintainers: + - Xingyu Wu xingyu.wu@starfivetech.com + - Walker Chen walker.chen@starfivetech.com + +properties: + compatible: + const: starfive,jh8100-i2s + + reg: + maxItems: 1 + + interrupts: + description: | + The interrupt line number for the I2S controller. Add this + parameter if the I2S controller that you are using does not + support DMA. + maxItems: 1 + + clocks: + items: + - description: Bit clock + - description: Main ICG clock + - description: Inner master clock + + clock-names: + items: + - const: bclk + - const: icg + - const: mclk_inner + + resets: + maxItems: 1 + + dmas: + items: + - description: TX DMA Channel + - description: RX DMA Channel + minItems: 1 + + dma-names: + items: + - const: tx + - const: rx + minItems: 1 + + cdns,i2s-max-channels: + description: | + Number of I2S max stereo channels supported by the hardware. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 1 + maximum: 8 + + "#sound-dai-cells": + const: 0 + +required: + - compatible + - reg + - clocks + - clock-names + - resets + +oneOf: + - required: + - dmas + - dma-names + - required: + - interrupts + +unevaluatedProperties: false + +examples: + - | + i2s@122b0000 { + compatible = "starfive,jh8100-i2s"; + reg = <0x122b0000 0x1000>; + clocks = <&syscrg_ne 133>, + <&syscrg_ne 170>, + <&syscrg 50>; + clock-names = "bclk", "icg", + "mclk_inner"; + resets = <&syscrg_ne 43>; + dmas = <&dma 7>, <&dma 6>; + dma-names = "tx", "rx"; + cdns,i2s-max-channels = <2>; + #sound-dai-cells = <0>; + };
Xingyu, Mark,
On Thu, Dec 21, 2023 at 11:32:22AM +0800, Xingyu Wu wrote:
Add bindings for the Multi-Channel I2S controller of Cadence on the StarFive JH8100 SoC.
Signed-off-by: Xingyu Wu xingyu.wu@starfivetech.com
.../bindings/sound/cdns,jh8100-i2s.yaml | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/cdns,jh8100-i2s.yaml
diff --git a/Documentation/devicetree/bindings/sound/cdns,jh8100-i2s.yaml b/Documentation/devicetree/bindings/sound/cdns,jh8100-i2s.yaml new file mode 100644 index 000000000000..5d95d9ab3e45 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cdns,jh8100-i2s.yaml @@ -0,0 +1,100 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/cdns,jh8100-i2s.yaml#
Filename matching the compatible please.
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+title: Cadence multi-channel I2S controller for StarFive JH8100 SoC
+description: |
You only need the | if there is formatting to preserve.
- The Cadence I2S Controller implements a function of the multi-channel
- (up to 8-channel) bus. It combines functions of a transmitter and a receiver.
- It is used in the StarFive JH8100 SoC.
+maintainers:
- Xingyu Wu xingyu.wu@starfivetech.com
- Walker Chen walker.chen@starfivetech.com
+properties:
- compatible:
- const: starfive,jh8100-i2s
- reg:
- maxItems: 1
- interrupts:
- description: |
The interrupt line number for the I2S controller. Add this
parameter if the I2S controller that you are using does not
support DMA.
You've got one i2s controller here, you should know if it supports DMA or not.
- maxItems: 1
- clocks:
- items:
- description: Bit clock
- description: Main ICG clock
- description: Inner master clock
- clock-names:
- items:
- const: bclk
- const: icg
- const: mclk_inner
- resets:
- maxItems: 1
- dmas:
- items:
- description: TX DMA Channel
- description: RX DMA Channel
- minItems: 1
- dma-names:
- items:
- const: tx
- const: rx
- minItems: 1
- cdns,i2s-max-channels:
- description: |
Number of I2S max stereo channels supported by the hardware.
- $ref: /schemas/types.yaml#/definitions/uint32
- minimum: 1
- maximum: 8
Mark, is there no common property for this kind of thing? That said, there's one device here so the number is known at present. Another note, this property is not required, so it should have a default.
It's kinda hard to know with this binding - it is touted as being for a particular Cadence IP, and some aspects are pretty generic, but at the same time there's only one device here so it's hard to tell what is variable between implementations and what is not. Are there no other implementations of this controller? Unless it is brand new, I find that hard to believe.
Cheers, Conor.
- "#sound-dai-cells":
- const: 0
+required:
- compatible
- reg
- clocks
- clock-names
- resets
+oneOf:
- required:
- dmas
- dma-names
- required:
- interrupts
+unevaluatedProperties: false
+examples:
- |
- i2s@122b0000 {
compatible = "starfive,jh8100-i2s";
reg = <0x122b0000 0x1000>;
clocks = <&syscrg_ne 133>,
<&syscrg_ne 170>,
<&syscrg 50>;
clock-names = "bclk", "icg",
"mclk_inner";
resets = <&syscrg_ne 43>;
dmas = <&dma 7>, <&dma 6>;
dma-names = "tx", "rx";
cdns,i2s-max-channels = <2>;
#sound-dai-cells = <0>;
- };
-- 2.25.1
On Thu, Dec 21, 2023 at 01:53:00PM +0000, Conor Dooley wrote:
On Thu, Dec 21, 2023 at 11:32:22AM +0800, Xingyu Wu wrote:
- cdns,i2s-max-channels:
- description: |
Number of I2S max stereo channels supported by the hardware.
- $ref: /schemas/types.yaml#/definitions/uint32
- minimum: 1
- maximum: 8
Mark, is there no common property for this kind of thing? That said, there's one device here so the number is known at present. Another note, this property is not required, so it should have a default.
I wouldn't expect this to be a property in the first place, as currently presented this is specific to a single instance of the IP in a single SoC. In general this is something that is obvious from the compatible and doesn't need a property, it's only plausibly useful for Cadence and Designware which is a very short list of vendors.
On 2023/12/21 21:58, Mark Brown wrote:
On Thu, Dec 21, 2023 at 01:53:00PM +0000, Conor Dooley wrote:
On Thu, Dec 21, 2023 at 11:32:22AM +0800, Xingyu Wu wrote:
- cdns,i2s-max-channels:
- description: |
Number of I2S max stereo channels supported by the hardware.
- $ref: /schemas/types.yaml#/definitions/uint32
- minimum: 1
- maximum: 8
Mark, is there no common property for this kind of thing? That said, there's one device here so the number is known at present. Another note, this property is not required, so it should have a default.
I wouldn't expect this to be a property in the first place, as currently presented this is specific to a single instance of the IP in a single SoC. In general this is something that is obvious from the compatible and doesn't need a property, it's only plausibly useful for Cadence and Designware which is a very short list of vendors.
The Cadence I2S can support 8 channels. But on the JH8100 SoC, two instances of this just provide 4 channels to use, one just provides 2 channels, and the other one can provide 8 channels. Should I use the property name of 'jh8100,i2s-max-channels' instead for some special instances on the JH8100 SoC?
Best regards, Xingyu Wu
On Fri, Dec 22, 2023 at 05:55:14PM +0800, Xingyu Wu wrote:
The Cadence I2S can support 8 channels. But on the JH8100 SoC, two instances of this just provide 4 channels to use, one just provides 2 channels, and the other one can provide 8 channels. Should I use the property name of 'jh8100,i2s-max-channels' instead for some special instances on the JH8100 SoC?
No, your current name is fine if the binding is generic for all Cadence users. I do think it would be good to have a separate compatible for these two channel instances, if there's been one customisation there may well have been others.
Please fix your mail client to word wrap within paragraphs at something substantially less than 80 columns. Doing this makes your messages much easier to read and reply to.
On 2023/12/21 21:53, Conor Dooley wrote:
Xingyu, Mark,
On Thu, Dec 21, 2023 at 11:32:22AM +0800, Xingyu Wu wrote:
Add bindings for the Multi-Channel I2S controller of Cadence on the StarFive JH8100 SoC.
Signed-off-by: Xingyu Wu xingyu.wu@starfivetech.com
.../bindings/sound/cdns,jh8100-i2s.yaml | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/cdns,jh8100-i2s.yaml
diff --git a/Documentation/devicetree/bindings/sound/cdns,jh8100-i2s.yaml b/Documentation/devicetree/bindings/sound/cdns,jh8100-i2s.yaml new file mode 100644 index 000000000000..5d95d9ab3e45 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cdns,jh8100-i2s.yaml @@ -0,0 +1,100 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/cdns,jh8100-i2s.yaml#
Filename matching the compatible please.
Noted.
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+title: Cadence multi-channel I2S controller for StarFive JH8100 SoC
+description: |
You only need the | if there is formatting to preserve.
Will drop.
- The Cadence I2S Controller implements a function of the multi-channel
- (up to 8-channel) bus. It combines functions of a transmitter and a receiver.
- It is used in the StarFive JH8100 SoC.
+maintainers:
- Xingyu Wu xingyu.wu@starfivetech.com
- Walker Chen walker.chen@starfivetech.com
+properties:
- compatible:
- const: starfive,jh8100-i2s
- reg:
- maxItems: 1
- interrupts:
- description: |
The interrupt line number for the I2S controller. Add this
parameter if the I2S controller that you are using does not
support DMA.
You've got one i2s controller here, you should know if it supports DMA or not.
The I2S already supports interrupt handler, but if the SoC supports DMA controller to be use, it can optionally use DMA.
- maxItems: 1
- clocks:
- items:
- description: Bit clock
- description: Main ICG clock
- description: Inner master clock
- clock-names:
- items:
- const: bclk
- const: icg
- const: mclk_inner
- resets:
- maxItems: 1
- dmas:
- items:
- description: TX DMA Channel
- description: RX DMA Channel
- minItems: 1
- dma-names:
- items:
- const: tx
- const: rx
- minItems: 1
- cdns,i2s-max-channels:
- description: |
Number of I2S max stereo channels supported by the hardware.
- $ref: /schemas/types.yaml#/definitions/uint32
- minimum: 1
- maximum: 8
Mark, is there no common property for this kind of thing? That said, there's one device here so the number is known at present. Another note, this property is not required, so it should have a default.
It's kinda hard to know with this binding - it is touted as being for a particular Cadence IP, and some aspects are pretty generic, but at the same time there's only one device here so it's hard to tell what is variable between implementations and what is not. Are there no other implementations of this controller? Unless it is brand new, I find that hard to believe.
Cheers, Conor.
Sorry, It does not seem to be common property. The Cadence I2S supports 8 channels. There are four I2S controllers on the JH8100 SoC, and two of them just provide 4 channels to use, one of them just provide 2 channels. It seems to depend on the SoC.
Thanks, Xingyu Wu
- "#sound-dai-cells":
- const: 0
+required:
- compatible
- reg
- clocks
- clock-names
- resets
+oneOf:
- required:
- dmas
- dma-names
- required:
- interrupts
+unevaluatedProperties: false
+examples:
- |
- i2s@122b0000 {
compatible = "starfive,jh8100-i2s";
reg = <0x122b0000 0x1000>;
clocks = <&syscrg_ne 133>,
<&syscrg_ne 170>,
<&syscrg 50>;
clock-names = "bclk", "icg",
"mclk_inner";
resets = <&syscrg_ne 43>;
dmas = <&dma 7>, <&dma 6>;
dma-names = "tx", "rx";
cdns,i2s-max-channels = <2>;
#sound-dai-cells = <0>;
- };
-- 2.25.1
On 21/12/2023 04:32, Xingyu Wu wrote:
- dma-names:
- items:
- const: tx
- const: rx
- minItems: 1
- cdns,i2s-max-channels:
Custom properties after generic, so after sound-dai-cells. The coding style now mentions this.
- description: |
Number of I2S max stereo channels supported by the hardware.
- $ref: /schemas/types.yaml#/definitions/uint32
- minimum: 1
- maximum: 8
- "#sound-dai-cells":
- const: 0
+required:
- compatible
- reg
- clocks
- clock-names
- resets
+oneOf:
- required:
- dmas
- dma-names
- required:
- interrupts
+unevaluatedProperties: false
This is not correct without allOf: which should point you to missing $ref to dai-common.
Best regards, Krzysztof
On 2023/12/22 0:07, Krzysztof Kozlowski wrote:
On 21/12/2023 04:32, Xingyu Wu wrote:
- dma-names:
- items:
- const: tx
- const: rx
- minItems: 1
- cdns,i2s-max-channels:
Custom properties after generic, so after sound-dai-cells. The coding style now mentions this.
Noted.
- description: |
Number of I2S max stereo channels supported by the hardware.
- $ref: /schemas/types.yaml#/definitions/uint32
- minimum: 1
- maximum: 8
- "#sound-dai-cells":
- const: 0
+required:
- compatible
- reg
- clocks
- clock-names
- resets
+oneOf:
- required:
- dmas
- dma-names
- required:
- interrupts
+unevaluatedProperties: false
This is not correct without allOf: which should point you to missing $ref to dai-common.
Will fix.
Best regards, Krzysztof
Thanks, Xingyu Wu
participants (3)
-
Conor Dooley
-
kernel test robot
-
Krzysztof Kozlowski
-
Mark Brown
-
Xingyu Wu