Pillgram::Audio: Difference between revisions
→TLV320AIC3110: Explanation |
m →Device Tree: Spacing |
||
Line 6: | Line 6: | ||
<syntaxhighlight/dts-v1/; | <syntaxhighlight/dts-v1/; | ||
/plugin/; | /plugin/; | ||
/ { | / { | ||
compatible = "brcm,bcm2712", "brcm,bcm2711", "brcm,bcm2835"; | compatible = "brcm,bcm2712", "brcm,bcm2711", "brcm,bcm2835"; | ||
// compatible = "brcm,bcm2835"; | // compatible = "brcm,bcm2835"; | ||
fragment@0 { | fragment@0 { | ||
target = <&i2s_clk_consumer>; | target = <&i2s_clk_consumer>; | ||
Line 20: | Line 20: | ||
}; | }; | ||
}; | }; | ||
fragment@1 { | fragment@1 { | ||
target-path = "/"; | target-path = "/"; | ||
__overlay__ { | __overlay__ { | ||
status = "okay"; | status = "okay"; | ||
codec_1v8_reg: codec-1v8-reg { | codec_1v8_reg: codec-1v8-reg { | ||
compatible = "regulator-fixed"; | compatible = "regulator-fixed"; | ||
Line 43: | Line 43: | ||
#size-cells = <0>; /* No size cells for I2C devices */ | #size-cells = <0>; /* No size cells for I2C devices */ | ||
status = "okay"; | status = "okay"; | ||
tlv320aic3110: tlv320aic3110@18 { | tlv320aic3110: tlv320aic3110@18 { | ||
compatible = "ti-pg,tlv320aic3110", "ti,tlv320aic3110", "ti,tlv320aic311x"; | compatible = "ti-pg,tlv320aic3110", "ti,tlv320aic3110", "ti,tlv320aic311x"; | ||
Line 51: | Line 51: | ||
// system-clock-direction-out; // Codec as master | // system-clock-direction-out; // Codec as master | ||
status = "okay"; | status = "okay"; | ||
HPVDD-supply = <&vdd_3v3_reg>; | HPVDD-supply = <&vdd_3v3_reg>; | ||
SPRVDD-supply = <&vdd_5v0_reg>; | SPRVDD-supply = <&vdd_5v0_reg>; | ||
Line 58: | Line 58: | ||
IOVDD-supply = <&vdd_3v3_reg>; | IOVDD-supply = <&vdd_3v3_reg>; | ||
DVDD-supply = <&codec_1v8_reg>; | DVDD-supply = <&codec_1v8_reg>; | ||
clocks = <&mclk_external>; | clocks = <&mclk_external>; | ||
clock-names = "mclk"; | clock-names = "mclk"; | ||
Line 64: | Line 64: | ||
mclk-frequency = <12288000>; | mclk-frequency = <12288000>; | ||
// gpio-controller; | // gpio-controller; | ||
reset-gpios = <&gpio 13 1>; // GPIO 13 as active low reset | reset-gpios = <&gpio 13 1>; // GPIO 13 as active low reset | ||
reset-delay-us = <10000>; /* 10ms delay */ | reset-delay-us = <10000>; /* 10ms delay */ | ||
// Debug properties (must precede subnodes) | // Debug properties (must precede subnodes) | ||
debug; | debug; | ||
linux,debug; | linux,debug; | ||
}; | }; | ||
}; | }; | ||
}; | }; | ||
fragment@3 { | fragment@3 { | ||
target = <&sound>; | target = <&sound>; | ||
Line 85: | Line 85: | ||
simple-audio-card,convert-rate = <48000>; | simple-audio-card,convert-rate = <48000>; | ||
simple-audio-card,mclk-fs = <256>; | simple-audio-card,mclk-fs = <256>; | ||
simple-audio-card,bitclock-master = <&snd_codec>; | simple-audio-card,bitclock-master = <&snd_codec>; | ||
simple-audio-card,frame-master = <&snd_codec>; | simple-audio-card,frame-master = <&snd_codec>; | ||
simple-audio-card,widgets = | simple-audio-card,widgets = | ||
"Microphone", "Mic Jack", | "Microphone", "Mic Jack", | ||
Line 97: | Line 97: | ||
"MIC1LP", "Mic Jack", | "MIC1LP", "Mic Jack", | ||
"MIC1LM", "Mic Jack"; | "MIC1LM", "Mic Jack"; | ||
status = "okay"; | status = "okay"; | ||
dailink0_master: simple-audio-card,cpu { | dailink0_master: simple-audio-card,cpu { | ||
sound-dai = <&i2s_clk_consumer>; | sound-dai = <&i2s_clk_consumer>; | ||
Line 105: | Line 105: | ||
dai-tdm-slot-width = <32>; | dai-tdm-slot-width = <32>; | ||
}; | }; | ||
snd_codec: simple-audio-card,codec { | snd_codec: simple-audio-card,codec { | ||
sound-dai = <&tlv320aic3110>; | sound-dai = <&tlv320aic3110>; | ||
Line 115: | Line 115: | ||
}; | }; | ||
}; | }; | ||
fragment@4 { | fragment@4 { | ||
target-path = "/"; | target-path = "/"; | ||
Line 129: | Line 129: | ||
}; | }; | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== Explanation == | == Explanation == | ||
After carefully reading the source code, I finally found the culprit of my issues. Even if the datasheet suggest I can bypass the PLL if use a proper frequency for MCLK (I chose 12.288Mhz and 11.2896Mhz which divided by 256 gives 48Khz and 41.1Khz), the device driver does not support any arbitrary frequency! They have a bunch of lookup tables for clock rates and playback and if your choice is not present, the driver will fail. | After carefully reading the source code, I finally found the culprit of my issues. Even if the datasheet suggest I can bypass the PLL if use a proper frequency for MCLK (I chose 12.288Mhz and 11.2896Mhz which divided by 256 gives 48Khz and 41.1Khz), the device driver does not support any arbitrary frequency! They have a bunch of lookup tables for clock rates and playback and if your choice is not present, the driver will fail. |
Revision as of 20:45, 20 January 2025
TLV320AIC3110
Schematics
Device Tree
<syntaxhighlight/dts-v1/; /plugin/;
/ {
compatible = "brcm,bcm2712", "brcm,bcm2711", "brcm,bcm2835"; // compatible = "brcm,bcm2835"; fragment@0 { target = <&i2s_clk_consumer>; __overlay__ { status = "okay"; #sound-dai-cells = <0>; brcm,tx-channels = <2>; brcm,rx-channels = <1>; }; }; fragment@1 { target-path = "/"; __overlay__ { status = "okay"; codec_1v8_reg: codec-1v8-reg { compatible = "regulator-fixed"; regulator-name = "tlv320aic3104_1v8"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; regulator-always-on; status = "okay"; }; }; }; fragment@2 { target = <&i2c1>; __overlay__ { #address-cells = <1>; /* Single cell for I2C address */ #size-cells = <0>; /* No size cells for I2C devices */ status = "okay"; tlv320aic3110: tlv320aic3110@18 { compatible = "ti-pg,tlv320aic3110", "ti,tlv320aic3110", "ti,tlv320aic311x"; reg = <0x18>; #sound-dai-cells = <0>; // system-clock-frequency = <12288000>; // Codec clock config // system-clock-direction-out; // Codec as master status = "okay"; HPVDD-supply = <&vdd_3v3_reg>; SPRVDD-supply = <&vdd_5v0_reg>; SPLVDD-supply = <&vdd_5v0_reg>; AVDD-supply = <&vdd_3v3_reg>; IOVDD-supply = <&vdd_3v3_reg>; DVDD-supply = <&codec_1v8_reg>; clocks = <&mclk_external>; clock-names = "mclk"; // system-clk-frequency = <12288000>; mclk-frequency = <12288000>; // gpio-controller; reset-gpios = <&gpio 13 1>; // GPIO 13 as active low reset reset-delay-us = <10000>; /* 10ms delay */ // Debug properties (must precede subnodes) debug; linux,debug; }; }; }; fragment@3 { target = <&sound>; __overlay__ { compatible = "simple-audio-card"; i2s-controller = <&i2s_clk_consumer>; simple-audio-card,name = "TLV320AIC3110"; simple-audio-card,format = "i2s"; simple-audio-card,convert-rate = <48000>; simple-audio-card,mclk-fs = <256>; simple-audio-card,bitclock-master = <&snd_codec>; simple-audio-card,frame-master = <&snd_codec>; simple-audio-card,widgets = "Microphone", "Mic Jack", "Speaker", "External Speaker"; simple-audio-card,routing = "External Speaker", "SPL", "External Speaker", "SPR", "MIC1LP", "Mic Jack", "MIC1LM", "Mic Jack"; status = "okay"; dailink0_master: simple-audio-card,cpu { sound-dai = <&i2s_clk_consumer>; dai-tdm-slot-num = <2>; dai-tdm-slot-width = <32>; }; snd_codec: simple-audio-card,codec { sound-dai = <&tlv320aic3110>; clocks = <&mclk_external>; system-clock-direction-out = "out"; system-clock-frequency = <12288000>; //*** added LAX mclk-fs = <256>; //*** added LAX }; }; }; fragment@4 { target-path = "/"; __overlay__ { mclk_external: mclk_external { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <12288000>; // 12.288 MHz clock-output-names = "mclk"; }; }; };
}; </syntaxhighlight>
Explanation
After carefully reading the source code, I finally found the culprit of my issues. Even if the datasheet suggest I can bypass the PLL if use a proper frequency for MCLK (I chose 12.288Mhz and 11.2896Mhz which divided by 256 gives 48Khz and 41.1Khz), the device driver does not support any arbitrary frequency! They have a bunch of lookup tables for clock rates and playback and if your choice is not present, the driver will fail.
I modified the source code and added the proper lookups for my custom frequencies
Code: Select all
/* ADC dividers can be disabled by configuring them to 0 */ static const struct aic31xx_rate_divs aic31xx_divs[] = { ... /* 11.2896 MHz (11289600 Hz) */ { 11289600, 44100, 1, 7, 6800, 128, 8, 2, 128, 8, 2}, /* 12.288 MHz (12288000 Hz) */ { 12288000, 44100, 1, 7, 5264, 128, 8, 2, 128, 8, 2}, /* 11.2896 MHz (11289600 Hz) */ { 11289600, 48000, 1, 7, 6800, 128, 8, 2, 128, 8, 2}, /* 12.288 MHz (12288000 Hz) */ { 12288000, 48000, 1, 8, 1920, 128, 8, 2, 128, 8, 2},
After a fun fight with Ubuntu to compile this, lo and behold, everything plays!
Now for my project which involves an Iot device, I don't want to have to include an unsigned device driver that will need DKMS to install with every kernel update, I will redo my PCB hardware oscillator to use a natively supported frequency. I leave as an exercise to the people at TI to write a function that dynamically creates a lookup entry for a random frequency MCLK and playback combo!