How to define a relay in a device tree - embedded-linux

I have a board, SoC running Linux 5+, with a electrical relay. The relay is triggered by a GPIO. I am looking for a good way to define a relay in a device tree file.
I define LEDs as
led {
compatible = "gpio-leds";
debug {
label = "debug";
gpios = ...
default-state = "off";
};
};
This results in
# ls /sys/class/leds/
debug
I would like to have the relay be something similar such as
# ls /sys/class/{relays,outputs,gpios}/
relay1
What is a good way to achieve this?

Since relay behaves as simply as GPIO output (or more precisely GPO), what you need is just name the corresponding line. It can be done by assigning gpio-line-names property of the GPIO controller in the ACPI or Device Tree. With a use of libgpiod tools (such as gpiofind, gpioinfo), that access GPIO controller via character device node, you may find your line and do the operations on it. Note, GPIO sysfs interface is deprecated and it will be removed from the kernel on a horizon of ~5 years or so.

Related

Device Tree dependency between two nodes

I have two device tree nodes, one sets a gpio pin and the other one configures one i2c bus, ex:
&gpio2 {
en-gpio {
gpio-hog;
gpios = <5 0>;
output-high;
};
};
&i2c1 {
gpiom1: gpio#27 {
compatible = "microchip,mcp23008";
gpio-controller;
#gpio-cells = <2>;
reg = <0x27>;
};
};
How can i add a dependency between the i2c node and gpio one?
What i want to achieve is that the gpio pin should be set before the devices on i2c are initialized.
Short answer
You can't provide dependency between nodes in this case. But most likely the correct order is already taken care of in your case, and GPIO pin will be set before I2C device initialization, thanks to earlier initcall used for GPIO controller driver, and because gpio-hog is used. If you want to check it for your platform to be sure -- below are details.
Nodes relationship
As stated in Device trees II: The harder parts LWN article:
Naturally, in each case the device which provides the interrupt or GPIO will need to be initialized before it can be found and used. It wasn't very many kernel versions ago that this was a real problem. However in the 3.4 kernel, drivers gained the ability for their initialization (or probe) routine to return the error EPROBE_DEFER which would cause the initialization to be tried again later. So if a driver finds that a GPIO line is listed in the devicetree, but no driver has registered GPIOs for the target node yet, it can fail with EPROBE_DEFER and know it can try again later. This can even be used to remove the need for callbacks and delayed registration in board files, but it is really essential for devicetree, and happily it works quite well.
Alas, in your case it's probably not possible to specify dependency between nodes, so that your i2c1 or gpiom1 depends on gpio2. At least I don't see any gpios properties for I2C controllers or GPIO controllers in Documentation/devicetree/bindings/, that can be used for referencing your en-gpio. So it seems like you should rely on drivers loading order.
Driver dependencies
There are two possible dependencies between drivers:
If drivers are built-in (inside of kernel image): drivers can be initialized at different initcalls, thus being loaded in correct order
If drivers are loadable (.ko files): drivers can have dependencies, defined in kernel build system
As you didn't mention your platform, let's see how it works using BeagleBone Black board for example. You can use this as a template to find out how it's done on your platform.
Static dependencies
Let's check drivers init order:
From am33xx-l4.dtsi file we can see that:
GPIO controller: compatible = "ti,omap4-gpio"
I2C controller: compatible = "ti,omap4-i2c"
I2C device: compatible = "microchip,mcp23008"
Corresponding drivers for those compatible strings are:
GPIO controller: drivers/gpio/gpio-omap.c
I2C controller: drivers/i2c/busses/i2c-omap.c
I2C device: drivers/pinctrl/pinctrl-mcp23s08.c
Those drivers are initialized on next initcalls:
GPIO controller: postcore_initcall (=2)
I2C controller: subsys_initcall (=4)
I2C device: subsys_initcall (=4)
So GPIO controller driver will be initialized before I2C drivers.
Dynamic dependencies
What about dynamic dependencies? From corresponding Makefile and Kconfig files we can see config options and dependencies:
GPIO controller: CONFIG_GPIO_OMAP, tristate, doesn't depend on I2C stuff
I2C controller: CONFIG_I2C_OMA, tristate, doesn't depend on GPIO stuff
I2C device: CONFIG_PINCTRL_MCP23S08, tristate, depends on I2C
So if drivers are loaded in user-space as .ko files, it all depends on the order of their loading, user must take care of it in rootfs. Usually GPIO and I2C controller drivers are built-in, so no need to discuss this further, but just FYI, here is how the order is defined for modprobe tool.
Kernel Configuration
To check how drivers are built (built-in or loadable), one can check .config file. E.g. if multi_v7_defconfig is used:
CONFIG_GPIO_OMAP=y
CONFIG_I2C_OMAP=y
In that case both drivers are built-in, and we know that GPIO driver has earlier initcall than I2C one.
GPIO hogging
You did the right thing by declaring your pin as gpio-hog. You probably already know what it means, but I'll reference the explanation here for everyone else who is interested. From Documentation/devicetree/bindings/gpio/gpio.txt:
The GPIO chip may contain GPIO hog definitions. GPIO hogging is a mechanism
providing automatic GPIO request and configuration as part of the
gpio-controller's driver probe function.
So this is as early as you can get. And if your GPIO controller driver is built-in and has initcall number smaller than one for I2C drivers, you can argue that your en-gpio pin will be set before I2C device driver init.

