Device Tree GPIO Reset - embedded-linux

I'm working on a board based on the iMX6 and am trying to configure a number of GPIOs that are being used as chip enable and reset lines. Based on the research I've done, the way to handle this is via the gpio-reset driver in the device tree. Following the documentation I've come up with the below code which compiles but I'm not sure how to then control these reset lines from user space.
The first device tree driver I used was the gpio-leds which created an leds folder in sys/class with nodes to control the LED. However I don't see anything similar for reset. So I have 2 questions:
1) Is GPIO-RESET the correct binding to use for controlling reset lines, enable lines, etc.
2) Is there documentation on how to handle this and other bindings from user space, similar to how I'm controlling the GPIO-LED?
Kernel: Linux buildroot 4.1.15
/dts-v1/;
#include <dt-bindings/input/input.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/pinctrl/omap.h>
#include "imx6ul.dtsi"
/ {
model = "Freescale i.MX6 UltraLite 14x14 EVK Board";
compatible = "fsl,imx6ul-14x14-evk", "fsl,imx6ul";
memory {
reg = <0x80000000 0x20000000>;
};
/* Reset Line Configuration */
gpio_resets {
compatible = "linux,gpio-reset";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gpioreset>;
gnss {
gpios = <&gpio1 4 0>;
asserted-state = <0>;
duration-ms = <100>;
auto;
};
};
...
};
&iomuxc {
pinctrl-names = "default";
imx6ul-evk {
pinctrl_gpioreset:
gpiorstgrp {
fsl,pins = <
MX6UL_PAD_GPIO1_IO04__GPIO1_IO04 0x000010B0 /* GNSS RESET_N */
>;
};
...
};

I'm not exactly sure about the gpio-reset sysfs interface as I couldn't find any information in bindings documentation, but for the normal gpio interface you need to export the gpio before it will show up in /sys/class/gpio/gpio*. Basically you just need to write the number of the gpio you wish to use to the export file underneath /sys/class/gpio. Here is an example of someone doing that. If you're just toggling the gpio on/off that interface should be enough.

Is GPIO-RESET the correct binding to use for controlling reset lines, enable lines, etc.
I have been looking for such a driver too.
I can see that there was a proposal for exactly this:
https://lwn.net/Articles/585145/
but I cannot find it in my kernel version (tracking the 5.4.y releases).
Only in some stale imx6 kernel: https://github.com/samnazarko/linux-imx6/blob/master/Documentation/devicetree/bindings/reset/gpio-reset.txt
So I will either
create a small driver to support the "delayed" function based on the above proposal (time of asserting the reset at boot).
use gpio-led with a default-state. Maybe using the "one-shot" trigger, to provide a single-write API to my apps. (Write once to the sysfs shot file results in a single toggle of the pin for a configurable time.)
Totally handle it from the userspace via libgpio or sysfs. (Maybe combined with gpio-led, to have at least a clearly defined state of the line during boot.)

Related

STM32MP1 linux IRQs & EXTI controller config in DTS file

I'm running a buildroot linux environment on a STM32MP157 dev board. I have a button with an internal pullup on pin B12. I want to fire an interrupt once the line goes low. On other linux boards like the RPi, I've been able to call gpio_to_irq(<gpio#>) and get the IRQ for that pin. Done, simple. However, on this board, there are only 16 external interrupts connected to the EXTI peripheral; they are configurable in a sense that any port may be connected to the EXTI, but the pin numbers cannot overlap. For example GPIO A12 and B12 may NOT be connected to the EXTI at the same time. I have ensured that no other devices are using and GPIO port pin 12.
I have edited my DTS file to reflect that I want my GPIO B12 connected to the EXTI controller. But so far I have had no luck in making that happen. Here is the documentation for the interrupts provided by ST. If someone can explain how to fix the device tree such that I can request the B12 interrupt from my driver I would really appreciate it.
Here's my DTS file:
/dts-v1/;
#include "stm32mp157.dtsi"
#include "stm32mp15xa.dtsi"
#include "stm32mp15-pinctrl.dtsi"
#include "stm32mp15xxac-pinctrl.dtsi"
#include "stm32mp15xx-dkx.dtsi"
/ {
model = "STMicroelectronics STM32MP157A-DK1 Discovery Board";
compatible = "st,stm32mp157a-dk1", "st,stm32mp157";
chosen {
stdout-path = "serial0:115200n8";
};
button {
compatible = "test,button";
input-gpios = <&gpiob 12 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; //Works with pull-up once the driver is loaded.
interrupts-extended = <&gpiob 12 IRQ_TYPE_EDGE_FALLING>;
interrupt-names = "qwerty";
status = "okay";
};
led {
extern-led {
compatible = "test,led";
gpios = <&gpiob 10 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "cpu";
};
};
};
I have tried the following:
interrupts-extended = <&exti 28 IRQ_TYPE_EDGE_FALLING>; (This SOC only has 16 pins per GPIO bank, so B12 is global GPIO 28)
interrupts-extended = <&gpiob 12 IRQ_TYPE_EDGE_FALLING>;
interrupt-parent = <&gpiob>;
interrupts = <12
IRQ_TYPE_EDGE_FALLING>;
Lastly, my stretch goal is to be able to request the IRQ by name, from the interrupt-name property in the device tree. Something like request_irq("qwerty"). Is that possible?
EDIT: I have temporarily connected my pushbutton to GPIO A12, and it successfully fires the interrupt, confirming that the EXTI #12 interrupt is connected to GPIO bank A. How can I go about changing this from within the device tree? Thank you in advance.
Okay I have solved this. Apparently iterating through your GPIO pins with the gpio*_to_irq() functions was the problem. When the function was called, the kernel would immediately configure the EXTI interface for that pin. I thought it was defaulting to Port A, but that was actually caused by iterating through all the GPIO pins looking for the interrupt number starting at GPIO 0, aka Port A Pin 0. So by only calling the gpio_to_irq or gpiod_to_irq function for the pins you need, the kernel will properly configure the EXTI interface for the requested pins.

Linux Device Tree: Touch controller failing i2c test

Context
I am using an i.MX6 ULL application processor with a Goodix 9271 touch-screen display. The display has been added to the device tree and is working correctly. I now wanted to add the touch controller, which is connected to my application processor via I²C. I therefore added
A new node under my I²C node which adds the controller as a device on the bus.
A new pin control group for the application processor to interface with the touch controller
I have enumerated them here:
/* #1: Device node on the I2C bus */
&i2c1 {
clock_frequency = <100000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1>;
status = "okay";
/* Awesome new touch controller */
gt9271_ts#5d {
compatible = "goodix,gt9271"; /* Device tree binding */
reg = <0x5d>; /* I2C bus address */
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gt9271_ts_gpio>; /* Custom pinctrl group node */
interrupt-parent = <&gpio4>;
interrupts = <16,0>; /* GPIO 4 + pin 16 + active high */
reset-gpios = <&gpio4 12 0>; /* GPIO 4 + Pin 12 + active high */
touchscreen-size-x = <1200>;
touchscreen-size-y = <800>;
touchscreen-inverted-x;
touchscreen-inverted-y;
};
/* ... */
};
/* #2: Pin control group */
&iomuxc {
pinctrl_gt9271_ts_gpio: gt9271_ts_gpiogrp {
fsl,pins = <
MX6UL_PAD_NAND_DQS__GPIO4_IO16 0x80000000 /* Interrupt */
MX6UL_PAD_NAND_READY_B__GPIO4_IO12 0x80000000 /* Reset */
>;
};
/* ... */
};
Explanation: bus address
The device data sheet, available here, indicates that two slave addresses are supported: 0xBA/0xBB and 0x28/0x29. The device is set to use 0xBA/0xBB adjusted for 7-bit addressing as recommended in this binding, (so the address assigned in the node is actually 0x5d).
Explanation: control pins
The I²C reset and interrupt are connected (respectively) to GPIO 4, pin 16, and GPIO 4, pin 12. These are reserved for NAND but NAND is not being used with this processor so the pins are free.
Problem
Unfortunately, the touchscreen controller configuration I have added is failing on boot with an I²C related message. I am greeted on boot with the following:
[ 2.118110] Goodix-TS 0-005d: 0-005d supply AVDD28 not found, using dummy regulator
[ 2.126059] Goodix-TS 0-005d: 0-005d supply VDDIO not found, using dummy regulator
[ 2.134510] Goodix-TS 0-005d: i2c test failed attempt 1: -6
[ 2.177733] Goodix-TS 0-005d: i2c test failed attempt 2: -6
[ 2.217377] Goodix-TS 0-005d: I2C communication failure: -6
I have attempted to search the error code (-6) but find sparse to non-existent search results online. I've checked that the connector is physically there and it seems to be.
What steps might I take to diagnose such an error code?
The solution is as follows:
The documentation states that I should include the property in the format irq-gpios. I previously thought I only needed the interrupts property. After adding irq-gpios = <&gpio4 16 0>;, the device passed the I2C test.
I disabled touchscreen-inverted-x;, and touchscreen-inverted-y; by removing those lines. I had incorrectly assumed I needed to do that originally.
Verdict:
Try to follow the documentation precisely.

Where can I find the mapping of SAMA5D27-SOM1-EK1 devices and it's GPIOS?

I am using SAMA5D27-SOM-EK1 embedded board.
I build for it Linux image OS using YOCTO project version SUMO.
I need to know device's GPIOS ( gpios-leds and gpios keys specialy) and the mapping of the board.
When I enter in /sys/firmware/devicetree/base/leds/red for example in the board terminal I can find gpio file but when i open it there are symbols which i can't read.
I think that I can find such things in the generated Device Tree but i can't find its path!
Please help me out
Here is the original dts: https://elixir.bootlin.com/linux/v5.2/source/arch/arm/boot/dts/at91-sama5d27_som1_ek.dts#L510
The relevant part is:
leds {
compatible = "gpio-leds";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_led_gpio_default>;
status = "okay"; /* Conflict with pwm0. */
red {
label = "red";
gpios = <&pioA PIN_PA10 GPIO_ACTIVE_HIGH>;
};
green {
label = "green";
gpios = <&pioA PIN_PB1 GPIO_ACTIVE_HIGH>;
};
blue {
label = "blue";
gpios = <&pioA PIN_PA31 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "heartbeat";
};
};
This shows that the red LED is connected to the PA10 gpio, green is on PB1 and blue on PA31.
The other way to find the info is to look at the schematics here:
http://ww1.microchip.com/downloads/en/DeviceDoc/SAMA5D27-SOM1-EK1_Board%20Files_1.B.B.zip
Page 3 of SAMA5D27-SOM1-EK1_REVB.pdf sums the pinmuxing and page 8 shows the actual connection.
Regarding what you want to do (toggling the led if I remember correctly), you can simply have a look at /sys/class/leds/red/brightness writing 0 in that file will turn it off while writing 1, will turn it on.
The device tree sources are available online and are not present in the target system.
Please follow this link
However you could discover how it is working running a sort of reverse engineering using the Device Tree Compiler (DTC) if it is available on the target, run
dtc -I fs /sys/firmware/devicetree/base

When using dt-blob.dts to configure GPIO pins, which pin#pxx corresponds to #12 on the 40-pin header?

My Raspberry Pi 3B runs Jessie-Lite. I would like to configure Physical pin 12/BCM pin 18/Wiring Pi pin 1 to be an output, set to low.
On Stretch, this can be done easily via config.txt
gpio=18=op,dl
On previous versions, this is apparently done by editing the dt-blob.dts file (https://www.raspberrypi.org/documentation/configuration/pin-configuration.md)
However, in the section for pins_3b1 or pins_3b2 (Pi 3 B), I cannot find a reference corresponding to my target pin (Physical pin 12/BCM pin 18/Wiring Pi pin 1). There is no pin#p12 or pin#p18. There is a pin#p1 but inside the videcore {} section.
Thank you.
[From https://www.raspberrypi.org/forums/viewtopic.php?f=107&t=237796&p=1453560#p1453560]
The dt-blob is not meant to list all pins - just those with a specific function and that require a non-default value. If you were to initialise GPIO18 from the dt-blob to be an output driving low you would need to add something like:
pin#p18 { function = "output"; startup_state = "active"; termination = "no_pulling"; polarity = "active_low"; };

device-tree mismatch: .probe never called

I'm having trouble understanding how device-tree works, or specifically why this driver won't init. This is in the rockchip vendor kernel for android, version 3.10
drivers/watchdog/rk29_wdt.c (reduced for readability)
static const struct of_device_id of_rk29_wdt_match[] = {
{ .compatible = "rockchip,watch dog" }
};
static struct platform_driver rk29_wdt_driver = {
.probe = rk29_wdt_probe,
[..]
.of_match_table = of_rk29_wdt_match,
.name = "rk29-wdt",
},
};
static int __init watchdog_init(void)
{
printk("watchdog_init\n");
return platform_driver_register(&rk29_wdt_driver);
}
and this is the soc dtsi
arch/arm/boot/dts/rk3288.dtsi
watchdog: wdt#2004c000 {
compatible = "rockchip,watch dog";
reg = <0xff800000 0x100>;
clocks = <&pclk_pd_alive>;
clock-names = "pclk_wdt";
interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
rockchip,irq = <0>;
rockchip,timeout = <2>;
rockchip,atboot = <1>;
rockchip,debug = <0>;
status = "okay";
};
however, the .probe function of the driver is never called. It is compiled in and the __init function is called. I suspect it has something to do witch the device tree entry not matching? Maybe the space is an issue?
Or is there anything else that runs before .probe that determines if the driver should continue?
Also i'm not sure how a flattened tree works, so maybe this is relevant:
arch/arm/mach-rockchip/rk3288
DT_MACHINE_START(RK3288_DT, "Rockchip RK3288 (Flattened Device Tree)")
.smp = smp_ops(rockchip_smp_ops),
.map_io = rk3288_dt_map_io,
.init_time = rk3288_dt_init_timer,
.dt_compat = rk3288_dt_compat,
.init_late = rk3288_init_late,
.reserve = rk3288_reserve,
.restart = rk3288_restart,
MACHINE_END
There are a number of possible ways this might happen, and most of them are well away from the driver code itself. Firstly, a .dtsi fragment alone doesn't tell the whole story - the device tree syntax is hierarchical, so the properties (in particular the status) might still be overridden by the board-level .dts which includes a basic SoC .dtsi file. Secondly, the compiled DTB isn't the last word either, since the bootloader may dynamically modify it before passing it to the kernel - this is typically done for memory nodes and SMP enable methods, but could potentially affect anything.
This kind of debugging is often best tackled in reverse, by examining the state of the booted system, then working backwards to figure out how things got that way - the specifics of this particular question rule some of this out already, but for the sake of completeness:
If the kernel knows about the driver, and it's loaded and properly initialised, it should show up somewhere in /sys/bus/*/drivers/ - otherwise, it may be in a module which needs loading, or it may have failed to initialise due to some unmet dependency on some other driver or resource.
If the kernel knows about the device, it should show up somewhere in /sys/bus/*/devices/, and if it's correctly bound to a driver and probed then they should both have a symlink to each other.
If the device is nowhere to be found, then on a DT-based system the next place to check would be /proc/device-tree/ (dependent on CONFIG_PROC_DEVICETREE on older kernels, and canonically found in /sys/firmware/devicetree/base/ on newer ones) - this will show the view of the DT as the kernel found it, and a bit of poking around there should hopefully make clear any missing nodes or out-of-place properties, such as a disabled node causing the kernel to skip creating a device altogether. Beware that the property files themselves are just the raw data - so you probably want to go snooping with hexdump rather than cat - and that all numeric cells are in big-endian byte order.
I notice that in your definition you miss so called SENTINEL in your array, null empty struct.
Look here an example:
static const struct of_device_id clk_ids[] = {
{ .compatible = "sirf,atlas7-clkc" },
{},
};

Resources