Device tree for I2S0 on Hikey 960

I am trying to use I2S0 on the Hikey 960. From the hikey schematics, I see I2S0 being connected to the low speed header.

I want to use I2S0 to interface with the following MIC and Speaker:
MIC: https://www.tindie.com/products/onehorse/ics43434-i2s-digital-microphone/
Speaker: Overview | Adafruit MAX98357 I2S Class-D Mono Amp | Adafruit Learning System

The dts for hikey 960 (hi3660.dtsi) does not have any entry for i2s0. The essential part is as follows:

I know to make the I2S0 work, I will have to add a device node for I2S0. My question is related to the sound device node. Right now the sound device node is assuming one dai link. If I understand it correctly, each I2S is a dai link. The dai link also has to mention the cpu and the codec. In the setup I want, I will have two external codecs, one for MIC and one for speaker. My question is that will I have to create two dai links for the MIC and speaker codecs (something like shows below), or they somehow need to be put together in one dai link ?

    sound {
        compatible = "simple-audio-card"; 
        simple-audio-card,name = "<I will fill this>";

        simple-audio-card,dai-link@0 {        /* I2S2 */
            format = "i2s";
            bitclock-master = <&sound_i2s2>;
            frame-master = <&sound_i2s2>
            sound_i2s2: cpu {
                sound-dai = <&i2s2>;
            };
            codec {
                sound-dai = <&adv7533>;
            };
        };

        simple-audio-card,dai-link@1 {        /* I2S0 + MIC */
            format = "i2s";
            bitclock-master = <&sound_i2s0_1>;
            frame-master = <&sound_i2s0_1>;
            cpu {
                sound-dai = <&i2s0>;
            };
            sound_i2s0_1: codec {
                sound-dai = <&max98357a>;
            };
        };

        simple-audio-card,dai-link@2 {        /* I2S0 + Speaker */
            format = "i2s";
            bitclock-master = <&sound_i2s0_2>;
            frame-master = <&sound_i2s0_2>;
            cpu {
                sound-dai = <&i2s0>;
            };
            sound_i2s0_2: codec {
                sound-dai = <&ics43432>;
            };
        };
    };

Thank you.

One dai can handle multiple streams. Both of your devices are dumb devices, so you don’t need to specify hardware specific codecs for them (i.e. max98357a and ics43432), just use a single dummy codec that has both input and output.

Use sound/soc/codecs/bt-soc.c as a pattern – change sample rate and channel count to match your hardware. If you can figure out how to set the hikey960 to MONO, let me know. I’m using a kludge to convert a stereo stream with a blank second channel into a mono stream in userspace.

And presumably you already noticed that the voltage of those devices does not match the SBC, so level shifter and a 3.3v regulator.

1 Like

I have a follow up to my question. I am trying to see what all configuration is needed for making audio in/out work using I2S0 on Hikey960 (I think this is SIO_AUDIO in ASP). I did check ALSA documentation since I’m new to ALSA ( ALSA SoC Layer — The Linux Kernel documentation )

My guess is that platform and machine driver should be there in the kernel. For the codec drivers, the hikey kernel has drivers for max98357a speaker and ics43432 MIC. Wrt the dts entries, device node entry is missing for i2s0 and dai link missing under sound node. You already suggested a way to handle the dai link part.
For creating the I2S0 entry, assume I can set right dma channel numbers, reg addresses, and pinmux control (if you know the dma channel numbers and reg addresses, please let me know. It would be very helpful).

I have two questions:

  1. For I2S0 device node entry in hi3660.dtsi, can I use the same I2S driver (sound/soc/hisilicon/hisi-i2s.c) that I2S2 device node is matching to (“hisi-i2s”). My hypothesis is that the same driver may work, but I’m not sure. I may have to assign unique name for the I2S0 dai for structures ‘struct snd_soc_dai_driver hisi_i2s_dai_init’ and ‘struct snd_soc_component_driver hisi_i2s_i2s_comp’.

  1. Apart from the above (wrt ALSA) is there any other configuration needed to make audio work using I2S0 which is on low speed header for Hikey960 ? My goal is to make the audio work using peripherals mentioned before so that the Audio HAL Linaro has provided for Android (based on tinyALSA) can interact with I2S0 audio codecs.

Thank you for your time.

Hi, All:

Is there any update for I2S0 use?
I’m also trying to enable i2s0. But I trace dtsi setting.
Below’s I2S2 setting
i2s2: hisi_i2s {
compatible = “hisilicon,hisi-i2s”;
reg = <0x0 0xe804f800 0x0 0x400>,
<0x0 0xe804e000 0x0 0x400>;
pinctrl-names = “default”;
pinctrl-0 = <&i2s2_pmx_func &i2s2_cfg_func>;
dmas = <&asp_dmac 18 &asp_dmac 19>;
dma-names = “rx”, “tx”;
#sound-dai-cells = <0>;
};

