DEV Community

moonlitpath
moonlitpath

Posted on • Edited on

Submitting a DT Schema Patch for Rockchip RK3399-GRU Sound — A Dev Journal

Note: The earlier parts of this series were part of my GSoC application for DT bindings. While I started this patch during that phase, I ended up submitting it afterward—so this became my first independent contribution to the community.


Mistake in previous patch
I realized that I had overlooked a major check in my first patch.. I hadn't checked for active users! And... turns out.. OLPC is quite an old device with minimal userbase..

How could I make such a crucial mistake? It seems I was so excited to start the last time, that I had forgotten to check whether the file has active users. Working on a file with active users doing so will actually benefit the community and be considered more meaningful. Old devices without active users can also be wrong, it's harder for the maintainers to manage such devices.


So this time around, I made sure to check whether this file has active users. To do that, we have to check whether this file has any active users that was built by arm64 defconfig.

The DT Binding that I chose to convert this time around was ROCKCHIP with MAX98357A/RT5514/DA7219 codecs on GRU boards.

This is the file:

ROCKCHIP with MAX98357A/RT5514/DA7219 codecs on GRU boards.

Required properties:
- compatible: "rockchip,rk3399-gru-sound"
- rockchip,cpu: The phandle of the Rockchip I2S controller that's
  connected to the codecs
- rockchip,codec: The phandle of the audio codecs

Optional properties:
- dmic-wakeup-delay-ms : specify delay time (ms) for DMIC ready.
  If this option is specified, which means it's required dmic need
  delay for DMIC to ready so that rt5514 can avoid recording before
  DMIC send valid data

Example:

sound {
        compatible = "rockchip,rk3399-gru-sound";
        rockchip,cpu = <&i2s0>;
        rockchip,codec = <&max98357a &rt5514 &da7219>;
        dmic-wakeup-delay-ms = <20>;
};
Enter fullscreen mode Exit fullscreen mode

To check if there are any active users, I search the compatible property in the above file to check if there's a .dtsi or .dts file available that uses my controller.

And..

anu@laptop:~/kernel-dev/source/linux$ git grep "rockchip,rk3399-gru-sound" -- arch/arm64
arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi:           compatible = "rockchip,rk3399-gru-sound";

Enter fullscreen mode Exit fullscreen mode

It is in use!

I checked lore, and didn't find anyone working on this file so, it's mine now~
I'll start working!


Understanding the hardware
Rockchip SoC (system on chip) processors are ARM-based processors commonly used in Chromebooks, Tablets, embedded systems, etc.

This device is the sound subsystem machine that orchestrates multiple codecs. It gives audio capabilities to Rockchip RK3399 SoC.

Rockchip RK3399 SoC by itself doesnt have audio capabilites. It has to be paired with external codecs, like Realtek codec, etc, in order to gain these capabilites.


Working on the code

A thing that I found useful while writing the code, was -- I first filled my empty yaml file with everything I was 100% sure of (like the header and compatible property) , and then slowly worked on towards the things I was unsure of, i.e the vendor properties.

Understanding the vendor properties

  1. rockchip,cpu: phandle of the Rockchip I2S controller
    I2S is standard audio protocol to send/recieve digital audio data between chips.
    So, this means that this property contains a pointer (phandle) to another device in the device tree - specifically I2S controller chip.

  2. rockchip,codec: phandle of the audio codecs
    it is a pointer (phandle) to the audio codec devices. The sound driver needs to know which codec is available and how to control them.

    Understanding the codecs

    • MAX98357A — Class D speaker amplifier (typically for built-in speakers)
    • RT5514 — Microphone codec (input path, often includes DSP for voice detection)
    • DA7219 — Full-featured audio codec (can do both input/output, often handles headphone/headset)

I started looking if the vendor properties that were defined here were already defined elsewhere, in which case, I should refer to those.

I used the search tool rg because I found it much faster than grep or git grep.

anu@laptop:~/kernel-dev/source/linux$ rg "rockchip,codec" Documentation/devicetree/bindings/ -t yaml
anu@laptop:~/kernel-dev/source/linux$ rg "rockchip,cpu" Documentation/devicetree/bindings/ -t yaml
Enter fullscreen mode Exit fullscreen mode

As the result shows, no. they weren't used before.

