From 8607306d50e56a6a18b757f5373d5ecd9dd1e565 Mon Sep 17 00:00:00 2001
From: Stephen Gordon <gordoste@iinet.net.au>
Date: Thu, 27 Feb 2025 22:01:41 +1100
Subject: [PATCH] Backport support for ezsound 6x8 soundcard to 6.6.y

Signed-off-by: Stephen Gordon <gordoste@iinet.net.au>
---
 .../bindings/sound/ti,pcm3168a.yaml           |   8 ++
 arch/arm/boot/dts/overlays/Makefile           |   1 +
 arch/arm/boot/dts/overlays/README             |   6 +
 .../dts/overlays/ezsound-6x8iso-overlay.dts   | 117 ++++++++++++++++++
 arch/arm64/configs/bcm2712_defconfig          |   1 +
 sound/soc/codecs/pcm3168a.c                   |  12 ++
 6 files changed, 145 insertions(+)
 create mode 100644 arch/arm/boot/dts/overlays/ezsound-6x8iso-overlay.dts

diff --git a/Documentation/devicetree/bindings/sound/ti,pcm3168a.yaml b/Documentation/devicetree/bindings/sound/ti,pcm3168a.yaml
index b6a4360ab845dd..6acc22364fa0ac 100644
--- a/Documentation/devicetree/bindings/sound/ti,pcm3168a.yaml
+++ b/Documentation/devicetree/bindings/sound/ti,pcm3168a.yaml
@@ -58,6 +58,14 @@ properties:
   VCCDA2-supply:
     description: DAC power supply regulator 2 (+5V)
 
+  adc-force-cons:
+    description: Force ADC to operate in consumer mode. Useful if ADC and DAC
+      clock pins are tied together with DAC as producer.
+
+  dac-force-cons:
+    description: Force DAC to operate in consumer mode. Useful if ADC and DAC
+      clock pins are tied together with ADC as producer.
+
   ports:
     $ref: audio-graph-port.yaml#/definitions/port-base
     properties:
diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile
index 272717f6d01db5..595a8991b46e7c 100644
--- a/arch/arm/boot/dts/overlays/Makefile
+++ b/arch/arm/boot/dts/overlays/Makefile
@@ -64,6 +64,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
 	enc28j60.dtbo \
 	enc28j60-spi2.dtbo \
 	exc3000.dtbo \
+	ezsound-6x8iso.dtbo \
 	fbtft.dtbo \
 	fe-pi-audio.dtbo \
 	fsm-demo.dtbo \
diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README
index 820af14f58cfd4..0b69aeb997fca7 100644
--- a/arch/arm/boot/dts/overlays/README
+++ b/arch/arm/boot/dts/overlays/README
@@ -1284,6 +1284,12 @@ Params: interrupt               GPIO used for interrupt (default 4)
         swapxy                  Touchscreen swapped x y axis
 
 
+Name:   ezsound-6x8iso
+Info:   Overlay for the ezsound 6x8 isolated soundcard.
+Load:   dtoverlay=ezsound-6x8iso
+Params: <None>
+
+
 Name:   fbtft
 Info:   Overlay for SPI-connected displays using the fbtft drivers.
 
