Linux Device Tree: Touch controller failing i2c test - embedded-linux

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.

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.

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

How to read a RFID card using MFRC522

I am trying to read a RFID tag/card using MFRC522. I have used the rfid-master library, and trying to read the card using the "dumpinfo" from "examples". but the serial monitor is showing me this-
WARNING: Communication failure, is the MFRC522 properly connected?
and of course not reading any card when I scan them. I have checked the port and it's connected to its legal comm port.
What can be a reason for this communication failure?
/*
* --------------------------------------------------------------------------------------------------------------------
* Example sketch/program showing how to read data from a PICC to serial.
* --------------------------------------------------------------------------------------------------------------------
* This is a MFRC522 library example; for further details and other examples see: https://github.com/miguelbalboa/rfid
*
* Example sketch/program showing how to read data from a PICC (that is: a RFID Tag or Card) using a MFRC522 based RFID
* Reader on the Arduino SPI interface.
*
* When the Arduino and the MFRC522 module are connected (see the pin layout below), load this sketch into Arduino IDE
* then verify/compile and upload it. To see the output: use Tools, Serial Monitor of the IDE (hit Ctrl+Shft+M). When
* you present a PICC (that is: a RFID Tag or Card) at reading distance of the MFRC522 Reader/PCD, the serial output
* will show the ID/UID, type and any data blocks it can read. Note: you may see "Timeout in communication" messages
* when removing the PICC from reading distance too early.
*
* If your reader supports it, this sketch/program will read all the PICCs presented (that is: multiple tag reading).
* So if you stack two or more PICCs on top of each other and present them to the reader, it will first output all
* details of the first and then the next PICC. Note that this may take some time as all data blocks are dumped, so
* keep the PICCs at reading distance until complete.
*
* #license Released into the public domain.
*
* Typical pin layout used:
* -----------------------------------------------------------------------------------------
* MFRC522 Arduino Arduino Arduino Arduino Arduino
* Reader/PCD Uno/101 Mega Nano v3 Leonardo/Micro Pro Micro
* Signal Pin Pin Pin Pin Pin Pin
* -----------------------------------------------------------------------------------------
* RST/Reset RST 9 5 D9 RESET/ICSP-5 RST
* SPI SS SDA(SS) 10 53 D10 10 10
* SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16
* SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14
* SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15
*/
#include <SPI.h>
#include <MFRC522.h>
#define RST_PIN 9 // Configurable, see typical pin layout above
#define SS_PIN 10 // Configurable, see typical pin layout above
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance
void setup() {
Serial.begin(9600); // Initialize serial communications with the PC
while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)
SPI.begin(); // Init SPI bus
mfrc522.PCD_Init(); // Init MFRC522
mfrc522.PCD_DumpVersionToSerial(); // Show details of PCD - MFRC522 Card Reader details
Serial.println(F("Scan PICC to see UID, SAK, type, and data blocks..."));
}
void loop() {
// Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
if ( ! mfrc522.PICC_IsNewCardPresent()) {
return;
}
// Select one of the cards
if ( ! mfrc522.PICC_ReadCardSerial()) {
return;
}
// Dump debug info about the card; PICC_HaltA() is automatically called
mfrc522.PICC_DumpToSerial(&(mfrc522.uid));
}
Are you the one who soldered the pins of mfrc522? I think you should double check your connection if it was shorted or not. Also if you're using 5v instead of 3.3v it might damage the mfrc522.

Device Tree GPIO Reset

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.)

Example of use pwm_get() in linux kernel

I want to try to use PWM in linux kernel module for my Rasperry Pi. I've successfully enabled PWM via SYSFS interface.
For usage of pwm in kernel modules documentation states:
New users should use the pwm_get() function and pass to it the
consumer device or a consumer name. pwm_put() is used to free the PWM
device. Managed variants of these functions, devm_pwm_get() and
devm_pwm_put(), also exist.
pwm_get function looks like this:
/**
* pwm_get() - look up and request a PWM device
* #dev: device for PWM consumer
* #con_id: consumer name
....
*/
struct pwm_device *pwm_get(struct device *dev, const char *con_id)
Where I can find dev and con_id? I suspect that they should be defined in device tree, but it is only a suspicion.
One example of pwm_get() is available in the Intel PWM backlight
panel driver.
Here it is being used to obtain a PWM source by its name.
/* Get the PWM chip for backlight control */
panel->backlight.pwm = pwm_get(dev->dev, "pwm_backlight");
The PWM provider itself is defined
here...
/* PWM consumed by the Intel GFX */
static struct pwm_lookup crc_pwm_lookup[] = {
PWM_LOOKUP("crystal_cove_pwm", 0, "0000:00:02.0", "pwm_backlight", 0, PWM_POLARITY_NORMAL),
};
...and initialised
here.
/* Add lookup table for crc-pwm */
pwm_add_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup));
pwm-beeper is another example of pwm_get().
beeper->pwm = pwm_get(&pdev->dev, NULL);
A corresponding entry in the device tree is present here.
buzzer {
compatible = "pwm-beeper";
pwms = <&pwm 0 1000000 0>;
pinctrl-names = "default";
pinctrl-0 = <&pwm0_out>;
};
The inline documentation of pwm_get() describes both the ways it can be used.
/**
* pwm_get() - look up and request a PWM device
* #dev: device for PWM consumer
* #con_id: consumer name
*
* Lookup is first attempted using DT. If the device was not instantiated from
* a device tree, a PWM chip and a relative index is looked up via a table
* supplied by board setup code (see pwm_add_table()).
*
* Once a PWM chip has been found the specified PWM device will be requested
* and is ready to be used.
*
* Returns: A pointer to the requested PWM device or an ERR_PTR()-encoded
* error code on failure.
*/

Resources