So, I decided to refer to a rockchip schema, Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.yaml here, there was a vendor property rockchip,grf defined.
I also opened the example schema to understand how to define such properties.

  rockchip,cpu:
    $ref: /schemas/types.yaml#/definitions/phandle
    description:
      The phandle of the Rockchip I2S controller that's connected to the codecs

  rockchip,codec:
    $ref: /schemas/types.yaml#/definitions/phandle-array
    description: The phandle of the audio codecsi
Enter fullscreen mode Exit fullscreen mode

to confirm the type, I had referred to the example given in my original DT binding txt file

rockchip,cpu = <&i2s0>;                          # <--- phandle
rockchip,codec = <&max98357a &rt5514 &da7219>;   # <---phandle-array
Enter fullscreen mode Exit fullscreen mode

Understanding the optional property
dmic-wakeup-delay-ms: specify delay time for DMIC ready
DMIC: Digital Microphone -- for the microphone codec (RT5514)
The DMIC requires a small amount of time after waking up to stabilize and start recording to produce valid audio data, else it can record garbage data.

So, this property tells that it's required for DMIC to wait for X ms before starting to record.

Thus, I checked out the dmic codec in Documentation/devicetree/bindings/sound/dmic-codec.yaml and checked out it's wakeup property.

I found this defined in that file:

  wakeup-delay-ms:
    description: Delay (in ms) after enabling the DMIC
Enter fullscreen mode Exit fullscreen mode

Searching for parent files for my schema

It seems that in the above code, this property does the same thing as the property I defined..
Does this file need to be inherited.. ?

so I searched for the files that had used the wakeup-delay-ms property, and I found:
Documentation/devicetree/bindings/sound/adi,adau7002.yaml

  wakeup-delay-ms:
    description:
      Delay after power up needed for device to settle.
Enter fullscreen mode Exit fullscreen mode

however.. for this file.. the dmic file wasnt included.. why?

So, I looked up this device:
ADAU7002 is Analog Devices' audio converter chip. It converts PDM (pulse density modulation) to I2S. It's a codec, but it's not a DMIC.

This means that their property having the same names.... means nothing.

Then I noticed something:
This property... it seemed to not be a core DT property since I had not seen it in the example-schema.yaml .. is this a clue?

Answer: no. it isn't. It's just a property. I had this concept in my internal mind that the referring to the parent properties (using allOf: $ref:) are somewhat like "inheritence" in OOPS. That is why I had thought that if a property has a same name, then it must be "imported" from another file. This is not the case at all.

A file being a parent simply means that along with the rules defined in the current schema, the DTS should also satisfy all the rules defined by the parent schema.
No inheritence, the OOP concepts have no relation to this concept.


Then, I noticed another thing, while going through similar files.
All the yaml schema files that I had checked from this folder seemed to inherit the dai-common.yaml
even the DT Binding converstion patch about Maxim integrated Audio Codec that I had analysed while learning about DT schemas had this file as a parent...

I had learnt at that time:
DAI = Digital Audio Interface
codec needs to handle separate i/o (mic, speaker, etc) -- so each device would have a separate DAI port

Does that mean my file will need it though?
My device just needs to orchestrate multiple codecs which will manage the DAI. I needn't do that.

i checked in the dtsi file with rockchip,rk3399-gru-sound keyword to find where my file is referenced, and no it does not reference any 'sound-dai-cells' property. This proves that I should not include it in my file.

it does however contains maxim,max98357a -- that refeneces the dai property, but that's a difference audio codec file. not related to me

sound: sound {
                compatible = "rockchip,rk3399-gru-sound";
                rockchip,cpu = <&i2s0 &spdif>;
        };
Enter fullscreen mode Exit fullscreen mode

thus my driver does not require the soudn dai property

now, i have to prevent the schema from allowing any extra properties, so i referred to example-schema.yaml

# Ideally, the schema should have this line otherwise any other properties
# present are allowed. There's a few common properties such as 'status' and
# 'pinctrl-*' which are added automatically by the tooling.
#   
# This can't be used in cases where another schema is referenced
# (i.e. allOf: [{$ref: ...}]).
# If and only if another schema is referenced and arbitrary children nodes can
# appear, "unevaluatedProperties: false" could be used.  A typical example is
# an I2C controller where no name pattern matching for children can be added.
additionalProperties: false