How to use kernel GPIO descriptor interface

I'm trying to develop a simple Linux kernel module that manages a bunch of sensors/actuators pinned on the GPIO of a Raspberry Pi.
The GPIO functionalities I need are quite simple: get/set pin values, receive IRQs, ...
In my code, I have a misc_device which implements the usual open, read, write and open operations. In my read operation, for instance, I'd like to get the value (high/low) of a specific GPIO pin.
Luckily, the kernel provides an interface for such GPIO operations. Actually, there are two interfaces, according to the official GPIO doc: the legacy one, which is extremely simple yet deprecated, and the new descriptor-based one.
I'd like to use the latter for my project, and I understand how to implement all I need except for one thing: the device tree stuff.
With reference to board.txt, before I can call gpiod_get_index() and later gpiod_get_value(), first I need to setup the device tree somehow like this:
foo_device {
compatible = "acme,foo";
...
led-gpios = <&gpio 15 GPIO_ACTIVE_HIGH>, /* red */
<&gpio 16 GPIO_ACTIVE_HIGH>, /* green */
<&gpio 17 GPIO_ACTIVE_HIGH>; /* blue */
power-gpios = <&gpio 1 GPIO_ACTIVE_LOW>;
};
However, I've absolutely no clue where to put that chunk of code, nor if I really need it. Mind that I have a misc device which looks like this, where aaa_fops contains the read operation:
static struct miscdevice aaa = {
MISC_DYNAMIC_MINOR, "aaa", &aaa_fops
};
Using the old deprecated interface, my problem would be solved because it doesn't require to mess with the device tree, but I'd still like to use the new one if not too complex.
I've read a bunch of documentation, both official and unofficial, but couldn't find a straight and simple answer to my issue. I tried to find an answer in the kernel source code, especially in the drivers section, but only got lost in a valley of complex and messy stuff.
The lack of working, minimal examples (WME) about kernel is significantly slowing down my learning process, just my opinion about it.
Could you please give me a WME of a simple device (preferably a misc) whose read() operation gets the value of a pin, using the new GPIO interface?
If you need more details about my code, just ask. Thanks in advance!
Note 1: I'm aware that most of my work could be done in userspace rather than kernelspace; my project is for educational purposes only, to learn the kernel.
Note 2: I choose a misc device because it's simple, but I can switch to a char device if needed.
... first I need to setup the device tree somehow like this:
...
However, I've absolutely no clue where to put that chunk of code
Device Tree nodes and properties should not be called "code".
Most devices are connected to a peripheral bus, so device nodes typically are child nodes of the peripheral bus node.
Could you please give me a WME of a simple device
You can find numerous examples of descriptor-based GPIO usage in the kernel source.
Since the documentation specifies the GPIO descriptor as a property named
<function>-gpios, a grep of the directory arch/arm/boot/dts for the string "\-gpios" reports many possible examples.
In particular there's
./bcm2835-rpi-b.dts: hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>;
This hpd-gpios property belongs to the hdmi base-node defined in bcm283x.dtsi, and is used by the gpu/drm/vc4/vc4_hdmi.c driver.
/* General HDMI hardware state. */
struct vc4_hdmi {
...
int hpd_gpio;
...
};
static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
{
...
/* Only use the GPIO HPD pin if present in the DT, otherwise
* we'll use the HDMI core's register.
*/
if (of_find_property(dev->of_node, "hpd-gpios", &value)) {
...
hdmi->hpd_gpio = of_get_named_gpio_flags(dev->of_node,
"hpd-gpios", 0,
&hpd_gpio_flags);
if (hdmi->hpd_gpio < 0) {
ret = hdmi->hpd_gpio;
goto err_unprepare_hsm;
}
...
}
If the hpd-gpios property is defined/found and successfully retrieved from the board's DeviceTree, then the driver's structure member hpd_gpio holds the GPIO pin number.
Since this driver does not call devm_gpio_request(), the framework apparently allocates the GPIO pin for the driver.
The driver can then access the GPIO pin.
static enum drm_connector_status
vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
{
...
if (vc4->hdmi->hpd_gpio) {
if (gpio_get_value_cansleep(vc4->hdmi->hpd_gpio) ^
vc4->hdmi->hpd_active_low)
return connector_status_connected;
else
return connector_status_disconnected;
}

Enable hardware SPI on Xillinux

I have a MicroZed board with Xillinux 1.3 running on it. I wanted to interface an external SPI ADC to it, and write an application in linux to read values from the ADC. Zynq device's hardware SPI interface isn't enabled in Xillinux. How can I go about enabling it, I would have to recompile the FSBL and U-boot, but I don't know where to start. Can I just modify the Xillinux's Vivado design and proceed from there or will I have to start from scratch?
You should not have to modify FSBL or U-boot. You should only have to add the SPI controller to the device tree and update the programmable logic so that the SPI pins connect to your ADC.
Xilinx SDK has tools for creating the device tree file, described on the Build Device Tree Blob page.
I usually edit .dts files by hand, but you still need to run dtc to convert them to binary format as described on that page.
For an example, here is a .dts fragment for a zynq-zc770-xm013.dts board enabling SPI connected to a flash chip:
&spi0 {
status = "okay";
num-cs = <4>;
is-decoded-cs = <0>;
eeprom: at25#0 {
at25,byte-len = <8192>;
at25,addr-mode = <2>;
at25,page-size = <32>;
compatible = "atmel,at25";
reg = <2>;
spi-max-frequency = <1000000>;
};
};
you have to do 2 steps.
1- modify the hardware descriptor file (.h) of your board in your kernel sources and add the spi device. First, take a look at the schematic of the board and the datasheet of the processo to make sure to use the right device with the right name
2- add spidev on your kernel config
now build and boot the kernel, if you check on /dev/ you should find spidev** something.

Interpretation of gpio: in fixed-regulator device tree entry?

I'm trying to control (on/off) a voltage regulator that is mapped to a GPIO pin and powers an external device.
The device tree for the regulator has the following entry:
reg_usb1_vbus: usb1_vbus {
compatible = "regulator-fixed";
regulator-name = "usb1_vbus";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
gpio = <&gpio3 28 0>;
enable-active-high;
};
As I read the documentation i got confused for it states:
Optional properties:
gpio: gpio to use for enable control
However, I can't export the sysfs interface of that GPIO and use it to control the power supply (just on/off) for the external device. In addition if I comment out the gpio = <&gpio3 28 0>; from the device tree, the external device gets no power (when it isn't commented the device is always powered).
The regulator has a sysfs interface exported:
80090000.usb-vbus power suspend_standby_state
device state type
microvolts subsystem uevent
name suspend_disk_state
num_users suspend_mem_state
however I can't write to any of the files.
What is the correct way to interpret the gpio: entry?
gpio to use for enable control
In which case I'm missing a mapping between a pin on which I want to have the regulator voltage.
gpio which will have the voltage from the regulator to power some external unit
In which case I'm missing a way to turn it on and off
I'm trying to control (on/off) a voltage regulator that is mapped to a GPIO pin and powers an external device.
...
What is the correct way to interpret the gpio: entry?
Seems like you're asking an XY question.
First the Y part regarding the GPIO.
The gpio DT entry you refer to would be for an enable/disable control by the regulator framework. It is intended for exclusive use by the regulator driver to control the (external?) regulator hardware. It is not intended for software control of the regulator outside the framework by the user (as you are trying to do).
This GPIO is defined as an output in drivers/regulator/core.c:
static int regulator_ena_gpio_request(struct regulator_dev *rdev,
const struct regulator_config *config)
{
...
ret = gpio_request_one(config->ena_gpio,
GPIOF_DIR_OUT | config->ena_gpio_flags,
rdev_get_name(rdev));
...
}
The GPIO pin is not read for "enable control", but has its value set in
regulator_ena_gpio_ctrl() in order to actively enable or disable the (external) regulator.
The inablity to export the same GPIO pin using sysfs when that pin is also declared in the Device Tree is easily explained. Once the driver acquires the specified GPIO for its use (through the DT), it is no longer unused, and you cannot export that GPIO through sysfs anymore.
GPIOs are a managed resource, and need to be allocated and freed (by a driver or sysfs) just like any other resource such as memory. If you were able to export this GPIO that was also used by the driver, then you would be able to put the GPIO into a state that was inconsistent with what the driver was doing. That in turn would lead to an unstable or misbehaving code.
In which case I'm missing a mapping between a pin on which I want to have the regulator voltage.
The GPIO pin specified in the Device Tree is a logic (i.e. digital) output. It is not the regulator output, which would be an analog output.
You should consult the schematic for your board to confirm that this GPIO is connected to a control input of a regulator.
As to the X part regarding enabling/disabling the regulator:
Software control of the regulator's output is documented in Documentation/power/regulator/consumer.txt
A consumer driver can get access to its supply regulator by calling :-
regulator = regulator_get(dev, "Vcc");
A consumer can enable its power supply by calling:-
int regulator_enable(regulator);
A consumer can disable its supply when no longer needed by calling :-
int regulator_disable(regulator);
The 'consumer" is an electronic device that is supplied power by a regulator.
Apparently the intended framework is have the "consumer driver" own and control its regulator, and not allow an external interface (e.g. sysfs) to interfere with this "consumer driver". If you insist on having userland control, then you could implement an ioctl() or sysfs interface to the "consumer driver" (to avoid conflict/contention with the regulator driver).
In which case I'm missing a way to turn it on and off
What you're really looking for seems to be (upper-layer) power management, and that has its own framework, of which regulators is a lower layer (which is normally not accessible for user control). You should study Documentation/driver-api/pm/devices.txt.
I am not extremely familiar with the regulator core in the kernel, but it seems to me that the regulator interface needs to give you access to the GPIO in a different way than the standad export GPIO method.
I have not looked into this, but it is possible the the regulator interface opens up a character device to userspace for control over the regulator. (Don't hold me to that)
I do see in the documentation and in the driver source code drivers/regulator/fixed.c that the GPIO is not a required DT attribute. You might be able to leave it out of the DT in which case the Driver will never acquire your GPIO, then you can manually control it through the standard export GPIO interface.

Documentation for regulator framework with device tree

I would like to know if there is any documentation for the linux kernel regulator framework with device tree. I am totally lost with consumer name and lists. I need to add consumers from device tree but I cant see consumer list at all in the device tree files.
I am using AM335x based custom board based on TI sitara.
By reading both documentation (DeviceTree and Regulator) you should be able to find what you want. But as usual the best documentation is the code itself. The driver ti-abb-regulator is using the DeviceTree and the Regulator framework.
In addition, Federico has already said, there are so-called MFD(MultiFunction) devices. These are often referred PMIC(Power Management IC) that are used in conjunction with a SOC from TI. For AM335x it maybe TPS65217, TPS65910A, TPS65910x, TPS650250, etc. If so, that means some of them you can find follow this link: MFD.
I was just looking into this myself, and my conclusion is that the setup in device tree is pretty different from the way it's done in the board file.
What you'll need to do is to add your drivers to the device tree as well, and then use the "[name]-supply" notation, e.g.:
cpus {
cpu0 {
cpu0-supply = <&omap_tps65912_dcdc1>;
};
};
If you look for this in other board files, you'll see how it works.

Resources