Handling pin modes from devicetree to module - linux

I am trying to write a linux device driver for a SPI device, using Atmels SAMA5d35 MPU. Linux version is 4.19.30.
I have configured the pins in my device tree and set the status to "okay".
After that the pins changed mode as expected. My question is then, how do I manipulate pinmodes during runtime? My SPI device is not always on, neither is my driver always loaded. When that is the case I want the configured SPI pins to change mode to normal GPIOs (for power-consumption).
Is it the drivers task to do that, or is it something one can define in the device tree, when the driver for example is not loaded?
I have tried to implement a pinctrl-0 for setting the pins to SPI mode, and then a pinctrl-1 for setting the same pins to normal GPIOs. My idea was to switch between these pin configuration in the device driver, but unfortunately the device tree complaints about using the same pins for both pinctrl-0 and pinctrl-1 (compiles fine, but system wont boot). Although this was just my logical thoughts. I am sure there is a more correct way to do the things I stated above.
spi0: spi#f0004000 {
status = "okay";
ext_adc: ads1258#1 {
compatible = "ti,ads1258";
pinctrl-names = "default", "sleep";
pinctrl-0 = <&pinctrl_spi0_default>;
pinctrl-1 = <&pinctrl_spi0_sleep>;
reg = <1>; /* Hardware chipselect SPI0_NPCS1 */
spi-max-frequency = <16000000>; /* According to datasheet */
start-gpios = <&pioD 5 GPIO_ACTIVE_HIGH>;
drdy-gpios = <&pioD 22 GPIO_ACTIVE_LOW>;
enaadc-gpios = <&pioA 26 GPIO_ACTIVE_HIGH>;
};
};

My question is then, how do I manipulate pinmodes during runtime?
That's called "Runtime pinmuxing", which is described in Documentation/pinctrl.txt.
But you may not have to do that.
When that is the case I want the configured SPI pins to change mode to normal GPIOs (for power-consumption).
Is it the drivers task to do that, or is it something one can define in the device tree, when the driver for example is not loaded?
The default mode for a pin (of Atmel/Microchip SoCs) is to be unassigned to any peripheral mode, and be available for use as a GPIO.
All pins that are not assigned to a peripheral or acquired by a driver as a GPIO, end up in the pool of available GPIOs.
So when your SPI driver is not successfully installed, those pins it would use will be in the pool of available GPIOs.
I have tried to implement a pinctrl-0 for setting the pins to SPI mode, and then a pinctrl-1 for setting the same pins to normal GPIOs.
Assigning pins for use by the SPI controller is proper, but there is no mechanism AFAIK for assigning a pin to be an available GPIO.
You can only define properties in the DT for what a device, such as the SPI controller, requires.
There is no mechanism for an "alternate" assignment.
I am sure there is a more correct way to do the things I stated above.
If your driver does not install, then its resources such as its pins should not be allocated. The pins that the SPI would have used will remain unused, and end up in the pool of available GPIOs (unless something else claims/requests one of those pins).
So your DT needs to simply define what your device uses, and leave it at that.
If you still want your driver to modify the state of its pin, then study the section titled "Pin control requests from drivers" in Documentation/pinctrl.txt.

Related

vbus regulator device tree

can someone explain the device tree settings? What they will do on i.MX6 Processor?
Thanks!
vbus1_regulator: regulator#1 {
compatible = "regulator-fixed";
regulator-name = "vbus1_regulator";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
gpio = <&gpio3 22 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
&usbotg {
vbus-supply = <&vbus1_regulator>;
dr_mode = "host";
status = "okay";
};
The USB protocol defines two roles - host and client. With USB OTG (on-the-go) a device can have both host and client capabilities. See:
http://www.usb.org/developers/onthego/
https://www.maximintegrated.com/en/app-notes/index.mvp/id/1822
In order for the device to work as a host, it needs to provide power for the client device connected to it, as required by the USB standard.
That being said, the &usbotg node is:
Using the _vbus1_regulator_ as USB power supply.
Forcing the USB OTG port to work as host by setting the dr_mode property to host.
Enabling the node by setting the status to okay.
Please see the Linux kernel device-tree bindings documentation for more details:
https://www.kernel.org/doc/Documentation/devicetree/bindings/usb/fsl-usb.txt
And the vbus1_regulator node is:
Using the kernel driver compatible to regulator-fixed: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/regulator/fixed.c?h=v4.19-rc1#n196
Setting the name of the regulator to vbus1_regulator.
Defining the minimum and maximum voltages to the same value of 5000000 micro volts, which as the same as 5 volts. Both are the same due to the nature of a fixed voltage regulator - you have a single fixed output voltage value.
Using a GPIO pin (declared elsewhere) to control the regulator (switch on/off).
Defining that the GPIO level must be high in order to activate the regulator. If this property is omitted, that it is assumed that the regulator is active on logic level low.
Please see the Linux kernel device-tree bindings documentaiton for more details:
https://www.kernel.org/doc/Documentation/devicetree/bindings/regulator/fixed-regulator.txt