Enter fullscreen mode Exit fullscreen mode

Thus, I set additionalProperties: false

and done!

final file:

# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/rockchip,rk3399-gru-sound.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: ROCKCHIP with MAX98357A/RT5514/DA7219 codecs on GRU boards

maintainers:
  - Heiko Stuebner <heiko@sntech.de>

properties:
  compatible:
    const: rockchip,rk3399-gru-sound

  rockchip,cpu:
    $ref: /schemas/types.yaml#/definitions/phandle
    description:
      The phandle of the Rockchip I2S controller that's connected to the codecs

  rockchip,codec:
    $ref: /schemas/types.yaml#/definitions/phandle-array
    description: The phandle of the audio codecs

  dmic-wakeup-delay-ms:
    description:
      specify delay time (ms) for DMIC ready.
      If this option is specified, which means it's required dmic need
      delay for DMIC to ready so that rt5514 can avoid recording before
      DMIC sends valid data

required:
  - compatible
  - rockchip,cpu
  - rockchip,codec

additionalProperties: false

examples:
  - |
    sound {
      compatible = "rockchip,rk3399-gru-sound";
      rockchip,cpu = <&i2s0>;
      rockchip,codec = <&max98357a &rt5514 &da7219>;
      dmic-wakeup-delay-ms = <20>;
    };
Enter fullscreen mode Exit fullscreen mode

Testing

Now it's time to test it!

So, following the same steps as the last time,

I first test it against the core DT schema, to check if the binding is correct --

anu@laptop:~/kernel-dev/source/linux$ make -j8 dt_binding_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/sound/rockchip,rk3399-gru-sound.yaml
make[1]: Entering directory '/home/anu/kernel-dev/source/linux/out'
  SCHEMA  Documentation/devicetree/bindings/processed-schema.json
  CHKDT   ../Documentation/devicetree/bindings
  LINT    ../Documentation/devicetree/bindings
  DTEX    Documentation/devicetree/bindings/sound/rockchip,rk3399-gru-sound.example.dts
  DTC [C] Documentation/devicetree/bindings/sound/rockchip,rk3399-gru-sound.example.dtb
make[1]: Leaving directory '/home/anu/kernel-dev/source/linux/out'

Enter fullscreen mode Exit fullscreen mode

and it is!

now it's time to validate it against the specified dtb schema

(note: i had not been able to try this in the past file because that file had no DTB file for it..)

I tried this:

anu@laptop:~/kernel-dev/source/linux$ ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make CHECK_DTBS=y DT_SCHEMA_FILES=Documentation/devicetree/bindings/sound/rockchip,rk3399-gru-sound.yaml rockchip/rk3399-gru-kevin.dtb
***
*** Configuration file ".config" not found!
***
*** Please run some configurator (e.g. "make oldconfig" or
*** "make menuconfig" or "make xconfig").
***
/home/anu/kernel-dev/source/linux/Makefile:844: include/config/auto.conf.cmd: No such file or directory
make[1]: *** [/home/anu/kernel-dev/source/linux/Makefile:853: .config] Error 1
make: *** [Makefile:248: __sub-make] Error 2

Enter fullscreen mode Exit fullscreen mode

the reason was that I had not built a .config file using defconfig first.

for searching for the answer, I had referred this post by Krzysztof Kozlowski: https://www.linaro.org/blog/tips-and-tricks-for-validating-devicetree-sources-with-the-devicetree-schema/

first, I cleaned the directory. I hadn't done this at the start, and got an error while building in the next steps, where I was pointed to run make mrproper

anu@laptop:~/kernel-dev/source/linux$ make mrproper
make[1]: Entering directory '/home/anu/kernel-dev/source/linux/out'
  CLEAN   Documentation/devicetree/bindings
  CLEAN   scripts/basic
  CLEAN   scripts/dtc
make[1]: Leaving directory '/home/anu/kernel-dev/source/linux/out'
Enter fullscreen mode Exit fullscreen mode

I set up my environment

anu@laptop:~/kernel-dev/source/linux$ export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
export KBUILD_OUTPUT=out/
Enter fullscreen mode Exit fullscreen mode

this builds the .config file:

anu@laptop:~/kernel-dev/source/linux$ make defconfig
make[1]: Entering directory '/home/anu/kernel-dev/source/linux/out'
  GEN     Makefile
