【i2s】Milk-V Duo添加speaker——max98357a解码器驱动

git diff

eth0 disable and ssh still can work.

diff --git a/build/boards/cv180x/cv1800b_milkv_duo_sd/dts_riscv/cv1800b_milkv_duo_sd.dts b/build/boards/cv180x/cv1800b_milkv_duo_sd/dts_riscv/cv1800b_milkv_duo_sd.dts
index e90e2c32a..e970969ff 100644
--- a/build/boards/cv180x/cv1800b_milkv_duo_sd/dts_riscv/cv1800b_milkv_duo_sd.dts
+++ b/build/boards/cv180x/cv1800b_milkv_duo_sd/dts_riscv/cv1800b_milkv_duo_sd.dts
@@ -29,3 +29,40 @@
 	model = "Milk-V Duo";
 };
 
+// [+] youaki, add for speaker
+
+
+&i2s2 {
+	status = "okay";
+	#sound-dai-cells = <0>;
+};
+
+/**/
+
+&ethernet0 {
+	status = "disabled";
+};
+
+
+/ {
+	/* codec */
+	max98357a: max98357a {
+		#sound-dai-cells = <0>;
+		compatible = "maxim,max98357a";
+		status = "okay";
+
+		/* this may be necessary, otherwise driver will not load */
+		sdmode-gpios = <&porta 14 0>;
+		/* max98357a has gain & sd_mode gpio. but codec driver just has sdmode */
+
+		clocks = <&i2s_mclk 0>;
+		clock-names = "i2sclk";
+	};
+
+	/* sound_ext3 use external codec */
+	sound_max98357a {
+		compatible = "cvitek,cv1835-max98357a";
+		cvi,card_name = "cv1835_max98357a";
+	};
+
+};
diff --git a/build/boards/cv180x/cv1800b_milkv_duo_sd/linux/cvitek_cv1800b_milkv_duo_sd_defconfig b/build/boards/cv180x/cv1800b_milkv_duo_sd/linux/cvitek_cv1800b_milkv_duo_sd_defconfig
index 4c60136fc..1cdbc64aa 100644
--- a/build/boards/cv180x/cv1800b_milkv_duo_sd/linux/cvitek_cv1800b_milkv_duo_sd_defconfig
+++ b/build/boards/cv180x/cv1800b_milkv_duo_sd/linux/cvitek_cv1800b_milkv_duo_sd_defconfig
@@ -345,3 +345,16 @@ CONFIG_EPOLL=n
 CONFIG_ELF_CORE=y
 CONFIG_COREDUMP=y
 CONFIG_PROC_SYSCTL=y
+
+# youkai add for audio
+CONFIG_SND_PROC_FS=y
+# CONFIG_SND_SOC_CV1835_CONCURRENT_I2S=y  # question
+
+# close dac -- dac gpio used to led
+CONFIG_SND_SOC_CV182XA_CV182XADAC=n
+CONFIG_SND_SOC_CV182XADAC=n
+
+# add max98357a for speaker
+CONFIG_SND_SOC_MAX98357A=y
+CONFIG_SND_SOC_CV1835_MAX98357A=y
+# CONFIG_DEBUG_INFO=y
diff --git a/build/boards/cv180x/cv1800b_milkv_duo_sd/u-boot/cvi_board_init.c b/build/boards/cv180x/cv1800b_milkv_duo_sd/u-boot/cvi_board_init.c
index 74941cb09..69eb4320d 100644
--- a/build/boards/cv180x/cv1800b_milkv_duo_sd/u-boot/cvi_board_init.c
+++ b/build/boards/cv180x/cv1800b_milkv_duo_sd/u-boot/cvi_board_init.c
@@ -41,5 +41,12 @@ int cvi_board_init(void)
 	PINMUX_CONFIG(SD1_D0, SPI2_SDI);
 	PINMUX_CONFIG(SD1_D3, SPI2_CS_X);
 
+	// youkai add for max98357a speaker
+	PINMUX_CONFIG(PAD_ETH_TXP, IIS2_LRCK);
+	PINMUX_CONFIG(PAD_ETH_TXM, IIS2_BCLK);
+	PINMUX_CONFIG(PAD_ETH_RXP, IIS2_DO);
+	PINMUX_CONFIG(PAD_ETH_RXM, IIS2_DI);
+	PINMUX_CONFIG(SD0_PWR_EN, XGPIOA_14);	// sdmode
+
 	return 0;
 }
diff --git a/build/boards/cv181x/cv1812cp_milkv_duo256m_sd/dts_riscv/cv1812cp_milkv_duo256m_sd.dts b/build/boards/cv181x/cv1812cp_milkv_duo256m_sd/dts_riscv/cv1812cp_milkv_duo256m_sd.dts
index 16734cb47..f08c768ed 100644
--- a/build/boards/cv181x/cv1812cp_milkv_duo256m_sd/dts_riscv/cv1812cp_milkv_duo256m_sd.dts
+++ b/build/boards/cv181x/cv1812cp_milkv_duo256m_sd/dts_riscv/cv1812cp_milkv_duo256m_sd.dts
@@ -34,3 +34,22 @@
 	model = "Milk-V Duo256M";
 };
 
+// [+] youaki, add for speaker
+
+/ {
+	/* codec */
+	max98357a: max98357a {
+		#sound-dai-cells = <0>;
+		compatible = "maxim,max98357a";
+		status = "okay";
+		/*sdmode-gpios = <&gpio1 14 0>;*/ 
+		/* max98357a has gain & sd_mode gpio. but codec driver just has sdmode */
+	};
+
+	/* sound_ext3 use external codec */
+	sound {
+		compatible = "cvitek,cv1835-max98357a";
+		cvi,card_name = "cv1835_max98357a";
+	};
+
+};
diff --git a/build/boards/cv181x/cv1812cp_milkv_duo256m_sd/linux/cvitek_cv1812cp_milkv_duo256m_sd_defconfig b/build/boards/cv181x/cv1812cp_milkv_duo256m_sd/linux/cvitek_cv1812cp_milkv_duo256m_sd_defconfig
index 4bfbc511c..368638019 100644
--- a/build/boards/cv181x/cv1812cp_milkv_duo256m_sd/linux/cvitek_cv1812cp_milkv_duo256m_sd_defconfig
+++ b/build/boards/cv181x/cv1812cp_milkv_duo256m_sd/linux/cvitek_cv1812cp_milkv_duo256m_sd_defconfig
@@ -294,3 +294,16 @@ CONFIG_EPOLL=n
 CONFIG_ELF_CORE=y
 CONFIG_COREDUMP=y
 CONFIG_PROC_SYSCTL=y
