|
|
| Line 1: |
Line 1: |
| = TLV320AIC3110 = | | == Summary == |
| == Schematics ==
| | Importing file |
| [[File:Tlv320aic3110-schematics-copyright.png|thumb]]
| |
| | |
| == 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!
| |