*** Default configuration is based on 'defconfig'
#
# configuration written to .config
#
make[1]: Leaving directory '/home/anu/kernel-dev/source/linux/out'

Enter fullscreen mode Exit fullscreen mode

now for this step, I had run a full make dtbs_check.. however it took a lot of time, almost 20 mins to finish.

when I first ran this command, I got this error:

$ ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make CHECK_DTBS=y 
DT_SCHEMA_FILES=Documentation/devicetree/bindings/sound/rockchip,rk3399-gru-sound.yaml rockchip/rk3399-gru-kevin.dtb DTC 
[C] arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dtb 
/home/anu/kernel-dev/source/linux/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dtb:
sound (rockchip,rk3399-gru-sound): 
rockchip,cpu:0: [211, 212] is too long from schema $id: http://devicetree.org/schemas/sound/rockchip,rk3399-gru-sound.yaml
Enter fullscreen mode Exit fullscreen mode

look at this part:

rockchip,cpu:0: [211, 212] is too long from schema $id: 
Enter fullscreen mode Exit fullscreen mode

this means that the property rockchip,cpu should be a phandle-array and not a phandle, that I had set it to.

So, I went to the DT Schema, changed it and ran make dtbs_check again.
This time, it passed.
make[1]: Leaving directory '/home/anu/kernel-dev/source/linux/out'

make dtbs_check had taken way too much time the last time around. Now, I decided to test it against a dtb file.

When I had searched for the dts file before to find active users, there was a .dtsi file, but no .dts file.
it was this one: arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi

so, i decided to see whether there are any dts files that import this dtsi file.

anu@laptop:~/kernel-dev/source/linux$ rg "rk3399-gru.dtsi"
arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi
8:#include "rk3399-gru.dtsi"

arch/arm64/boot/dts/rockchip/rk3399-gru-chromebook.dtsi
8:#include "rk3399-gru.dtsi"
248:     * set this here, because rk3399-gru.dtsi ensures we can generate this
Enter fullscreen mode Exit fullscreen mode

and I found.. 2 more .dtsi files.. I didn't give up and kept digging

anu@laptop:~/kernel-dev/source/linux$ rg "rk3399-gru-scarlet.dtsi"
arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet-kd.dts
10:#include "rk3399-gru-scarlet.dtsi"

arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet-inx.dts
10:#include "rk3399-gru-scarlet.dtsi"

arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet-dumo.dts
10:#include "rk3399-gru-scarlet.dtsi"


anu@laptop:~/kernel-dev/source/linux$ rg "rk3399-gru-chromebook.dtsi"
arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
9:#include "rk3399-gru-chromebook.dtsi"

arch/arm64/boot/dts/rockchip/rk3399-gru-bob.dts
9:#include "rk3399-gru-chromebook.dtsi"
Enter fullscreen mode Exit fullscreen mode

and I found .dts files!
now, I can test them!

anu@laptop:~/kernel-dev/source/linux$ make CHECK_DTBS=y DT_SCHEMA_FILES=Documentation/devicetree/bindings/sound/rockchip,rk3399-gru-sound.yaml  rockchip/rk3399-gru-kevin.dtb
make[1]: Entering directory '/home/anu/kernel-dev/source/linux/out'
  HOSTCC  scripts/dtc/dtc.o
  HOSTCC  scripts/dtc/flattree.o
  HOSTCC  scripts/dtc/fstree.o
  HOSTCC  scripts/dtc/data.o
  HOSTCC  scripts/dtc/livetree.o
  HOSTCC  scripts/dtc/treesource.o
  HOSTCC  scripts/dtc/srcpos.o
  HOSTCC  scripts/dtc/checks.o
  HOSTCC  scripts/dtc/util.o
  LEX     scripts/dtc/dtc-lexer.lex.c
  YACC    scripts/dtc/dtc-parser.tab.[ch]
  HOSTCC  scripts/dtc/dtc-lexer.lex.o
  HOSTCC  scripts/dtc/dtc-parser.tab.o
  HOSTLD  scripts/dtc/dtc
  HOSTCC  scripts/dtc/libfdt/fdt.o
  HOSTCC  scripts/dtc/libfdt/fdt_ro.o
  HOSTCC  scripts/dtc/libfdt/fdt_wip.o
  HOSTCC  scripts/dtc/libfdt/fdt_sw.o
  HOSTCC  scripts/dtc/libfdt/fdt_rw.o
  HOSTCC  scripts/dtc/libfdt/fdt_strerror.o
  HOSTCC  scripts/dtc/libfdt/fdt_empty_tree.o
  HOSTCC  scripts/dtc/libfdt/fdt_addresses.o
  HOSTCC  scripts/dtc/libfdt/fdt_overlay.o
  HOSTCC  scripts/dtc/fdtoverlay.o
  HOSTLD  scripts/dtc/fdtoverlay
  SCHEMA  Documentation/devicetree/bindings/processed-schema.json
  UPD     include/config/kernel.release
  DTC [C] arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dtb