Linux I2C kernel driver binding

I am learning about how to develop a Linux I2C kernel driver, and I learn from websites below.
How to instantiate I2C devices
I2C Driver for Linux Based Embedded System
...
Next, I found a sample that shows how to implement a I2C touchpad driver, but it really confused me.
linux/drivers/input/mouse/synaptics_i2c.c
My question is, how Linux kernel bind this driver to correctly device? This driver don't provide 'detect' callback, no specify the I2C slave address via i2c_driver.address_list, and there is seems no anyone to call i2c_board_info to register the address info (I grep a whole Linux codebase).
I thought the driver MUST be specify the slave address or provide the 'detect' callback, just like
drivers/hwmon/adc128d818.c
or
linux/drivers/rtc/rtc-ds1307.c (it will be register by i2c_board_info)
Please let me know what I missed, thanks.
The i2c device declaration is start from device tree.
Declare the i2c devices in device tree.
Example:
i2c1: i2c#400a0000 {
/* ... master properties skipped ... */
clock-frequency = <100000>;
flash#50 {
compatible = "atmel,24c256";
reg = <0x50>;
};
pca9532: gpio#60 {
compatible = "nxp,pca9532";
gpio-controller;
#gpio-cells = <2>;
reg = <0x60>;
};
};
Where,
1) 400a000 is a i2c bus address
2) pca9532 and flash are driver names
3) #50 and #60 are slave address
4) the attribute “compatible” to find and map device with the driver
5) other attribute which is inside cell of each entries are specific to the driver which will be used for device initialization during the probe
https://www.kernel.org/doc/Documentation/i2c/instantiating-devices
I finally figured out my question.
Refer to http://www.embedded-bits.co.uk/2009/i2c-in-the-2632-linux-kernel/
There is need to register my I2C device with i2c_new_probed_device() or i2c_new_device on Kernel to let it have a mapping table about slave address and device name.

How to set a pin between boot and module load for an embedded Linux?