+
+# youkai add for audio
+CONFIG_SND_PROC_FS=y
+# CONFIG_SND_SOC_CV1835_CONCURRENT_I2S=y  # question
+
+# close dac -- dac gpio used to led
+CONFIG_SND_SOC_CV182XA_CV182XADAC=n
+CONFIG_SND_SOC_CV182XADAC=n
+
+# add max98357a for speaker
+CONFIG_SND_SOC_MAX98357A=y
+CONFIG_SND_SOC_CV1835_MAX98357A=y
+# CONFIG_DEBUG_INFO=y
diff --git a/build/boards/default/dts/cv180x/cv180x_asic_bga.dtsi b/build/boards/default/dts/cv180x/cv180x_asic_bga.dtsi
index 2bcacfb3a..8d5b60514 100644
--- a/build/boards/default/dts/cv180x/cv180x_asic_bga.dtsi
+++ b/build/boards/default/dts/cv180x/cv180x_asic_bga.dtsi
@@ -5,7 +5,9 @@
 
 / {
 	/delete-node/ i2s@04110000;
-	/delete-node/ i2s@04120000;
+	/*
+		/delete-node/ i2s@04120000;
+	*/
 	/delete-node/ sound_ext1;
 	/delete-node/ sound_ext2;
 	/delete-node/ sound_PDM;
diff --git a/build/boards/default/dts/cv181x/cv181x_asic_qfn.dtsi b/build/boards/default/dts/cv181x/cv181x_asic_qfn.dtsi
index 93081c5d7..7d915d6dd 100644
--- a/build/boards/default/dts/cv181x/cv181x_asic_qfn.dtsi
+++ b/build/boards/default/dts/cv181x/cv181x_asic_qfn.dtsi
@@ -104,7 +104,9 @@
 / {
 	/delete-node/ wifi-sd@4320000;
 	/delete-node/ i2s@04110000;
-	/delete-node/ i2s@04120000;
+	/*
+		/delete-node/ i2s@04120000;
+	*/
 	/delete-node/ sound_ext1;
 	/delete-node/ sound_ext2;
 	/delete-node/ sound_PDM;
diff --git a/buildroot-2021.05/configs/milkv-duo256m_musl_riscv64_defconfig b/buildroot-2021.05/configs/milkv-duo256m_musl_riscv64_defconfig
index 20fa4431e..aee4dbef4 100644
--- a/buildroot-2021.05/configs/milkv-duo256m_musl_riscv64_defconfig
+++ b/buildroot-2021.05/configs/milkv-duo256m_musl_riscv64_defconfig
@@ -510,3 +510,6 @@ BR2_PACKAGE_NCNN=y
 BR2_PACKAGE_NCNN_BENCH=y
 BR2_PACKAGE_NCNN_EXAMPLE=y
 BR2_PACKAGE_CMATRIX=y
+
+# youkai add -- open audio
+BR2_PACKAGE_TINYALSA=y
diff --git a/buildroot-2021.05/configs/milkv-duo_musl_riscv64_defconfig b/buildroot-2021.05/configs/milkv-duo_musl_riscv64_defconfig
index 2bc8cd5e3..f0c014b9c 100644
--- a/buildroot-2021.05/configs/milkv-duo_musl_riscv64_defconfig
+++ b/buildroot-2021.05/configs/milkv-duo_musl_riscv64_defconfig
@@ -519,3 +519,6 @@ BR2_PACKAGE_IPERF3=y
 BR2_PACKAGE_NTP=y
 BR2_PACKAGE_NTP_NTPDATE=y
 BR2_PACKAGE_NTP_NTPTIME=y
+
+# youkai add -- open audio
+BR2_PACKAGE_TINYALSA=y
diff --git a/device/milkv-duo/overlay/mnt/system/usb-rndis.sh b/device/milkv-duo/overlay/mnt/system/usb-rndis.sh
index e0f132b3a..95972ae2f 100755
--- a/device/milkv-duo/overlay/mnt/system/usb-rndis.sh
+++ b/device/milkv-duo/overlay/mnt/system/usb-rndis.sh
@@ -7,6 +7,9 @@
 sleep 0.5
 ifconfig usb0 192.168.42.1
 
+# youkai add for tinyalsa
+ln -s /lib/ld-musl-riscv64v0p7_xthead.so.1 /lib/ld-musl-riscv64.so.1
+
 count=`ps | grep dnsmasq | grep -v grep | wc -l`
 if [ ${count} -lt 1 ] ;then
   echo "/etc/init.d/S80dnsmasq start" >> /tmp/rndis.log 2>&1
diff --git a/device/milkv-duo256m/overlay/mnt/system/usb-rndis.sh b/device/milkv-duo256m/overlay/mnt/system/usb-rndis.sh
index e0f132b3a..95972ae2f 100755
--- a/device/milkv-duo256m/overlay/mnt/system/usb-rndis.sh
+++ b/device/milkv-duo256m/overlay/mnt/system/usb-rndis.sh
@@ -7,6 +7,9 @@
 sleep 0.5
 ifconfig usb0 192.168.42.1
 
+# youkai add for tinyalsa
+ln -s /lib/ld-musl-riscv64v0p7_xthead.so.1 /lib/ld-musl-riscv64.so.1
+
 count=`ps | grep dnsmasq | grep -v grep | wc -l`
 if [ ${count} -lt 1 ] ;then
   echo "/etc/init.d/S80dnsmasq start" >> /tmp/rndis.log 2>&1
diff --git a/linux_5.10/sound/soc/cvitek/Kconfig b/linux_5.10/sound/soc/cvitek/Kconfig
index b2540aa8e..62bd74cac 100644
--- a/linux_5.10/sound/soc/cvitek/Kconfig
+++ b/linux_5.10/sound/soc/cvitek/Kconfig
@@ -190,3 +190,9 @@ config SND_SOC_CV1835_LT9611
 	tristate "Support for the lt9611 card"
 	help
 	  lt9611 codec enable.
+
+# youkai add for extend speaker
+config SND_SOC_CV1835_MAX98357A
+	tristate "Support for the max98357a card"
+	help
+	  max98357a codec enable.
diff --git a/linux_5.10/sound/soc/cvitek/Makefile b/linux_5.10/sound/soc/cvitek/Makefile
index 93060ca2b..f538b0e7f 100644
--- a/linux_5.10/sound/soc/cvitek/Makefile
+++ b/linux_5.10/sound/soc/cvitek/Makefile
@@ -79,3 +79,6 @@ endif
 obj-$(CONFIG_CV1835_I2S_SUBSYS) += cv1835_i2s_subsys.o
 
 obj-$(CONFIG_SND_SOC_CV1835_LT9611) += cv1835_lt9611.o
+
+# youkai add for extend speaker
+obj-$(CONFIG_SND_SOC_CV1835_MAX98357A) += cv1835_max98357a.o
diff --git a/linux_5.10/sound/soc/cvitek/cv1835_i2s.c b/linux_5.10/sound/soc/cvitek/cv1835_i2s.c
index 77f1f2126..d33997acd 100644
--- a/linux_5.10/sound/soc/cvitek/cv1835_i2s.c
+++ b/linux_5.10/sound/soc/cvitek/cv1835_i2s.c
@@ -96,7 +96,9 @@ static void i2s_reset(struct cvi_i2s_dev *dev, u32 stream)
 {
 	u32 retry = 0;
 
-	dev_dbg(dev->dev, "blk_mode=0x%08x, clk_ctrl=0x%08x, i2s_enable=0x%08x\n",
+	dev_err(dev->dev,"%s start ====={",__func__);
+
+	dev_err(dev->dev, "blk_mode=0x%08x, clk_ctrl=0x%08x, i2s_enable=0x%08x\n",
 		i2s_read_reg(dev->i2s_base, BLK_MODE_SETTING),
 		i2s_read_reg(dev->i2s_base, I2S_CLK_CTRL0),
 		i2s_read_reg(dev->i2s_base, I2S_ENABLE));
@@ -126,6 +128,8 @@ static void i2s_reset(struct cvi_i2s_dev *dev, u32 stream)
 
 		i2s_write_reg(dev->i2s_base, I2S_RESET, I2S_RESET_TX_PULL_DOWN);
 	}
+
+	dev_err(dev->dev,"%s end =====}",__func__);
 }
 
 static irqreturn_t i2s_irq_handler(int irq, void *dev_id)
@@ -137,7 +141,7 @@ static irqreturn_t i2s_irq_handler(int irq, void *dev_id)
 
 	if (dev->active >= 1) { /* If I2S is really active */
 		if (val & (I2S_INT_RXFO | I2S_INT_RXFU)) {
-			dev_dbg(dev->dev, "WARNING!!! I2S RX FIFO exception occur int_status=0x%x\n", val);
+			dev_err(dev->dev, "WARNING!!! I2S RX FIFO exception occur int_status=0x%x\n", val);
 			i2s_write_reg(dev->i2s_base, I2S_ENABLE, I2S_OFF);
 			i2s_write_reg(dev->i2s_base, I2S_CLK_CTRL0,
 				      (i2s_read_reg(dev->i2s_base, I2S_CLK_CTRL0) | AUD_ENABLE));
@@ -145,7 +149,7 @@ static irqreturn_t i2s_irq_handler(int irq, void *dev_id)
 			i2s_reset(dev, SNDRV_PCM_STREAM_CAPTURE);
 			i2s_write_reg(dev->i2s_base, I2S_ENABLE, I2S_ON);
 		} else if (val & (I2S_INT_TXFO | I2S_INT_TXFU)) {
-			dev_dbg(dev->dev, "WARNING!!! I2S TX FIFO exception occur int_status=0x%x\n", val);
+			dev_err(dev->dev, "WARNING!!! I2S TX FIFO exception occur int_status=0x%x\n", val);
 			i2s_write_reg(dev->i2s_base, I2S_ENABLE, I2S_OFF);
 			i2s_write_reg(dev->i2s_base, I2S_CLK_CTRL0,
 				      (i2s_read_reg(dev->i2s_base, I2S_CLK_CTRL0) | AUD_ENABLE));
@@ -164,7 +168,7 @@ static irqreturn_t i2s_irq_handler(int irq, void *dev_id)
 static void i2s_start(struct cvi_i2s_dev *dev,
 		      struct snd_pcm_substream *substream)
 {
-
+	dev_err(dev->dev,"%s start ====={",__func__);
 	u32 i2s_enable = i2s_read_reg(dev->i2s_base, I2S_ENABLE);
 	u32 clk_ctrl = i2s_read_reg(dev->i2s_base, I2S_CLK_CTRL0);
 	u32 blk_mode_setting = i2s_read_reg(dev->i2s_base, BLK_MODE_SETTING);
@@ -193,7 +197,7 @@ static void i2s_start(struct cvi_i2s_dev *dev,
 	} else
 		dev_err(dev->dev, "WARNING!!!  I2S SHOULD NOT be in ON state\n");
 
-	dev_dbg(dev->dev,
+	dev_err(dev->dev,
 		"blk_mode=0x%08x, clk_ctrl=0x%08x, int_en=0x%08x, frame_setting=0x%08x, slot_setting=0x%08x, data_format=0x%08x\n",
 		i2s_read_reg(dev->i2s_base, BLK_MODE_SETTING),
 		i2s_read_reg(dev->i2s_base, I2S_CLK_CTRL0),
@@ -201,6 +205,7 @@ static void i2s_start(struct cvi_i2s_dev *dev,
 		i2s_read_reg(dev->i2s_base, FRAME_SETTING),
 		i2s_read_reg(dev->i2s_base, SLOT_SETTING1),
 		i2s_read_reg(dev->i2s_base, DATA_FORMAT));
+	dev_err(dev->dev,"%s end =====}",__func__);
 }
 
 static void i2s_stop(struct cvi_i2s_dev *dev,
@@ -217,7 +222,7 @@ static void i2s_stop(struct cvi_i2s_dev *dev,
 		u32 clk_ctrl = i2s_read_reg(dev->i2s_base, I2S_CLK_CTRL0);
 
 		if (((blk_mode_setting & ROLE_MASK) == MASTER_MODE) && ((clk_ctrl & AUD_ENABLE) == AUD_ENABLE))	{
-			dev_dbg(dev->dev, "Disable aud_en\n");
+			dev_err(dev->dev, "Disable aud_en\n");
 			i2s_write_reg(dev->i2s_base, I2S_CLK_CTRL0, clk_ctrl & ~(AUD_ENABLE));
 		}
 	}
@@ -234,7 +239,7 @@ static int cvi_i2s_dai_probe(struct snd_soc_dai *cpu_dai)
 {
 	struct cvi_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
 
-	dev_dbg(cpu_dai->dev, "%s start *cpu_dai = %p name = %s\n", __func__, cpu_dai, cpu_dai->name);
+	dev_err(cpu_dai->dev, "%s start *cpu_dai = %p name = %s\n", __func__, cpu_dai, cpu_dai->name);
 	cpu_dai->playback_dma_data = &dev->play_dma_data;
 	cpu_dai->capture_dma_data = &dev->capture_dma_data;
 
@@ -246,7 +251,7 @@ static int cvi_i2s_dai_probe(struct snd_soc_dai *cpu_dai)
 		dev_err(cpu_dai->dev, "%s capture_dma_data == NULL\n", __func__);
 	}
 
-	dev_dbg(cpu_dai->dev, "%s end cpu_dai->playback_dma_data = %p\n", __func__, cpu_dai->playback_dma_data);
+	dev_err(cpu_dai->dev, "%s end cpu_dai->playback_dma_data = %p\n", __func__, cpu_dai->playback_dma_data);
 
 	return 0;
 
@@ -259,16 +264,16 @@ static int cvi_i2s_startup(struct snd_pcm_substream *substream,
 	struct cvi_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
 	union cvi_i2s_snd_dma_data *dma_data = NULL;
 
-	dev_dbg(dev->dev, "%s start *cpu_dai = %p name = %s\n", __func__, cpu_dai, cpu_dai->name);
+	dev_err(dev->dev, "%s start *cpu_dai = %p name = %s\n", __func__, cpu_dai, cpu_dai->name);
 	if (!(dev->capability & CVI_I2S_RECORD) &&
 	    (substream->stream == SNDRV_PCM_STREAM_CAPTURE)) {
-		dev_dbg(dev->dev, "%s return -EINVAL;\n", __func__);
+		dev_err(dev->dev, "%s return -EINVAL;\n", __func__);
 		return -EINVAL;
 	}
 
 	if (!(dev->capability & CVI_I2S_PLAY) &&
 	    (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)) {
-		dev_dbg(dev->dev, "%s return -EINVAL; 2\n", __func__);
+		dev_err(dev->dev, "%s return -EINVAL; 2\n", __func__);
 		return -EINVAL;
 	}
 
@@ -277,12 +282,12 @@ static int cvi_i2s_startup(struct snd_pcm_substream *substream,
 	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
 		dma_data = &dev->capture_dma_data;
 	if (dma_data == NULL) {
-		dev_dbg(dev->dev, "%s dma_data == NULL\n", __func__);
+		dev_err(dev->dev, "%s dma_data == NULL\n", __func__);
 	}
 
-	dev_dbg(dev->dev, "%s start *dma_data = %p\n", __func__, dma_data);
+	dev_err(dev->dev, "%s start *dma_data = %p\n", __func__, dma_data);
 	snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)dma_data);
-	dev_dbg(dev->dev, "%s end cpu_dai->playback_dma_data = %p\n",
+	dev_err(dev->dev, "%s end cpu_dai->playback_dma_data = %p\n",
 		__func__, cpu_dai->playback_dma_data);
 	return 0;
 }
@@ -315,6 +320,14 @@ static int cvi_i2s_hw_params(struct snd_pcm_substream *substream,
 
 	config->chan_nr = params_channels(params);
 
+	dev_err(dev->dev,"%s ====={", __func__);
+
+	dev_err(dev->dev,"youkai %s card short name %s\n",__func__,substream->pcm->card->shortname);
+
+	dev_err(dev->dev,"(1) format");
+
+	dev_err(dev->dev, "channel %d format %d\n",params_channels(params),params_format(params));
+
 	switch (params_format(params)) {
 	case SNDRV_PCM_FORMAT_S16_LE:
 	case SNDRV_PCM_FORMAT_U16_LE:
@@ -349,8 +362,13 @@ static int cvi_i2s_hw_params(struct snd_pcm_substream *substream,
 						frame_setting |= FRAME_LENGTH(16) | FS_ACT_LENGTH(16);
 						break;
 					}
-				} else
+				} else{
 					frame_setting |= FRAME_LENGTH(16) | FS_ACT_LENGTH(16);
+					dev_err(dev->dev,"format 16");
+				}
+			} else if (!strcmp(substream->pcm->card->shortname, "cv1835_max98357a")) {
+				frame_setting |= FRAME_LENGTH(32) | FS_ACT_LENGTH(16);
+				dev_err(dev->dev,"format 16");
 			} else
 				frame_setting |= FRAME_LENGTH(32) | FS_ACT_LENGTH(16);
 
@@ -374,7 +392,8 @@ static int cvi_i2s_hw_params(struct snd_pcm_substream *substream,
 		if (!strcmp(substream->pcm->card->shortname, "cv182x_adc") ||
 			!strcmp(substream->pcm->card->shortname, "cv182x_dac") ||
 			!strcmp(substream->pcm->card->shortname, "cv182xa_adc") ||
-			!strcmp(substream->pcm->card->shortname, "cv182xa_dac")) {
+			!strcmp(substream->pcm->card->shortname, "cv182xa_dac") ||
+			!strcmp(substream->pcm->card->shortname, "cv1835_max98357a")) {
 			dev_err(dev->dev, "24 bit resolution is not supported\n");
 			return -EINVAL;
 		}
@@ -402,7 +421,8 @@ static int cvi_i2s_hw_params(struct snd_pcm_substream *substream,
 		if (!strcmp(substream->pcm->card->shortname, "cv182x_adc") ||
 			!strcmp(substream->pcm->card->shortname, "cv182x_dac") ||
 			!strcmp(substream->pcm->card->shortname, "cv182xa_adc") ||
-			!strcmp(substream->pcm->card->shortname, "cv182xa_dac")
+			!strcmp(substream->pcm->card->shortname, "cv182xa_dac") ||
+			!strcmp(substream->pcm->card->shortname, "cv1835_max98357a")
 			) {
 			dev_err(dev->dev, "32 bit resolution is not supported\n");
 			return -EINVAL;
@@ -431,6 +451,8 @@ static int cvi_i2s_hw_params(struct snd_pcm_substream *substream,
 	}
 	i2s_write_reg(dev->i2s_base, SLOT_SETTING1, slot_setting1);
 	i2s_write_reg(dev->i2s_base, FRAME_SETTING, frame_setting);
+	dev_err(dev->dev, "## slot_setting1 = %d\n", slot_setting1);
+	dev_err(dev->dev, "## frame_setting = %d\n", frame_setting);
 
 #if defined(CONFIG_SND_SOC_CV1835_CONCURRENT_I2S)
 	if ((dev->dev_id != 0) && (dev->dev_id != 3) && (dev->dev_id != i2s_subsys_query_master()))
@@ -438,7 +460,7 @@ static int cvi_i2s_hw_params(struct snd_pcm_substream *substream,
 #endif
 
 	slot_setting1 &= ~SLOT_NUM_MASK;
-	dev_dbg(dev->dev, "CVI-i2s: set slot number=%d\n",	config->chan_nr);
+	dev_err(dev->dev, "CVI-i2s: set slot number=%d\n",	slot_setting1);
 	switch (config->chan_nr) {
 	case EIGHT_CHANNEL_SUPPORT:
 		slot_setting1 |= SLOT_NUM(8);
@@ -467,6 +489,8 @@ static int cvi_i2s_hw_params(struct snd_pcm_substream *substream,
 			data_format |= SKIP_TX_INACT_SLOT;
 		} else
 			slot_setting1 |= SLOT_NUM(1);
+		
+		dev_err(dev->dev, "slot number=%d data_format %d\n", slot_setting1, data_format);
 
 		i2s_write_reg(dev->i2s_base, SLOT_SETTING1, slot_setting1);
 		i2s_write_reg(dev->i2s_base, SLOT_SETTING2, 0x01); /* enable slot 0-3 for TDM */
@@ -478,7 +502,12 @@ static int cvi_i2s_hw_params(struct snd_pcm_substream *substream,
 
 	cvi_i2s_config(dev, substream->stream); /* Config use HW DMA and FIFO threshold here */
 
+	dev_err(dev->dev,"(2) rate");
+
 	config->sample_rate = params_rate(params);
+
+	dev_err(dev->dev, "youkai sample_rate = %d\n",config->sample_rate);
+
 	//audio_clk = clk_get_rate(dev->clk);
 	/* set audio_clk depends on audio format */
 	switch (config->sample_rate) {
@@ -487,12 +516,18 @@ static int cvi_i2s_hw_params(struct snd_pcm_substream *substream,
 	case 44100:
 	case 88200:
 		audio_clk = CVI_22579_MHZ;
+		// if (!strcmp(substream->pcm->card->shortname, "cv1835_max98357a")){
+		// 	audio_clk = CVI_24576_MHZ;
+		// 	config->sample_rate = 48000;
+		// 	dev_err(dev->dev, "youkai match ");
+		// }
 		break;
 	case 8000:
 	case 16000:
 	case 32000:
 		if (!strcmp(substream->pcm->card->shortname, "cv182xa_adc") ||
-			!strcmp(substream->pcm->card->shortname, "cv182xa_dac"))
+			!strcmp(substream->pcm->card->shortname, "cv182xa_dac") ||
+			!strcmp(substream->pcm->card->shortname, "cv1835_max98357a"))
 			audio_clk = CVI_16384_MHZ;
 		else
 			audio_clk = CVI_24576_MHZ;
@@ -543,7 +578,7 @@ static int cvi_i2s_hw_params(struct snd_pcm_substream *substream,
 			!strcmp(substream->pcm->card->shortname, "cv182x_dac")) {
 		/* cv182x internal adc codec need dynamic MCLK frequency input */
 
-		dev_info(dev->dev, "%s set MCLK\n", __func__);
+		dev_err(dev->dev, "%s set MCLK rate=%d\n", __func__, config->sample_rate);
 		switch (config->sample_rate) {
 		case 8000:
 			clk_ctrl1 |= MCLK_DIV(6);
@@ -572,6 +607,27 @@ static int cvi_i2s_hw_params(struct snd_pcm_substream *substream,
 			!strcmp(substream->pcm->card->shortname, "cv182xa_dac")) {
 		/* cv182xa internal adc codec need dynamic MCLK frequency input */
 
+		switch (config->sample_rate) {
+		case 8000:
+		case 16000:
+		case 32000:
+			/* apll is 16.384Mhz, no need to divide */
+			clk_ctrl1 |= MCLK_DIV(1);
+			mclk_div = 1;
+			break;
+		case 11025:
+		case 22050:
+		case 44100:
+		case 48000:
+			clk_ctrl1 |= MCLK_DIV(2);
+			mclk_div = 2;
+			break;
+		default:
+			dev_err(dev->dev, "%s doesn't support this sample rate\n", __func__);
+			break;
+		}
+	} else if (!strcmp(substream->pcm->card->shortname, "cv1835_max98357a")) {
+
 		switch (config->sample_rate) {
 		case 8000:
 		case 16000:
@@ -592,14 +648,23 @@ static int cvi_i2s_hw_params(struct snd_pcm_substream *substream,
 			break;
 		}
 	} else {
+		dev_err(dev->dev, "%s set mclk audio_clk %d\n", substream->pcm->card->shortname,audio_clk);
 		if ((audio_clk == CVI_24576_MHZ) || (audio_clk == CVI_22579_MHZ)){
 			clk_ctrl1 |= MCLK_DIV(2);
 			mclk_div = 2;
+			dev_err(dev->dev, "set mclk ok");
 		}
 		else
 			dev_err(dev->dev, "Get unexpected audio system clk=%d\n", audio_clk);
 	}
 
+	dev_err(dev->dev, "## audio_clk = %d mclk_div %d \n", audio_clk, mclk_div);
+
+	dev_err(dev->dev,"(3) wss");
+
+	dev_err(dev->dev, "## dev->wss = %d\n", dev->wss);
+	dev_err(dev->dev, "## data_format = %d\n", data_format);
+
 	/* Configure I2S word length,  bclk_div and sync_div here*/
 	switch (dev->wss) {
 	case (WSS_32_CLKCYCLE):
@@ -630,22 +695,30 @@ static int cvi_i2s_hw_params(struct snd_pcm_substream *substream,
 		data_format |= WORD_LEN_32;
 		break;
 	case (WSS_16_CLKCYCLE):
+		dev_err(dev->dev, "WSS_16_CLKCYCLE\n");
+
 #if defined(CONFIG_ARCH_CV183X_ASIC)
+			dev_err(dev->dev, "CONFIG_ARCH_CV183X_ASIC\n");
 			bclk_div = (audio_clk / 1000) / (WSS_16_CLKCYCLE * (config->sample_rate / 1000));
 #else
+			dev_err(dev->dev, "no CONFIG_ARCH_CV183X_ASIC\n");
 			bclk_div = (audio_clk / 1000) / (WSS_16_CLKCYCLE * (config->sample_rate / 1000) * mclk_div);
 #endif
+		dev_err(dev->dev, "audio_clk %d rate %d mclk_div %d bclk_div %d\n", audio_clk, config->sample_rate, mclk_div, bclk_div);
 		data_format |= WORD_LEN_16;
 		break;
 	default:
 		dev_err(dev->dev, "resolution not supported\n");
 	}
 
+	dev_err(dev->dev,"(4) word length\n");
+
 	/* Configure word length */
 	i2s_write_reg(dev->i2s_base, DATA_FORMAT, data_format);
+	dev_err(dev->dev, "## data_format = %d\n", data_format);
 
 	clk_ctrl1 |= BCLK_DIV(bclk_div);
-	dev_dbg(dev->dev, "Set clock ctrl1=0x%08x\n", clk_ctrl1);
+	dev_err(dev->dev, "Set clock ctrl1=0x%08x\n", clk_ctrl1);
 	i2s_write_reg(dev->i2s_base, I2S_CLK_CTRL1, clk_ctrl1);
 
 #if defined(CONFIG_SND_SOC_CV1835_CONCURRENT_I2S)
@@ -653,12 +726,14 @@ static int cvi_i2s_hw_params(struct snd_pcm_substream *substream,
 		i2s_set_master_clk(clk_ctrl1);
 #endif
 
-	dev_dbg(dev->dev, "frame_setting=0x%08x, slot_setting1=0x%08x, clk_ctrl1=0x%08x, data_format=0x%08x\n",
+	dev_err(dev->dev, "frame_setting=0x%08x, slot_setting1=0x%08x, clk_ctrl1=0x%08x, data_format=0x%08x\n",
 		i2s_read_reg(dev->i2s_base, FRAME_SETTING),
 		i2s_read_reg(dev->i2s_base, SLOT_SETTING1),
 		i2s_read_reg(dev->i2s_base, I2S_CLK_CTRL1),
 		i2s_read_reg(dev->i2s_base, DATA_FORMAT));
 
+	dev_err(dev->dev,"%s =====}", __func__);
+
 	return 0;
 }
 
@@ -700,7 +775,7 @@ static int cvi_i2s_trigger(struct snd_pcm_substream *substream,
 		dev->active++;
 #if defined(CONFIG_SND_SOC_CV1835_CONCURRENT_I2S)
 		if ((dev->dev_id != 0) && (dev->dev_id != 3) && (dev->dev_id != i2s_subsys_query_master())) {
-			dev_dbg(dev->dev, "enable master clk generation\n");
+			dev_err(dev->dev, "enable master clk generation\n");
 			i2s_master_clk_switch_on(true);
 		}
 #endif
@@ -718,7 +793,7 @@ static int cvi_i2s_trigger(struct snd_pcm_substream *substream,
 		i2s_stop(dev, substream);
 #if defined(CONFIG_SND_SOC_CV1835_CONCURRENT_I2S)
 		if ((dev->dev_id != 0) && (dev->dev_id != 3) && (dev->dev_id != i2s_subsys_query_master())) {
-			dev_dbg(dev->dev, "disable master clk generation\n");
+			dev_err(dev->dev, "disable master clk generation\n");
 			i2s_master_clk_switch_on(false);
 		}
 #endif
@@ -746,7 +821,7 @@ static int cvi_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 
 	int ret = 0;
 
-	dev_dbg(dev->dev, "%s, fmt=0x%08x\n", __func__, fmt);
+	dev_err(dev->dev, "%s, fmt=0x%08x\n", __func__, fmt);
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM: /* Set codec to Master mode, so I2S IP need to be Slave mode */
@@ -762,7 +837,7 @@ static int cvi_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 		ret = -EINVAL;
 		break;
 	default:
-		dev_dbg(dev->dev, "cvitek : Invalid master/slave format\n");
+		dev_err(dev->dev, "cvitek : Invalid master/slave format\n");
 		ret = -EINVAL;
 		break;
 	}
@@ -789,7 +864,7 @@ static int cvi_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 		frame_setting |= FS_ACT_HIGH;
 		break;
 	default:
-		dev_dbg(dev->dev, "cvitek : Invalid frame format\n");
+		dev_err(dev->dev, "cvitek : Invalid frame format\n");
 		ret = -EINVAL;
 		break;
 	}
@@ -833,7 +908,7 @@ static int cvi_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 		i2s_write_reg(dev->i2s_base, FRAME_SETTING, frame_setting);
 		break;
 	default:
-		dev_dbg(dev->dev, "cvitek : Invalid I2S mode\n");
+		dev_err(dev->dev, "cvitek : Invalid I2S mode\n");
 		ret = -EINVAL;
 		break;
 	}
@@ -965,7 +1040,7 @@ static int cvi_configure_dai(struct cvi_i2s_dev *dev,
 
 
 	if ((!strcmp(capability, "tx")) || (!strcmp(capability, "txrx"))) {
-		dev_dbg(dev->dev, "CV: playback support\n");
+		dev_err(dev->dev, "CV: playback support\n");
 		cvi_i2s_dai->playback.channels_min = 1;
 		cvi_i2s_dai->playback.channels_max = 8;
 		cvi_i2s_dai->playback.formats = SNDRV_PCM_FMTBIT_S32_LE
@@ -977,13 +1052,13 @@ static int cvi_configure_dai(struct cvi_i2s_dev *dev,
 		cvi_i2s_dai->playback.rates = rates;
 	} else {
 		/* this device doesn't have playback capability */
-		dev_dbg(dev->dev, "CV: playback not support\n");
+		dev_err(dev->dev, "CV: playback not support\n");
 		cvi_i2s_dai->playback.channels_min = 0;
 		cvi_i2s_dai->playback.channels_max = 0;
 	}
 
 	if ((!strcmp(capability, "rx")) || (!strcmp(capability, "txrx"))) {
-		dev_dbg(dev->dev, "CV: capature support\n");
+		dev_err(dev->dev, "CV: capature support\n");
 		cvi_i2s_dai->capture.channels_min = 1;
 		cvi_i2s_dai->capture.channels_max = 8;
 		cvi_i2s_dai->capture.formats = SNDRV_PCM_FMTBIT_S32_LE
@@ -992,12 +1067,12 @@ static int cvi_configure_dai(struct cvi_i2s_dev *dev,
 		cvi_i2s_dai->capture.rates = rates;
 	} else {
 		/* this device doesn't have capature capability */
-		dev_dbg(dev->dev, "CV: capature not support\n");
+		dev_err(dev->dev, "CV: capature not support\n");
 		cvi_i2s_dai->capture.channels_min = 0;
 		cvi_i2s_dai->capture.channels_max = 0;
 	}
 
-	dev_dbg(dev->dev, "CV: i2s master/slave mode supported\n");
+	dev_err(dev->dev, "CV: i2s master/slave mode supported\n");
 	dev->capability |= CVI_I2S_MASTER | CVI_I2S_SLAVE;
 
 	dev->fifo_th = I2STDM_FIFO_DEPTH / 2;
@@ -1011,14 +1086,14 @@ static int cvi_configure_dai_by_dt(struct cvi_i2s_dev *dev,
 	int ret;
 	struct device_node *np = dev->dev->of_node;
 
-	dev_dbg(dev->dev, "%s start\n", __func__);
+	dev_err(dev->dev, "%s start\n", __func__);
 	ret = cvi_configure_dai(dev, cvi_i2s_dai, SNDRV_PCM_RATE_8000_192000);
 	if (ret < 0)
 		return ret;
 
 	/* Set TX parameters */
 	if (of_property_match_string(np, "dma-names", "tx") >= 0) {
-		dev_dbg(dev->dev, "%s dma-names  tx\n", __func__);
+		dev_err(dev->dev, "%s dma-names  tx\n", __func__);
 		dev->capability |= CVI_I2S_PLAY;
 		dev->play_dma_data.dt.addr = res->start + TX_WR_PORT_CH0;
 		dev->play_dma_data.dt.addr_width = 4;
@@ -1028,7 +1103,7 @@ static int cvi_configure_dai_by_dt(struct cvi_i2s_dev *dev,
 
 	/* Set RX parameters */
 	if (of_property_match_string(np, "dma-names", "rx") >= 0) {
-		dev_dbg(dev->dev, "%s dma-names  rx\n", __func__);
+		dev_err(dev->dev, "%s dma-names  rx\n", __func__);
 		dev->capability |= CVI_I2S_RECORD;
 		dev->capture_dma_data.dt.addr = res->start + RX_RD_PORT_CH0;
 		dev->capture_dma_data.dt.addr_width = 4;
@@ -1102,7 +1177,7 @@ static int cvi_i2s_probe(struct platform_device *pdev)
 	char *i2s_dev_name;
 	const char *mclk_out;
 
-	dev_info(&pdev->dev, "%s\n", __func__);
+	dev_err(&pdev->dev, "%s\n", __func__);
 
 	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
 	if (!dev)
@@ -1123,7 +1198,7 @@ static int cvi_i2s_probe(struct platform_device *pdev)
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	dev->i2s_base = devm_ioremap_resource(&pdev->dev, res);
-	dev_dbg(&pdev->dev, "I2S get i2s_base=0x%p\n", dev->i2s_base);
+	dev_err(&pdev->dev, "I2S get i2s_base=0x%p\n", dev->i2s_base);
 	if (IS_ERR(dev->i2s_base))
 		return PTR_ERR(dev->i2s_base);
 
@@ -1131,7 +1206,7 @@ static int cvi_i2s_probe(struct platform_device *pdev)
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq >= 0) {
-		dev_dbg(&pdev->dev, "I2S get IRQ=0x%x\n", irq);
+		dev_err(&pdev->dev, "I2S get IRQ=0x%x\n", irq);
 		ret = devm_request_irq(&pdev->dev, irq, i2s_irq_handler, 0,
 				       pdev->name, dev);
 		if (ret < 0) {
diff --git a/u-boot-2021.10/board/cvitek/cv180x/board.c b/u-boot-2021.10/board/cvitek/cv180x/board.c
index bfd1061b1..928aea125 100644
--- a/u-boot-2021.10/board/cvitek/cv180x/board.c
+++ b/u-boot-2021.10/board/cvitek/cv180x/board.c
@@ -157,9 +157,37 @@ void pinmux_config(int io_type)
 
 #include "../cvi_board_init.c"
 
+/*
+0x03009804[0] = 1'b1 (rg_ephy_apb_rw_sel=1, use apb interface)
+0x03009808[4:0] = 5'b00001 (rg_ephy_pll_stable_cnt[4:0] = 5'd1 (10us)
+0x03009800[2] = 0x0905 (rg_ephy_dig_rst_n=1, reset release, other keep default)
+wait 10us
+0x0300907C[12:8]= 5'b00101 (page_sel_mode0 = page 5)
+0x03009078[11:0] = 0xF00 (set to gpio from top)
+0x03009074[10:9 2:1]= 0x606 (set ephy rxp&rxm input&output enable)
+0x03009070[10:9 2:1]= 0x606 (set ephy rxp&rxm input&output enable)
+*/
+// static void cv180x_i2s2_init(void)
+// {
+// 	printk("cv180x_i2s2_init\n");
+// 	mmio_write_32(0x03009804, 0x0001);
+// 	mmio_write_32(0x03009808, 0x0001);
+// 	mmio_write_32(0x03009800, 0x0905);
+
+// 	// Wait PLL_Lock, Lock_Status p5.0x12@[15] = 1
+// 	mdelay(1);
+
+// 	mmio_write_32(0x0300907C, 0x0005);
+// 	mmio_write_32(0x03009078, 0x0F00);
+// 	mmio_write_32(0x03009074, 0x0606);
+// 	mmio_write_32(0x03009070, 0x0606);
+// }
+
 #if defined(CONFIG_PHY_CVITEK)
 static void cv180x_ephy_id_init(void)
 {
+	printk("cv180x_ephy_id_init\n");
+
 	// set rg_ephy_apb_rw_sel 0x0804@[0]=1/APB by using APB interface
 	mmio_write_32(0x03009804, 0x0001);
 
@@ -215,10 +243,14 @@ int board_init(void)
 	mmio_write_16(TIME_RECORDS_FIELD_UBOOT_START, start_time);
 
 #if defined(CONFIG_PHY_CVITEK) /* config cvitek cv180x eth internal phy on ASIC board */
-	cv180x_ephy_id_init();
+	cv180x_ephy_id_init();	// close eth0
 	cv180x_ephy_led_pinmux();
 #endif
 
+// #if defined(CONFIG_SND_SOC_CV1835_MAX98357A)
+	// cv180x_i2s2_init();			// open i2s2
+// #endif
+
 #if defined(CONFIG_NAND_SUPPORT)
 	pinmux_config(PINMUX_SPI_NAND);
 #elif defined(CONFIG_SPI_FLASH)

Re-enabled

CONFIG_STMMAC_ETH=y
CONFIG_CV182XA_PHY=y

in the defconfig while leaving

&ethernet0 {
	status = "disabled";
};

and now USB RNDIS works for ssh again while still seeing the slow pulsing on the 4 ETH TX/RX pins. So don’t do that. :slight_smile:

I tried to use the txp of eth0 as the sdmode to verify if I could set gpio through PINMUX-CONFIG in board_init. c.

However, I found that it failed.

It should still be necessary to configure the ethphy in 0x03009000.

But setting it up will cause SSH to fail, so I gave up porting max98357a on Duo.

Verified that my driver i2s and DMA functions are normal, it should be stuck in gpio mux.

Yes, it makes no sense to me that the GPIO pinmux settings seem to have no effect. For now I’m seeing that the internal codec ADC & DAC are working which provides single-channel analog audio I/O so that may be enough to proceed with some audio experiments. I would like to understand why the I2S pinmuxing on the ETH TX/RX pins doesn’t seem to work - a big mystery.

I finally found the “How to switch ETH to GPIO” description in the pin information spreadsheet which was quoted above. I see that you tried to include that in the board init but then commented it out. Have you tried to do that after boot-up via the devmem command? Does it still disable the RNDIS interface?

I noticed that your implementation of the “How to switch ETH to GPIO” register writes as described in the pin information spreadsheet is incorrect. The spreadsheet defines the proper register values using verilog vector syntax with bit field offsets that your code doesn’t apply properly. For example:

0x0300907C[12:8]= 5'b00101

is not equivalent to

mmio_write_32(0x0300907C, 0x0005);

but instead should be

mmio_write_32(0x0300907C, 0x0005<<8);

Note that it may also be necessary to preserve the contents of the other unspecified bits as well.

I’m testing this with a user-space mmap program now…

1 Like

Success! I’ve created a userland program that uses mmap to poke the proper values as described by the pinmap spreadsheet and now I’m seeing I2S signals on the ETH TX/RX pins. Here’s the code:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>

#define ETH_BASE_ADDRESS 0x03009000  // Base address of ETH registers on Duo

// Offsets for ETH registers
#define ETH_070 0x070
#define ETH_074 0x074
#define ETH_078 0x078
#define ETH_07C 0x07C
#define ETH_800 0x800
#define ETH_804 0x804
#define ETH_808 0x806

// word access macro
#define word(x) (x / sizeof(unsigned int))

int main() {
    int mem_fd;
    void *reg_map;

    // Open /dev/mem
    if ((mem_fd = open("/dev/mem", O_RDWR | O_SYNC)) < 0) {
        perror("can't open /dev/mem");
        return 1;
    }

    // Map registers to user space memory
    reg_map = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, ETH_BASE_ADDRESS);

    if (reg_map == MAP_FAILED) {
        perror("mmap error");
        close(mem_fd);
        return 1;
    }

    // Access ETH registers
    volatile unsigned int *eth_reg = (volatile unsigned int *)reg_map;
    unsigned int temp;

    // 0x03009804[0] = 1'b1 (rg_ephy_apb_rw_sel=1, use apb interface)
    temp = eth_reg[word(ETH_804)];
    printf("READ 804: 0x%08X\n", temp);
    temp |= 0x1;
    eth_reg[word(ETH_804)] = temp;
    printf("WRITE 804: 0x%08X\n", temp);

    // 0x03009808[4:0] = 5'b00001 (rg_ephy_pll_stable_cnt[4:0] = 5'd1 (10us))
    temp = eth_reg[word(ETH_808)];
    printf("READ 808: 0x%08X\n", temp);
    temp &= ~0x1F;
    temp |= 0x01;
    eth_reg[word(ETH_808)] = temp;
    printf("WRITE 808: 0x%08X\n", temp);

    // 0x03009800[2] = 0x0905 (rg_ephy_dig_rst_n=1, reset release, other keep default)
    temp = eth_reg[word(ETH_800)];
    printf("READ 800: 0x%08X\n", temp);
    temp = 0x0905;
    eth_reg[word(ETH_800)] = temp;
    printf("WRITE 808: 0x%08X\n", temp);
    
    // Delay 10us
    usleep(10);

    // 0x0300907C[12:8]= 5'b00101 (page_sel_mode0 = page 5)
    temp = eth_reg[word(ETH_07C)];
    printf("READ 07C: 0x%08X\n", temp);
    temp &= ~(0x1F << 8);
    temp |= (0x05 << 8);
    eth_reg[word(ETH_07C)] = temp;
    printf("WRITE 07C: 0x%08X\n", temp);
    
    // 0x03009078[11:0] = 0xF00 (set to gpio from top)
    temp = eth_reg[word(ETH_078)];
    printf("READ 078: 0x%08X\n", temp);
    temp &= ~0xFFF;
    temp |= 0xF00;
    eth_reg[word(ETH_078)] = temp;
    printf("WRITE 078: 0x%08X\n", temp);

    // 0x03009074[10:9 2:1]= 0x606 (set ephy rxp&rxm input&output enable)
    temp = eth_reg[word(ETH_074)];
    printf("READ 074: 0x%08X\n", temp);
    temp |= 0x606;
    eth_reg[word(ETH_074)] = temp;
    printf("WRITE 074: 0x%08X\n", temp);

    // 0x03009070[10:9 2:1]= 0x606 (set ephy rxp&rxm input&output enable)
    temp = eth_reg[word(ETH_070)];
    printf("READ 070: 0x%08X\n", temp);
    temp |= 0x606;
    eth_reg[word(ETH_070)] = temp;
    printf("WRITE 070: 0x%08X\n", temp);

    // Unmap memory
    munmap(reg_map, 4096);

    // Close /dev/mem
    close(mem_fd);

    return 0;
}

Just build this with the duo-examples SDK, upload it and run prior to using aplay . You can probably pull these register writes into the board_init.c code too.

4 Likes

Thank you, guys, for your great work!

2 Likes

Nice - got some Jean-Michel Jarre going there!

1 Like

I tried putting those register writes into the u-boot-2021.10/board/cvitek/cv180x/board.c file using the same format that LZ did and it didn’t work - I still had to do the memdev writes from userspace. I suspect that something in the kernel is overwriting the settings that u-boot applied, or else the code isn’t being invoked due to config macros not being set right. Will try some more variations.

1 Like

Well done.

I will test tonight.

I have previously attempted to remove the setting of eth_phy in board. c, which caused SSH to fail to run.

It seems that setting mmap in userspace will not affect ssh.
Is that right?

That is correct - the pin settings from userspace did not interfere with proper operation of USB RNDIS and I could still SSH and ping the milkv-duo after running that prog from the cmd line.

I notice that I did set the CONFIG_SND_SOC_CV1835_MAX98357A in the defconfig so I’m not sure why adding the reg writes to the board file didn’t work.

1 Like

Did you try putting the i2s setting at the end of the eth_phy initialization function?

I tried to remove the configuration of eth_phy, which caused SSH to fail.

My previous register settings did not set an offset of 7C, and I have not tried the correct one yet.

Here’s what I have:

diff --git a/u-boot-2021.10/board/cvitek/cv180x/board.c b/u-boot-2021.10/board/cvitek/cv180x/board.c
index bfd1061b1..44658592b 100644
--- a/u-boot-2021.10/board/cvitek/cv180x/board.c
+++ b/u-boot-2021.10/board/cvitek/cv180x/board.c
@@ -157,6 +157,34 @@ void pinmux_config(int io_type)
 
 #include "../cvi_board_init.c"
 
+#if defined(CONFIG_SND_SOC_CV1835_MAX98357A)
+/*
+0x03009804[0] = 1'b1 (rg_ephy_apb_rw_sel=1, use apb interface)
+0x03009808[4:0] = 5'b00001 (rg_ephy_pll_stable_cnt[4:0] = 5'd1 (10us)
+0x03009800[2] = 0x0905 (rg_ephy_dig_rst_n=1, reset release, other keep default)
+wait 10us
+0x0300907C[12:8]= 5'b00101 (page_sel_mode0 = page 5)
+0x03009078[11:0] = 0xF00 (set to gpio from top)
+0x03009074[10:9 2:1]= 0x606 (set ephy rxp&rxm input&output enable)
+0x03009070[10:9 2:1]= 0x606 (set ephy rxp&rxm input&output enable)
+*/
+static void cv180x_i2s2_init(void)
+{
+       printk("cv180x_i2s2_init\n");
+       mmio_write_32(0x03009804, 0x0001);
+       mmio_write_32(0x03009808, 0x0001);
+       mmio_write_32(0x03009800, 0x0905);
+
+       // Wait PLL_Lock, Lock_Status p5.0x12@[15] = 1
+       mdelay(1);
+
+       mmio_write_32(0x0300907C, 0x0500);
+       mmio_write_32(0x03009078, 0x0F00);
+       mmio_write_32(0x03009074, 0x0606);
+       mmio_write_32(0x03009070, 0x0606);
+}
+#endif
+
 #if defined(CONFIG_PHY_CVITEK)
 static void cv180x_ephy_id_init(void)
 {
@@ -219,6 +247,10 @@ int board_init(void)
        cv180x_ephy_led_pinmux();
 #endif
 
+#if defined(CONFIG_SND_SOC_CV1835_MAX98357A)
+       cv180x_i2s2_init();
+#endif
+
 #if defined(CONFIG_NAND_SUPPORT)
        pinmux_config(PINMUX_SPI_NAND);
 #elif defined(CONFIG_SPI_FLASH)

which appears to do the I2S setup after the eth setup.

1 Like

Yes i know that soundtrack all tooo well also

1 Like

There are various samples of WAV files here:

http://www0.cs.ucl.ac.uk/teaching/GZ05/samples/

1 Like

Hi Emeb

Great, your code can successfully convert gpio function from ETH to i2s.

I would like to organize the complete process of i2s development in another post.

Would you mind including your code? And I will make a note that it comes from you.

thanks~

LangZhao - sounds like a good idea. Feel free to use any of the material I’ve posted as you organize a complete process. Let me know if you need anything else from me.

Thanks, I have created a topic.
[duo256m]Add max98357a sound card - Duo - MilkV Community

I will paste your code later and link to you, I only put one link before.

1 Like

The other thing I want to do is add support for the I2S input pin. I suspect that would need a different kind of driver C file. I’ll have to study some other audio driver code to know how to do that.

Similar to adding a speaker, the main difference is the sound card driver, which is also the focus.

  1. sound card driver ---- point
  2. dts
  3. Makefile & Kconfig

I have mx5207 i2s mic, but there doesn’t codec driver in kernel/sound/soc/codec.
I2S MEMS Microphone for Raspberry Pi (INMP441) — Maker Portal (makersportal.com)

You can find “SND_SOC_DAPM_MIC” in code.
But generally, there are codecs that include both speakers and microphones, and there are relatively few microphones that support i2s alone.

I will check if there is a driver for MX5207, and if so, I will reply to you.

1 Like