From my understanding, If I want to enbale i2s0, the IORESOURCE_MEM must be difference with I2S0
i2s0: hisi_i2s {
compatible = “hisilicon,hisi-i2s”;
reg = <0x0 0xe804f800 0x0 0x400>,
<0x0 0xe804e000 0x0 0x400>;
pinctrl-names = “default”;
pinctrl-0 = <&i2s2_pmx_func &i2s2_cfg_func>;
dmas = <&asp_dmac 18 &asp_dmac 19>;
dma-names = “rx”, “tx”;
#sound-dai-cells = <0>;
};

I also want to connect I2C/I2S external codec to test AAudio. If possible, I’ll modify AudioHAL also.
But now I cannot find how-to add i2s0 devicetree. The SOC user manual don’t describe any information for register mapping like I2s0.

0xe804f800 in your i2s2 config is SOC_ACPU_SIO_BT_BASE_ADDR
and 0xe804e000 is SOC_ACPU_ASP_CFG_BASE_ADDR.
For i2s0 you may need to change the first one to
SOC_ACPU_SIO_AUDIO_BASE_ADDR=0xE804F000
Can’t provide an immediate answer for the MUX and CFG settings.
The SOC user manual is heavily censored, but Huawei has released (with veery looong delay) the code dump of Linux kernel source code for their hi3660-based smartphones. These addresses are taken from
Code_Opensource/kernel/drivers/hisi/ap/platform/hi3660/soc_acpu_baseaddr_interface.h, and it will be cool to create a table for all “censored” interfaces (also as seen through IOMCU/LPMCU/OCBC) in some kind of wiki.

Hi, Helg:

Thx for the answer. I’ll try to bind the I2S0 to snd-soc-dummy to test the i2s signal.

I have checked the source code and i2s0_pmx_func, i2s0_cfg_func are already available in hikey960-pinctrl.dtsi
The dmas = <&asp_dmac 18 &asp_dmac 19>; is for ASP DMA Channel 9, so you should use another channel (?)

#define SOC_ASP_DMAC_CH_PRI_ch9_pri_START (18)
#define SOC_ASP_DMAC_CH_PRI_ch9_pri_END (19)

Anyway, Linaro should really do us a favor and use non-obfuscated names in the DTS.

Hi, Helg:

I try to check the definitions for SOC_ASP_DMAC_CH.

I found it’s defined in soc_asp_dmac_interface.h. But it’s for hi6250 Mate P9 Lite.
For Hi3660, is it the same???

Hi, Helg:

I'll try to choose another one that doesn't be used.

If any update, I’ll let you know.

“Mate P9 Lite” does not exist. There are “P9 Lite” which uses hi6250, “Mate 9” and “P9” which use hi3660. I was referring to the “Mate 9” kernel source code (didn’t look at “P9”, but it should be very similar).
Since I2S2 is already working, you can also try to move it from CH9 to another one (there should be 16 ASP DMA channels)

Hi, Helg:

Currently, my configuration is like as below
kernel dtsi

  1. Add i2c/i2s codec into i2c device list
    ex. xxxx is my codec device

  2. Add I2S0 on sound card
    i2s0: hisi_i2s0 {
    compatible = “hisilicon,hisi-i2s”;
    reg = <0x0 0xe804f000 0x0 0x400>,
    <0x0 0xe804e000 0x0 0x400>;
    pinctrl-names = “default”;
    pinctrl-0 = <&i2s0_pmx_func &i2s0_cfg_func>;
    dmas = <&asp_dmac 30 &asp_dmac 31>;
    dma-names = “rx”, “tx”;
    #sound-dai-cells = <0>;
    };

             sound {
                     compatible = "simple-audio-card";
                     simple-audio-card,name = "hikey-hdmi";
    
                     simple-audio-card,dai-link@0 {
                             format = "i2s";
    
                             bitclock-master = <&sound_master>;
                             frame-master = <&sound_master>;
    
                             sound_master: cpu {
                                     sound-dai = <&i2s2>;
                             };
    
                             codec {
                                     sound-dai = <&adv7533>;
                             };
                     };
    
                     simple-audio-card,dai-link@1 {
                             format = "i2s";
    
                             bitclock-master = <&sound_master0>;
                             frame-master = <&sound_master0>;
    
                             sound_master0: cpu {
                                     sound-dai = <&i2s0>;
                             };
    
                             codec {
                                     sound-dai = <&xxxxx>;
                             };
                     };
             };
    
  3. tinyplay for test
    hikey960:/ # tinyplay /sdcard/Music/1khz_stereo_sinwave.wav -D 0 -d 0
    Playing sample: 2 ch, 48000 hz, 16 bit
    hikey960:/ # tinyplay /sdcard/Music/1khz_stereo_sinwave.wav -D 0 -d 1
    Playing sample: 2 ch, 48000 hz, 16 bit
    Error playing sample
    hikey960:/ #

  4. Another try for i2s0 dma channel is also the same.
    I have tried dma channel 0/8/10/15 for the experiment. the result is the same as (3).

