EmbeddedRelated.com
Forums
Memfault Beyond the Launch

driver allowing to define GPIO pin groups and control them via sysfs

Started by Unknown January 24, 2018
Hi,

I'm developing a system based on Xilinx MPSoC chip, where multiple functionalities are controlled by AXI GPIO blocks.
All those GPIO pins are accessible via sysfs interface.
However, it is difficult to find the gpio chip and pin numbers from running Linux system.
In the HDL design, the GPIO blocks are described by their names, but unfortunately those names are not propagated to the device tree.

For single pins, I have created a solution, that defines the virtual node in the device tree:
https://github.com/wzab/Z-turn-examples/blob/master/axi_dma_prj2/software/example/dts/ksgpio.dtsi
and provides the kernel space driver that allows to control single pins via functions exported to other kernel drivers:
https://github.com/wzab/Z-turn-examples/blob/master/axi_dma_prj2/software/example/axi4s2dmov/ksgpio.c

What I need now is something that supports multiple GPIOs and allows to define the group of pins like below. (for example assuming that we have a simple bus with 8-bit address, 8-bit data, read and write strobe, the example shuffles the order of pins to show the required flexibility)
In the device tree i can handle it like below:

&amba_pl {
            multi-gpio {
                    compatible = "wzab,multi-gpio";
                    data-gpios = <&axi_gpio_ctl 0 0>, 
                                  <&axi_gpio_ctl 17 0>, 
                                  <&axi_gpio_ctl 11 0>, 
                                  <&axi_gpio_ctl 2 0>, 
                                  <&axi_gpio_ctl 4 0>, 
                                  <&axi_gpio_ctl 6 0>, 
                                  <&axi_gpio_ctl 3 0>, 
                                  <&axi_gpio_ctl 7 0>; 
                    address-gpios = <&axi_gpio_ctl 1 0>, 
                                  <&axi_gpio_ctl 5 0>, 
                                  <&axi_gpio_ctl 14 0>, 
                                  <&axi_gpio_ctl 18 0>, 
                                  <&axi_gpio_ctl 19 0>, 
                                  <&axi_gpio_ctl 8 0>,
                                  <&axi_gpio_ctl 10 0>, 
                                  <&axi_gpio_ctl 12 0>, 
                    read-gpios = <&axi_gpio_ctl 21 0>, 
                    write-gpios = <&axi_gpio_ctl 24 0>, 
            };
};
Of course it would be nice if I could describe the continuous range of GPIOs in a simple way like "data-gpios = <&axi_pio_ctl 7-0 0>". 

But the real problem is how to efficently represent it in the driver?
It would be perfect, if I could create the node in the sysfs, like
/sys/class/multi-gpio/data, then control its direction and set its value like a single gpio:

echo out > /sys/class/multi-gpio/data/direction
echo 12 >  /sys/class/multi-gpio/data/value
echo 1 >   /sys/class/multi-gpio/write/value
echo 0 >   /sys/class/multi-gpio/write/value
echo in > /sys/class/multi-gpio/data/direction
echo 1 >   /sys/class/multi-gpio/read/value
val=`cat   /sys/class/multi-gpio/data/value`
echo 0 >   /sys/class/multi-gpio/read/value

Is the above a reasonable approach? Are there any existing solutions that can be used for such purposes?

Thank you very much in advance,
With best regards,
Wojtek
It seems, that the functions devm_gpiod_get_array, gpiod_set_array_value and similar may be useful...

Wojtek
Well, I have implemented a quick&dirty, proof of the concept implementation of such driver. The sources are available at https://groups.google.com/forum/#!topic/alt.sources/qp88RCer95s
I'll appreciate any error corrections or suggestions of improvements.

Regards,
Wojtek
The disadvantage of the solution published at https://groups.google.com/forum/#!topic/alt.sources/qp88RCer95s is that it requires creating "attributes" representing the groups of gpios manually in the code.
It would be good, to have a code that could autamatically scan the device tree for lists of gpios, and create appropriate attributes.
Unfortunately, the standard way of creating the attributes uses macros that are processed at the compile time (DEVICE_ATTR_RO and similar).
It seems, that the attributes may be created dynamically at the runtime, using the 
"device_create_file" function, but the "show" and "store" functions should be created in advance.
Well, probably it is possible to use the same "show" and "store" function for all attributes, and then access the appropriate array of GPIOs after checking the attribute name passed to the function via the "attr" argument (see http://elixir.free-electrons.com/linux/v4.14.14/source/include/linux/device.h#L553 ).
So in fact the only thing that is lacking is the possibility to find all GPIOs list in the device tree node.
Unfortunately, the gpiolib does not contain any iterator like "for_each_con_id" that I could run on a platform device...
Are there any other ways to do it?

TIA & Regards,
Wojtek
At the moment I have a version of the driver that allows to define the groups of the GPIOs in a single simple table in the driver's code:

static my_attr_t my_attrs[]={
  {"dout1",NULL},
  {"dout2",NULL},
  {"din",NULL},
  {NULL,NULL}
};

The user is responsible to make sure that the names in the table agree with the DT definition (e.g. in this case it should contain "dout1-gpios", "dout2-gpios and "din-gpios").
The sources of the driver are available at https://groups.google.com/d/msg/alt.sources/qp88RCer95s/xilfmezIAQAJ

Regards,
Wojtek

Memfault Beyond the Launch