diff --git a/arch/arm/boot/dts/overlays/ezsound-6x8iso-overlay.dts b/arch/arm/boot/dts/overlays/ezsound-6x8iso-overlay.dts
new file mode 100644
index 00000000000000..ac58be7039523f
--- /dev/null
+++ b/arch/arm/boot/dts/overlays/ezsound-6x8iso-overlay.dts
@@ -0,0 +1,117 @@
+//Device tree overlay for ezsound 6x8 isolated card
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2712";
+
+	fragment@0 {
+		target = <&rp1_i2s0_18_21>;
+		__overlay__ {
+			pins = "gpio18", "gpio19", "gpio20", "gpio22", "gpio24",
+			"gpio26", "gpio21", "gpio23", "gpio25", "gpio27";
+		};
+	};
+
+	fragment@1 {
+		target = <&rp1_i2s1_18_21>;
+		__overlay__ {
+			pins = "gpio18", "gpio19", "gpio20", "gpio22", "gpio24",
+			"gpio26", "gpio21", "gpio23", "gpio25", "gpio27";
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "simple-audio-card";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			i2s-controller = <&i2s_clk_consumer>;
+			status="okay";
+
+			simple-audio-card,name = "ezsound-6x8";
+
+			simple-audio-card,dai-link@0 {
+				reg = <0>;
+				format = "i2s";
+				bitclock-master = <&pcm3168_playback>;
+				frame-master = <&pcm3168_playback>;
+				cpu {
+					sound-dai = <&i2s_clk_consumer>;
+					dai-tdm-slot-num = <2>;
+					dai-tdm-slot-width = <32>;
+				};
+				pcm3168_playback: codec {
+					system-clock-fixed;
+					mclk-fs = <256>;
+					sound-dai = <&pcm3168a 0>;
+					dai-tdm-slot-num = <2>;
+					dai-tdm-slot-width = <32>;
+				};
+			};
+			simple-audio-card,dai-link@1 {
+				reg = <1>;
+				format = "i2s";
+				bitclock-master = <&pcm3168_capture>;
+				frame-master = <&pcm3168_capture>;
+				cpu {
+					sound-dai = <&i2s_clk_consumer>;
+					dai-tdm-slot-num = <2>;
+					dai-tdm-slot-width = <32>;
+				};
+				pcm3168_capture: codec {
+					system-clock-fixed;
+					mclk-fs = <256>;
+					sound-dai = <&pcm3168a 1>;
+					dai-tdm-slot-num = <2>;
+					dai-tdm-slot-width = <32>;
+				};
+			};
+		};
+	};
+
+	fragment@3 {
+		target-path = "/";
+		__overlay__ {
+			scki_clk: scki-clock {
+				compatible = "fixed-clock";
+				#clock-cells = <0>;
+				clock-frequency = <24576000>;
+			};
+		};
+	};
+
+	// Bring the I2S clock consumer block up
+	fragment@4 {
+		target = <&i2s_clk_consumer>;
+		__overlay__ {
+			#sound-dai-cells = <0>;
+			status = "okay";
+		};
+	};
+
+	fragment@5 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			pcm3168a: audio-codec@45 {
+				#sound-dai-cells = <1>;
+				compatible = "ti,pcm3168a";
+				status = "okay";
+				reg = <0x45>;
+				clocks = <&scki_clk>;
+				clock-names = "scki";
+				dac-force-cons;
+				VDD1-supply = <&vdd_3v3_reg>;
+				VDD2-supply = <&vdd_3v3_reg>;
+				VCCAD1-supply = <&vdd_5v0_reg>;
+				VCCAD2-supply = <&vdd_5v0_reg>;
+				VCCDA1-supply = <&vdd_5v0_reg>;
+				VCCDA2-supply = <&vdd_5v0_reg>;
+			};
+		};
+	};
+};
diff --git a/arch/arm64/configs/bcm2712_defconfig b/arch/arm64/configs/bcm2712_defconfig
index 3bdf65c72b403b..b3d2024b8ddc1c 100644
--- a/arch/arm64/configs/bcm2712_defconfig
+++ b/arch/arm64/configs/bcm2712_defconfig
@@ -1150,6 +1150,7 @@ CONFIG_SND_SOC_CS4265=m
 CONFIG_SND_SOC_ICS43432=m
 CONFIG_SND_SOC_MA120X0P=m
 CONFIG_SND_SOC_MAX98357A=m
+CONFIG_SND_SOC_PCM3168A_I2C=m
 CONFIG_SND_SOC_SPDIF=m
 CONFIG_SND_SOC_TLV320AIC23_I2C=m
 CONFIG_SND_SOC_WM8804_I2C=m
diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c
index 9d6431338fb715..f5125a7ba41776 100644
--- a/sound/soc/codecs/pcm3168a.c
+++ b/sound/soc/codecs/pcm3168a.c
@@ -61,6 +61,7 @@ struct pcm3168a_priv {
 	struct clk *scki;
 	struct gpio_desc *gpio_rst;
 	unsigned long sysclk;
+	bool adc_fc, dac_fc; // Force clock consumer mode
 
 	struct pcm3168a_io_params io_params[2];
 	struct snd_soc_dai_driver dai_drv[2];
@@ -479,6 +480,12 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
 		ms = 0;
 	}
 
+	// Force clock consumer mode if needed
+	if (pcm3168a->adc_fc && dai->id == PCM3168A_DAI_ADC)
+		ms = 0;
+	if (pcm3168a->dac_fc && dai->id == PCM3168A_DAI_DAC)
+		ms = 0;
+
 	format = io_params->format;
 
 	if (io_params->slot_width)
@@ -757,6 +764,11 @@ int pcm3168a_probe(struct device *dev, struct regmap *regmap)
 
 	pcm3168a->sysclk = clk_get_rate(pcm3168a->scki);
 
+	pcm3168a->adc_fc = of_property_read_bool(dev->of_node,
+       		"adc-force-cons");
+	pcm3168a->dac_fc = of_property_read_bool(dev->of_node,
+		"dac-force-cons");
+
 	for (i = 0; i < ARRAY_SIZE(pcm3168a->supplies); i++)
 		pcm3168a->supplies[i].supply = pcm3168a_supply_names[i];