linux-kernellinux-device-driverembedded-linuxdevice-treepetalinux

Linux device tree: how to parse property containing a list of cells


I am developing a Linux device driver for data acquisition in an embedded Linux (PetaLinux).

To avoid hardcoding hardware specifics in the kernel module one of the entries in device tree has a list of cells that describe mappings of relays accessed via SPI for different ADC chips, like this:

ll-adc@a1000000 {
  compatible = "ll,llmk1-adc-1.0";
  reg =   <0x0 0xa1000000 0x1000>;

  // related SPI devices to control attenutor relays
  relay-devs = <&usmk1_max4820_0 &usmk1_max4820_1>;

  // Which relays control which ADC channel attenuator
  relays =
        <0 0 0 2>, // Channel 0, att 0 --> relay dev 0, ch 2 
        <0 1 0 3>, // Channel 0, att 1 --> relay dev 0, ch 3 
        <1 0 1 3>, // Channel 1, att 0 --> relay dev 1, ch 3 
        <1 1 0 0>; // Channel 1, att 1 --> relay dev 0, ch 0 
};

When instantiating the device, I'd like to read the values from the property "relays" and save them in a table in kernel module.

However, I was unable to find proper functions to do that.

As far as I can see of_property_read_*_array can read an array for a property that contains a single cell. of_for_each* macros can iterate multiple values of a property as long as they are phandles, u32 or strings.

Can someone please suggest what is the proper way to read a list of cells as shown above if it is possible at all?

Thank you for your help.


Solution

  • An example in the kernel source indicates a possible solution.

    If your node property is composed of a list of n-tuples, then of_property_read_u32_index() can be used to fetch an individual u32 argument of the ith tuple:

    num_args = 4;
    
    if (!of_get_property(np, "relays", &tmp))
        return NULL;
    num_relays = tmp / (sizeof(u32) * num_args);
    
    for (i = 0; i < num_relays; i++) {
        offset = i * num_args;
        if (of_property_read_u32_index(np, "relays", offset, &arg0))
            goto err;
    
        if (of_property_read_u32_index(np, "relays", offset + 1, &arg1))
            goto err;
    
        if (of_property_read_u32_index(np, "relays", offset + 2, &arg2))
            goto err;
    
        if (of_property_read_u32_index(np, "relays", offset + 3, &arg3))
            goto err;
    }
    

    The driver drivers/clk/at91/clk-pll.c uses similar code to retrieve values from the atmel,pll-clk-output-ranges property:

            pmc: pmc@fffffc00 {
                plla: pllack {
                    atmel,clk-input-range = <2000000 32000000>;
                    atmel,pll-clk-output-ranges = <745000000 800000000 0 0>,
                                <695000000 750000000 1 0>,
                                <645000000 700000000 2 0>,
                                <595000000 650000000 3 0>,
                                <545000000 600000000 0 1>,
                                <495000000 550000000 1 1>,
                                <445000000 500000000 2 1>,
                                <400000000 450000000 3 1>;
                };  
                ...
            };            
    

    ADDENDUM

    Seems that the angle brackets in the definition of the property have no effect on the array of integers in the compiled dtb.
    Both of the following property definitions:

        node1 {
            xxx = <745000000 800000000 0 0>,
                <695000000 750000000 1 0>,
                <645000000 700000000 2 0>,
                <595000000 650000000 3 0>,
                <545000000 600000000 0 1>,
                <495000000 550000000 1 1>,
                <445000000 500000000 2 1>,
                <400000000 450000000 3 1>;
        };
    
        node2 {
            xxx = < 745000000 800000000 0 0
                695000000 750000000 1 0
                645000000 700000000 2 0
                595000000 650000000 3 0
                545000000 600000000 0 1
                495000000 550000000 1 1
                445000000 500000000 2 1
                400000000 450000000 3 1 >;
        };
    

    have the same value when dumped from /proc/device-tree/ :

    # hexdump -C node1/xxx
    00000000  2c 67 cc 40 2f af 08 00  00 00 00 00 00 00 00 00  |,g.@/...........|
    00000010  29 6c db c0 2c b4 17 80  00 00 00 01 00 00 00 00  |)l..,...........|
    00000020  26 71 eb 40 29 b9 27 00  00 00 00 02 00 00 00 00  |&q.@).'.........|
    00000030  23 76 fa c0 26 be 36 80  00 00 00 03 00 00 00 00  |#v..&.6.........|
    00000040  20 7c 0a 40 23 c3 46 00  00 00 00 00 00 00 00 01  | |.@#.F.........|
    00000050  1d 81 19 c0 20 c8 55 80  00 00 00 01 00 00 00 01  |.... .U.........|
    00000060  1a 86 29 40 1d cd 65 00  00 00 00 02 00 00 00 01  |..)@..e.........|
    00000070  17 d7 84 00 1a d2 74 80  00 00 00 03 00 00 00 01  |......t.........|
    00000080
    # hexdump -C node2/xxx
    00000000  2c 67 cc 40 2f af 08 00  00 00 00 00 00 00 00 00  |,g.@/...........|
    00000010  29 6c db c0 2c b4 17 80  00 00 00 01 00 00 00 00  |)l..,...........|
    00000020  26 71 eb 40 29 b9 27 00  00 00 00 02 00 00 00 00  |&q.@).'.........|
    00000030  23 76 fa c0 26 be 36 80  00 00 00 03 00 00 00 00  |#v..&.6.........|
    00000040  20 7c 0a 40 23 c3 46 00  00 00 00 00 00 00 00 01  | |.@#.F.........|
    00000050  1d 81 19 c0 20 c8 55 80  00 00 00 01 00 00 00 01  |.... .U.........|
    00000060  1a 86 29 40 1d cd 65 00  00 00 00 02 00 00 00 01  |..)@..e.........|
    00000070  17 d7 84 00 1a d2 74 80  00 00 00 03 00 00 00 01  |......t.........|
    00000080
    # cmp node1/xxx node2/xxx
    # 
    

    In either version of the property, the angled brackets (aka chevrons) and commas seem to be ignored, and the values are simply stored as a single-dimension array of integers (with big-endian byte order).


    ADDENDUM 2

    The above results are confirmed by two statements in the DeviceTree Specification (release v0.2-18-g8466c3b-dirty), section 6.3:

    Arrays of cells (i.e. units of information consisting of 32 bits) are represented by angle brackets surrounding a space separated list of C-style integers

    and

    (Property) Values may have several comma-separated components, which are concatenated together.

    Therefore a property value that is a single array is indistinguishable from several arrays that are concatenated.
    The use of a list of n-tuples would be purely for esthetics and readability.

    The "organization" of the data (as n-tuples) cannot be discerned at the dtb level.
    So the size or n of the n-tuple (or "list of cells") should be passed to the driver in another property, or specified in the bindings document (when hardcoded in the driver).