I am facing an interesting problem. I like to set a pin of my cpu. So far I created a module for controlling the pin. This module is setting the default pin configuration(high). The default pin configuration becomes active when the module is loaded. That is working fine.
Now I like to enable my default pin configuration right away from the start of boot process. To archive that I wrote a patch for the ATMEL bootloader(at91bootstrap) and the uboot(u-boot-at91). This works fine till the moment the kernel starts. At the kernel start the pins is set to the ATMEL default. They pins are defined in the device tree as gpios.
I think I have two possibilities:
1st - patch the /init/main.c at the "right" spot. Where is the right spot?
2nd - modify the device tree to set the GPIOs to an other default value. How to "re set" an gpio a value?
When you modify the pin in u-boot level; it will be override by the kernel. /init/main.c is worse idea and so I think you should not followed this approach
In kernel level if you you want to set the GPIO pin, there are two possibilities (apart from your module)
1) Kernel board file.
2) Device tree file.
Suppose if you want to set the SDIO pin as GPIO in i.MX6 board then you need to modify the code like this.
leds {
compatible = "gpio-leds";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gpio_leds>;
red {
gpios = <&gpio7 0 0>;
default-state = "on";
};
MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x1b0b0 //set the pin as GPIO
For the default state of the pin please refer the datasheet of your processor. And one pin may have different functionalities.
And if you want to use the same pin for some other functionalities instead of GPIO then you can choose on of the below configuration.
MX6QDL_PAD_SD3_DAT5__UART2_RX_DATA //UART2 RX Data pin
MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 //As a GPIO pin
MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA // UART1 RX data
MX6QDL_PAD_SD3_DAT6__SD3_DATA6 //SDIO pin which is default in this case
Please add more details if you are looking for something more (like pin number and device tree file name).

Linux - Is it necessary to register (instantiate) i2c devices before using them?

I'm confused on how userspace programs using Linux's i2c dev interface is able to register (instantiate?) i2c devices.
From my understanding by reading this: https://www.kernel.org/doc/Documentation/i2c/instantiating-devices, it seems we need to either:
Define a i2c_board_info struct with name and address of the i2c
device, do a i2c_register_board_info()
Have a devicetree entry such as this:
i2c1: i2c#400a0000 {
/* ... master properties skipped ... */
clock-frequency = <100000>;
flash#50 {
compatible = "atmel,24c256";
reg = <0x50>;
};
pca9532: gpio#60 {
compatible = "nxp,pca9532";
gpio-controller;
#gpio-cells = <2>;
reg = <0x60>;
};
};
Instantiate devies explicitly by defining a i2c_board_info struct, then call i2c_new_device() in the init of the i2c device driver
But how is this done for user space programs using the i2c-dev interface described here https://www.kernel.org/doc/Documentation/i2c/dev-interface?
I don't have a devicetree entry, and when I grep the code for i2c_board_info, i2c_register_board_info(), or i2c_new_device() I don't find anything. But the code below still works, how?
#include <linux/i2c-dev.h>
void read_from_device(uint8_t *read_data)
{
int result;
file_desc = open("/dev/i2c-2", O_RDWR);
ioctl(file_desc, I2C_SLAVE, device_address);
i2c_smbus_write_byte_data(file_desc, DEVICE_PAGE_ADDRESS, page_number);
result = i2c_smbus_read_byte_data(file_desc, device_register_address);
*read_data = result;
close(file_desc);
}
Does this mean we don't necessarily have to register (instantiate) i2c devices in order to use them? Does that apply to both i2c drivers as well as userspace programs using i2c-dev interface?
The i2c-dev driver binds to the bus (i2c_adapter), not a specific i2c device (i2c_client). So you only need to create the bus device to use i2c-dev and adding devices for the clients isn't necessary. In fact, you'll find i2c-dev will not let you use an I2C address bound to another driver unless you use the I2C_SLAVE_FORCE ioctl.
This is the opposite to the spidev driver, which binds to a specific spi slave device and not the bus as a whole. I2C predates the modern Linux device model and some things are different than is done in other places.
If you want a kernel driver to control the I2C device then there needs to be a device for the driver to bind to. The exception would be so-called "old style" I2C drivers which probe a set of addresses and bind to devices if any are found that appear to be the correct kind.

Named GPIOs in DeviceTree

I am trying to create a device tree for an embedded system, and would like to expose a few GPIOs to userspace. These are not and should not be used by kernel drivers. For instance, there is a USB device soldered to the board that is controlled by a user-space driver. It has a GPIO reset line, which the userspace library needs to access.
I would like these to be exposed by name in sysfs somewhere so that userspace can access /sys/class/gpio/usbreset instead of needing to know the magic gpio number and needing to specifically "export" it. I have tried setting it up as a GPIO hog, which initializes the GPIO, but its name does not appear in sysfs, and the gpio cannot be exported when it is hogged. I know that I can pick another kernel driver type such as LED, but it is not an LED, and this does not seem very clean to me.
What is the right way to export a named GPIO in sysfs?
You can use the "gpio-leds" type in the devtree. Make sure you have CONFIG_LEDS_GPIO in your kernel. Set up your devtree as described in Documentation/devicetree/bindings/leds/leds-gpio.txt. I know, it says "LED", but the driver just wiggles the GPIO, and doesn't care what's hooked up to it.
Example devtree entry (copied from the docs):
run-control {
compatible = "gpio-leds";
red {
gpios = <&mpc8572 6 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
green {
gpios = <&mpc8572 7 GPIO_ACTIVE_HIGH>;
default-state = "on";
};
};
Those entries will be accessible by name in sysfs, and you can manipulate them from userspace there.
I propose writing a simple kernel module to ask for the GPIO and then exporting a link, the link can be named and hence suitable for your request.
https://www.kernel.org/doc/Documentation/gpio/sysfs.txt
from the link above:
After the GPIO has been exported, gpiod_export_link() allows creating
symlinks from elsewhere in sysfs to the GPIO sysfs node. Drivers can
use this to provide the interface under their own device in sysfs with
a descriptive name

Resources