make[1]: Leaving directory '/home/anu/kernel-dev/source/linux/out'

Enter fullscreen mode Exit fullscreen mode

and done!

I also checked it against a few other .dts files that I found, and they also succeeded!

anu@laptop:~/kernel-dev/source/linux$ make CHECK_DTBS=y DT_SCHEMA_FILES=Documentation/devicetree/bindings/sound/rockchip,rk3399-gru-sound.yaml  rockchip/rk3399-gru-scarlet-dumo.dtb
make[1]: Entering directory '/home/anu/kernel-dev/source/linux/out'
  DTC [C] arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet-dumo.dtb
make[1]: Leaving directory '/home/anu/kernel-dev/source/linux/out'
Enter fullscreen mode Exit fullscreen mode

I also tested
arch/arm64/boot/dts/rockchip/rk3399-gru-bob.dts

arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet-kd.dts

and they both succeeded!

My patch is ready to submit!

Note: This patch was not a part of GSoC application, it was submitted after the application period. I submitted the patch directly to the mailing list, it didn't go through internal review with mentors like my previous patches.


[4-4-26]
I got a response from maintainer Krzysztof!

> Convert the rockchip,rk3399-gru-sound.txt DT binding to YAML Schema.  

DT Schema, not YAML Schema.  

Same in subject.  