Could you give me some instruction to enable i2s0???
From my experiment, I2S2 for hdmi work well, but the same setting for I2S0, the result is bad.

Your .dts looks good to me. Doing such lowlevel debugging is a hard task without the proper CPU manual :wink: I don’t see SIO being blocked by the BL1 TZPC code at the first glimpse (full bitmask names are available in the Mate 9 headers). Since you don’t use the sound codec, then some missing power/enable GPIO is also not the problem. I will try to check if xloader is messing with the TZPC settings.

Hi , Greg:

Thx. I’ll wait for your feedback.

hisi-i2s.c driver clearly says that

 * This driver only deals with S2 interface (BT)

so you should step through the headers of hikey960’s big brother Mate9, and replace everything bt-specific by audio-specific. Let’s take these 3 code lines as an example

/* deassert reset on sio_bt*/
hisi_syscon_bits(i2s, HI_ASP_CFG_R_RST_CTRLDIS_REG, 0,BIT(2)|BIT(6)|BIT(8)|BIT(16));
/* enable clk before frequency division */
hisi_syscon_bits(i2s, HI_ASP_CFG_R_GATE_EN_REG, 0,BIT(5)|BIT(6));
/* enable frequency division */
hisi_syscon_bits(i2s, HI_ASP_CFG_R_GATE_CLKDIV_EN_REG, 0,BIT(2)|BIT(5));

BIT2,BIT6,BIT8,BIT16 in the first line are rst_sio_bt_n, rst_ipc_n, rst_dmac_n,rst_gpio_n.
Replace BIT2 by BIT0 (rst_sio_audio).
BIT5,BIT6 in the second line are gt_btbclk_out,gt_siobt.
Replace by BIT1,BIT2 (gt_audiobclk_out,gt_sioaudio)
BIT2,BIT5 in the third line are gt_siobclk_div,gt_sio_bt_bclk_div.
Replace BIT5 by BIT3(gt_sio_audio_bclk_div).
And so on.

Hi, Helg:
OK, about the header text, maybe I forget to read it.
I’ll rewrite a driver named hisi-i2s-ap.c to overwrite the bit setting that you said.
Any update, I’ll let you know. Thanks for your support.

A closer inspection of the huawei smartphone kernel code shows that hi3660 has a block of 4 SIO ports (i2s0=audio, i2s1=voice, i2s2=bt, i2s3=modem). You should also read the I2S topics for Hikey: they do not help with the numbers for hi3660, but let you follow the design logic of the hisilicon engineers.

Hi, Helg:

Can you describe it more detailed?
I have copied hisi-i2s.h/.c to files name hisi-i2s-ap.h/.c to overwrite the setting for the three lines.
But it seems not enough. tinyplay result still shows

hikey960:/ # tinyplay /sdcard/Music/1khz_stereo_sinwave.wav -D 0 -d 1
Playing sample: 2 ch, 48000 hz, 16 bit
Error playing sample
hikey960:/ #

The dma channel I use for hisi-i2s-ap is

              i2s0: hisi_i2s0 {
                    compatible = "hisilicon,hisi-i2s-ap";
                    reg = <0x0 0xe804f000 0x0 0x400>,
                          <0x0 0xe804e000 0x0 0x400>;
                    pinctrl-names = "default";
                    pinctrl-0 = <&i2s0_pmx_func &i2s0_cfg_func>;
                    dmas = <&asp_dmac 14 &asp_dmac 15>;
                    dma-names = "rx", "tx";
                    #sound-dai-cells = <0>;
            };

You can follow the below link to check hisi-i2s-ap.h .c files.
hisi-i2s-ap.h
hisi-i2s-ap.c

I can’t test it myself because i don’t have any codec connected to I2S0 out, and using oscilloscope is too much effort for me.
Even if everything else is OK, the DMA channel use will be pure guesswork.

Use ‘strace’ to check where it fails.

Hi, Helg:

By the way, if you can use the oscilloscope, maybe I can deliver you a patch for binding i2s0 to dummy codec.
I think the real codec is not necessary.

strace log can be found at the below link
strace_log.txt

Without a real I2S mezzanine this will remain a pure intellectual exercise.