[PATCH 5/5] arm64: dts: imx8mq-phanbell: Enable the rt5645 analog audio
Rudi Heitbaum
rudi at heitbaum.com
Fri Aug 7 06:32:44 PDT 2026
The board has an rt5645 on i2c3 driving the 3.5 mm headphone jack, its
microphone and two on-board DMICs, fed by sai2.
The vendor kernel drives this codec from a machine driver of its own,
"google,edgetpu-audio-card", so its devicetree carries no widgets or
routing and the graph here is rebuilt for simple-audio-card. micbias1 is a
supply widget, and a supply is the source of a route rather than its sink -
as rt5645's own { "IN1P", NULL, "LDO2" } has it - so the sink/source pair
is "Headphone Mic", "micbias1".
GPIO5_IO4 carries headphone detect. The pad has to be muxed away from its
reset function, or both hp-detect-gpios and the codec interrupt point at a
pad that is still SPDIF_RX. Leaving realtek,jd-mode unset selects the mode
in which the driver takes jack state from hp-detect-gpios.
The slot width is pinned at 32 bits. With none set fsl_sai_hw_params()
takes it from the sample width, so a 24 bit open asks for a bit clock of
48000 * 2 * 24 = 2.304 MHz; fsl_sai_set_bclk() only accepts even dividers
and 24.576 MHz / 2.304 MHz is 10.67, so hw_params returns -EINVAL. 32 bit
slots ask for 3.072 MHz, a ratio of 8, and still carry 16 bit at the same
clock: rt5645_hw_params() takes the data length from params_width() and
only writes a BCLK-to-frame ratio for AIF2, so on AIF1 the codec ignores
the padding bits.
Declare both audio PLL families. fsl_sai only moves its mclk between the
8 kHz and 11.025 kHz families if the node names them as pll8k and pll11k,
which fsl_asoc_reparent_pll_clocks() then selects between by requested
rate. Without them the mclk is stuck at whatever assigned-clock-rates set
while 44100 is still on the advertised rate list, so ALSA is offered a rate
the clock cannot produce, does not resample, and hw_params fails:
44100 * 2 * 32 = 2.8224 MHz, and 24.576 MHz divided by that is 8.707.
The cpu dai also needs system-clock-direction-out. Without it
simple_util_parse_clk() leaves clk_direction at 0, which is
SND_SOC_CLOCK_IN, and fsl_sai_set_dai_sysclk() opens with
"if (dir == SND_SOC_CLOCK_IN) return 0". So set_sysclk returns without
setting the mclk rate and without ever reaching the reparent, silently and
at every rate.
Signed-off-by: Rudi Heitbaum <rudi at heitbaum.com>
---
.../boot/dts/freescale/imx8mq-phanbell.dts | 84 +++++++++++++++++++
1 file changed, 84 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/imx8mq-phanbell.dts b/arch/arm64/boot/dts/freescale/imx8mq-phanbell.dts
index 2d134eefb765..b819e644fa54 100644
--- a/arch/arm64/boot/dts/freescale/imx8mq-phanbell.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mq-phanbell.dts
@@ -46,6 +46,41 @@ fan: gpio-fan {
pinctrl-0 = <&pinctrl_gpio_fan>;
status = "okay";
};
+
+ sound-analog {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "Coral Analog";
+ simple-audio-card,format = "i2s";
+ simple-audio-card,bitclock-master = <&sound_analog_cpu>;
+ simple-audio-card,frame-master = <&sound_analog_cpu>;
+ simple-audio-card,mclk-fs = <256>;
+
+ simple-audio-card,widgets = "Headphone", "Headphone Jack",
+ "Microphone", "Headphone Mic",
+ "Microphone", "Internal Mic";
+
+ simple-audio-card,routing = "Headphone Jack", "HPOL",
+ "Headphone Jack", "HPOR",
+ "Headphone Mic", "micbias1",
+ "DMIC L1", "Internal Mic",
+ "DMIC R1", "Internal Mic";
+
+ /*
+ * 32 bit slots regardless of the sample width. sai2 divides its
+ * 24.576 MHz root by an even integer only, so a 24 bit frame at
+ * 48 kHz would ask for 2.304 MHz, a ratio of 10.67.
+ */
+ sound_analog_cpu: simple-audio-card,cpu {
+ sound-dai = <&sai2>;
+ system-clock-direction-out;
+ dai-tdm-slot-num = <2>;
+ dai-tdm-slot-width = <32>;
+ };
+
+ simple-audio-card,codec {
+ sound-dai = <&rt5645>;
+ };
+ };
};
&A53_0 {
@@ -272,6 +307,18 @@ &i2c3 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c3>;
status = "okay";
+
+ rt5645: audio-codec at 1a {
+ compatible = "realtek,rt5645";
+ reg = <0x1a>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_hp_det>;
+ #sound-dai-cells = <0>;
+ interrupt-parent = <&gpio5>;
+ interrupts = <4 IRQ_TYPE_EDGE_BOTH>;
+ hp-detect-gpios = <&gpio5 4 GPIO_ACTIVE_HIGH>;
+ realtek,dmic1-data-pin = <2>;
+ };
};
&fec1 {
@@ -295,6 +342,27 @@ ethphy0: ethernet-phy at 0 {
};
};
+&sai2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sai2>;
+ /*
+ * pll8k and pll11k let fsl_sai move the mclk between the two
+ * audio PLL families, so 44.1 kHz rates work as well as 48 kHz.
+ */
+ clocks = <&clk IMX8MQ_CLK_SAI2_IPG>,
+ <&clk IMX8MQ_CLK_SAI2_ROOT>,
+ <&clk IMX8MQ_CLK_DUMMY>, <&clk IMX8MQ_CLK_DUMMY>,
+ <&clk IMX8MQ_AUDIO_PLL1_OUT>,
+ <&clk IMX8MQ_AUDIO_PLL2_OUT>;
+ clock-names = "bus", "mclk1", "mclk2", "mclk3",
+ "pll8k", "pll11k";
+ assigned-clocks = <&clk IMX8MQ_CLK_SAI2>;
+ assigned-clock-parents = <&clk IMX8MQ_AUDIO_PLL1_OUT>;
+ assigned-clock-rates = <24576000>;
+ fsl,sai-mclk-direction-output;
+ status = "okay";
+};
+
&uart1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart1>;
@@ -383,6 +451,12 @@ MX8MQ_IOMUXC_GPIO1_IO00_ANAMIX_REF_CLK_32K 0x05
>;
};
+ pinctrl_hp_det: hpdetgrp {
+ fsl,pins = <
+ MX8MQ_IOMUXC_SPDIF_RX_GPIO5_IO4 0xd6
+ >;
+ };
+
pinctrl_i2c1: i2c1grp {
fsl,pins = <
MX8MQ_IOMUXC_I2C1_SCL_I2C1_SCL 0x4000007f
@@ -410,6 +484,16 @@ MX8MQ_IOMUXC_GPIO1_IO03_GPIO1_IO3 0x41
>;
};
+ pinctrl_sai2: sai2grp {
+ fsl,pins = <
+ MX8MQ_IOMUXC_SAI2_MCLK_SAI2_MCLK 0xd6
+ MX8MQ_IOMUXC_SAI2_TXFS_SAI2_TX_SYNC 0xd6
+ MX8MQ_IOMUXC_SAI2_TXC_SAI2_TX_BCLK 0xd6
+ MX8MQ_IOMUXC_SAI2_TXD0_SAI2_TX_DATA0 0xd6
+ MX8MQ_IOMUXC_SAI2_RXD0_SAI2_RX_DATA0 0xd6
+ >;
+ };
+
pinctrl_uart1: uart1grp {
fsl,pins = <
MX8MQ_IOMUXC_UART1_RXD_UART1_DCE_RX 0x49
--
2.53.0
More information about the linux-arm-kernel
mailing list