[https://elixir.bootlin.com/linux/v6.17-rc3/source/Documentation/devicetree/bindings/submitting-patches.rst#L18](https://elixir.bootlin.com/linux/v6.17-rc3/source/Documentation/devicetree/bindings/submitting-patches.rst#L18)  

...  

> +---  
> +$id: [http://devicetree.org/schemas/sound/rockchip,rk3399-gru-sound.yaml#](http://devicetree.org/schemas/sound/rockchip,rk3399-gru-sound.yaml#)  
> +$schema: [http://devicetree.org/meta-schemas/core.yaml#](http://devicetree.org/meta-schemas/core.yaml#)  
> +  
> +title: ROCKCHIP with MAX98357A/RT5514/DA7219 codecs on GRU boards  

Rockchip  

> +  
> +maintainers:  
> +  - Heiko Stuebner <[heiko@sntech.de](mailto:heiko@sntech.de)>  
> +  
> +properties:  
> +  compatible:  
> +    const: rockchip,rk3399-gru-sound  
> +  
> +  rockchip,cpu:  
> +    $ref: /schemas/types.yaml#/definitions/phandle-array  

Need to list items. See msm/gpu.yaml,  
allwinner,sun4i-a10-display-engine.yaml and others.  

And read the driver code to understand what is supposed to be here.  


> +    description:  
> +      The phandle of the Rockchip I2S controller that's connected to the codecs  
> +  
> +  rockchip,codec:  
> +    $ref: /schemas/types.yaml#/definitions/phandle-array  

Same here.  

> +    description: The phandle of the audio codecs
Enter fullscreen mode Exit fullscreen mode

The first 2 changes are clear. My naming was wrong. I can correct those easily. The next 2 were confusing.
I began exploring the files that he told me.
I started off with the yaml files (msm/gpu.yaml and allwinner,sun4i-a10-display-engine.yaml)

This is what I noticed:
both files had this structure-

subproperty:
  minItems: 1
  maxItems: 4
    items:
      maxItems: 1
Enter fullscreen mode Exit fullscreen mode

maxItems and minItems tell the valididator the maximum and minimum
items: maxItems:1 tells the schema validator that each individual entry in the phandle is a single phandle with no extra cells or arguments.

(example of phandle array entry with extra args: <&clk 3>)
This is true for both properties rockchip,cpu and rockchip,codec.

Next, I looked into the driver code. sound/soc/rockchip/rk3399_gru_sound.c

Inside this code, I observed the properties rockchip,cpu and rockchip,codec

I found that they were used in this function:

static int rockchip_sound_of_parse_dais(struct device *dev,
                    struct snd_soc_card *card)
{
    struct device_node *np_cpu, *np_cpu0, *np_cpu1;
    struct device_node *np_codec;
    struct snd_soc_dai_link *dai;
    struct snd_soc_dapm_route *routes;
    int i, index;
    int num_routes;

    card->dai_link = devm_kzalloc(dev, sizeof(rockchip_dais),
                      GFP_KERNEL);
    if (!card->dai_link)
        return -ENOMEM;

    num_routes = 0;
    for (i = 0; i < ARRAY_SIZE(rockchip_routes); i++)
        num_routes += rockchip_routes[i].num_routes;
    routes = devm_kcalloc(dev, num_routes, sizeof(*routes),
                  GFP_KERNEL);
    if (!routes)
        return -ENOMEM;
    card->dapm_routes = routes;

// 💡💡 rockchip,cpu defined here
    np_cpu0 = of_parse_phandle(dev->of_node, "rockchip,cpu", 0);
    np_cpu1 = of_parse_phandle(dev->of_node, "rockchip,cpu", 1);

    card->num_dapm_routes = 0;
    card->num_links = 0;

// 💡💡 rockchip,codec defined here
    for (i = 0; i < ARRAY_SIZE(rockchip_dais); i++) {
        np_codec = of_parse_phandle(dev->of_node,
                        "rockchip,codec", i);
        if (!np_codec)
            break;

        if (!of_device_is_available(np_codec))
            continue;

        index = rockchip_sound_codec_node_match(np_codec);
        if (index < 0)
            continue;

// 💡💡 the values for rockchip,codec and rockchip,cpu are used here. 
        switch (index) {
        case DAILINK_CDNDP:
            np_cpu = np_cpu1;
            break;
        case DAILINK_RT5514_DSP:
            np_cpu = np_codec;
            break;
        default:
            np_cpu = np_cpu0;
            break;
        }

        if (!np_cpu) {
            dev_err(dev, "Missing 'rockchip,cpu' for %s\n",
                rockchip_dais[index].name);
            return -EINVAL;
        }

        dai = &card->dai_link[card->num_links++];
        *dai = rockchip_dais[index];

        if (!dai->codecs->name)
            dai->codecs->of_node = np_codec;
        dai->platforms->of_node = np_cpu;
        dai->cpus->of_node = np_cpu;

        if (card->num_dapm_routes + rockchip_routes[index].num_routes >
            num_routes) {
            dev_err(dev, "Too many routes\n");
            return -EINVAL;
        }

        memcpy(routes + card->num_dapm_routes,
               rockchip_routes[index].routes,
               rockchip_routes[index].num_routes * sizeof(*routes));
        card->num_dapm_routes += rockchip_routes[index].num_routes;
    }

    return 0;
}
Enter fullscreen mode Exit fullscreen mode

Deduction:

rockchip,cpu can have 2 values at max and 1 value minimum.

I checked out array rockchip_dais[]

static const struct snd_soc_dai_link rockchip_dais[] = {
        [DAILINK_CDNDP] = {
        .name = "DP",
        .stream_name = "DP PCM",
        .init = rockchip_sound_cdndp_init,
        .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
            SND_SOC_DAIFMT_CBC_CFC,
        SND_SOC_DAILINK_REG(cdndp),
    },
    [DAILINK_DA7219] = {
        .name = "DA7219",
        .stream_name = "DA7219 PCM",
        .init = rockchip_sound_da7219_init,
        .ops = &rockchip_sound_da7219_ops,
        /* set da7219 as slave */
        .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
            SND_SOC_DAIFMT_CBC_CFC,
        SND_SOC_DAILINK_REG(da7219),
    },
    [DAILINK_DMIC] = {
        .name = "DMIC",
        .stream_name = "DMIC PCM",
        .ops = &rockchip_sound_dmic_ops,
        .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
            SND_SOC_DAIFMT_CBC_CFC,
        SND_SOC_DAILINK_REG(dmic),
    },
    [DAILINK_MAX98357A] = {
        .name = "MAX98357A",
        .stream_name = "MAX98357A PCM",
        .ops = &rockchip_sound_max98357a_ops,
        /* set max98357a as slave */
        .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
            SND_SOC_DAIFMT_CBC_CFC,
        SND_SOC_DAILINK_REG(max98357a),
    },
    [DAILINK_RT5514] = {
        .name = "RT5514",
        .stream_name = "RT5514 PCM",
        .ops = &rockchip_sound_rt5514_ops,
        /* set rt5514 as slave */
        .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
            SND_SOC_DAIFMT_CBC_CFC,
        SND_SOC_DAILINK_REG(rt5514),
    },
    /* RT5514 DSP for voice wakeup via spi bus */
    [DAILINK_RT5514_DSP] = {
        .name = "RT5514 DSP",
        .stream_name = "Wake on Voice",
        SND_SOC_DAILINK_REG(rt5514_dsp),
    },
};
Enter fullscreen mode Exit fullscreen mode

there are 6 elements in this array. however, the codec values accepted, as per the original txt binding title are:

ROCKCHIP with MAX98357A/RT5514/DA7219 codecs on GRU boards.

that means that this property can accept just 3 values at max.

looking at the switch case program in the driver code where the values are actually assigned:

        switch (index) {
        case DAILINK_CDNDP:
            np_cpu = np_cpu1;
            break;
        case DAILINK_RT5514_DSP:
            np_cpu = np_codec;
            break;
        default:
            np_cpu = np_cpu0;
            break;
        }
Enter fullscreen mode Exit fullscreen mode

we can make out that the order of elements for rockchip,cpu matters
but for rockchip,codec it does not matter. (look at the driver code and array.

Now, since the order of elements for rockchip,cpu matters, we need to write description for each item.

According to the code,
The 2nd element of the array is for DAILINK_CDNDP -- this is for the Cadence DisplayPort (cdn dp), -- the spdif controller
and the 1st element is for all the other options - I2S controllers connected to the codecs.

However, I noticed that the original txt binding had not contained any mention of the spdif controller, so i checked the .dtsi file for this binding: arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi

        sound: sound {
                compatible = "rockchip,rk3399-gru-sound";
                rockchip,cpu = <&i2s0 &spdif>;
        };      
Enter fullscreen mode Exit fullscreen mode

This proved that the spdif property indeed exists for the device RK3399-gru-sound

Thus, I can add it to my DT Schema in peace.
This is how I added it

  rockchip,cpu:
    $ref: /schemas/types.yaml#/definitions/phandle-array
    minItems: 1
    maxItems: 2
    items:
      - items:
          - description: Phandle to I2S controller connected to codecs
      - items:
        - description: Phandle to SPDIF controller

Enter fullscreen mode Exit fullscreen mode

I remember I had said this before:

there are 6 elements in this array. however, the codec values accepted, as per the original txt binding title are:

ROCKCHIP with MAX98357A/RT5514/DA7219 codecs on GRU boards.
that means that this property can accept just 3 values at max.

I realized that I should test this properly and prove that. So, I began carding through the files that used the rockchip,codec property

These were the files that had it:

  1. arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi
rockchip,codec = <&max98357a &dmic &codec &cdn_dp>
Enter fullscreen mode Exit fullscreen mode
  1. arch/arm64/boot/dts/rockchip/rk3399-gru-chromebook.dtsi
&sound {
        rockchip,codec = <&max98357a &headsetcodec
                          &codec &wacky_spi_audio &cdn_dp>;
};
Enter fullscreen mode Exit fullscreen mode

notice that there are some additional properties.

for this, i went back to the driver code:

index = rockchip_sound_codec_node_match(np_codec);
if (index < 0)
        continue;

switch (index) {
case DAILINK_CDNDP:
Enter fullscreen mode Exit fullscreen mode
static int rockchip_sound_codec_node_match(struct device_node *np_codec)
{
        struct device *dev;
        int i;

        for (i = 0; i < ARRAY_SIZE(dailink_match); i++) {
                if (!of_device_is_compatible(np_codec,
                                             dailink_match[i].compatible))
                        continue;

                if (dailink_match[i].bus_type) {
                        dev = bus_find_device_by_of_node(dailink_match[i].bus_type,
                                                         np_codec);
                        if (!dev)
                                continue;
                        put_device(dev);
                }

                return i;
        }
        return -1;
}
Enter fullscreen mode Exit fullscreen mode

so if the element is not found -1 is returned to the index, and is index < 0, the loop is simply continued.

now in order to understand the maximum entries,

for (i = 0; i < ARRAY_SIZE(rockchip_dais); i++) {
        np_codec = of_parse_phandle(dev->of_node, "rockchip,codec", i);
Enter fullscreen mode Exit fullscreen mode

the size of rockchip_dais is 6. thus, max 6 elements can be parsed, properties >6 will be ignored.
Thus, my assumption was wrong. the max_size of t he array should be 6.

However, looking at the code, it's clear that the order of the properties does not matter. i have no need to explicitly declare them.

After that, I did some touch ups to the descriptions of the properties to refine them a bit.
And done!

This is how my final v2 looks like:

# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/rockchip,rk3399-gru-sound.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Rockchip with MAX98357A/RT5514/DA7219 codecs on GRU boards

maintainers:
  - Heiko Stuebner <heiko@sntech.de>

properties:
  compatible:
    const: rockchip,rk3399-gru-sound

  rockchip,cpu:
    $ref: /schemas/types.yaml#/definitions/phandle-array
    description: |
      List of phandles to the Rockchip CPU DAI controllers connected to codecs
    minItems: 1
    items:
      - items:
          - description: Phandle to the Rockchip I2S controllers
      - items:
          - description: |
              Phandle to the Rockchip SPDIF controller. Required when a
              DisplayPort audio codec is referenced in rockchip,codec

  rockchip,codec:
    $ref: /schemas/types.yaml#/definitions/phandle-array
    description: |
      The phandles of the audio codecs connected to the Rockchip CPU DAI
      controllers
    minItems: 1
    maxItems: 6
    items:
      maxItems: 1

  dmic-wakeup-delay-ms:
    description: |
      specify delay time (ms) for DMIC ready.
      If this option is specified, a delay is required for DMIC to get ready
      so that rt5514 can avoid recording before DMIC sends valid data

required:
  - compatible
  - rockchip,cpu
  - rockchip,codec

additionalProperties: false

examples:
  - |
    sound {
      compatible = "rockchip,rk3399-gru-sound";
      rockchip,cpu = <&i2s0 &spdif>;
      rockchip,codec = <&max98357a &rt5514 &da7219 &cdn_dp>;
      dmic-wakeup-delay-ms = <20>;
    };
Enter fullscreen mode Exit fullscreen mode

Now it's time for testing.

  • [x] dt_binding_check
  • [x] dtbs_check

for this, I realized that i dont have to do such a long procedure of commands, as shown in the previous one, there is a shorter way:

make mrproper
Enter fullscreen mode Exit fullscreen mode
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- KBUILD_OUTPUT=out/ defconfig
Enter fullscreen mode Exit fullscreen mode
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- KBUILD_OUTPUT=out/ CHECK_DTBS=y DT_SCHEMA_FILES=Documentation/devicetree/bindings/sound/rockchip,rk3399-gru-sound.yaml rockchip/rk3399-gru-kevin.dtb
Enter fullscreen mode Exit fullscreen mode

both checks are completed successfully, the patch v2 is ready to submit!


I submitted v2!


[12-04-26 14:48:36]

YAY!!!! Krzysztof reviewed my patch, and didn't mention any changes!! It means my patch is correct right? :)) >.<


[13-04-26 00:12:08]

Omggggg!!!! I just recieved a mail from maintainer Mark Brown!!
It's applied!!!!!!

Enter fullscreen mode Exit fullscreen mode

OMGG!!! I am SO excited!!! My patch will actually be merged!! OMG! sfkafjsfdaajfnfkjsdfhbaewkfhawsljkshfkf

git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git

OMGGGGG!!! My patch is in the tree!!! _My patch is in the tree!!! aaaaaaaaa!!!!! I am SO excited!

I can't wait to start with my next patch! Looking into the driver code was so much fun! The entire process of exploration, observing existing code was SO interesting!
It's such a pity I have my exams coming up, so I won't be able to work on a new patch, or post for a while... :')

I'll resume contributing and my exploration once my exams are done :)

Top comments (0)