Share GPIO pins between two instances of the SPI Linux driver for AD7606 ADC - linux

I'm trying to enable two instances of AD7606 SPI driver for AD7606C. In order for ADC to start the conversion GPIO pins for CONVST (conversion start), interrupt pin (BUSY pin) and RESET pin have to be defined in the device tree for the driver to use.
Two ADCs are on the SPI bus, each ADC has it's own chip select pin and interrupt/BUSY pin but CONVST and RESET are hardwired and shared between two ADCs, on the same pins.
Device tree is given below, and platform used is STM32MP157C Odyssey.
&spi2 {
#address-cells = <1>;
#size-cells = <0>;
pinctrl-names = "default", "sleep";
pinctrl-0 = <&spi2_pins_mx>;
pinctrl-1 = <&spi2_sleep_pins_mx>;
status = "okay";
num-cs = <2>;
cs-gpios = <&gpiob 12 GPIO_ACTIVE_LOW>, // ADC CS1
<&gpiod 4 GPIO_ACTIVE_LOW>; // ADC CS2
adc0#0 {
compatible = "adi,ad7606b";
reg = <0>;
spi-max-frequency = <10000000>; // <60MHz if Vdrive > 2.7V, <40MHz if < 2.7V
spi-cpol;
spi-cpha;
avcc-supply = <&vref>;
interrupts = <10 IRQ_TYPE_EDGE_FALLING>; // Port and pin number where BUSY pin is connected
interrupt-parent = <&gpioe>;
adi,conversion-start-gpios = <&gpiof 10 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpioc 0 GPIO_ACTIVE_HIGH>;
adi,sw-mode;
};
adc1#1 {
compatible = "adi,ad7606b";
reg = <1>;
spi-max-frequency = <10000000>;
spi-cpol;
spi-cpha;
avcc-supply = <&vref>;
interrupts = <6 IRQ_TYPE_EDGE_FALLING>;
interrupt-parent = <&gpiod>;
adi,conversion-start-gpios = <&gpiof 10 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpioc 0 GPIO_ACTIVE_HIGH>;
adi,sw-mode;
};
};
The second driver returns probe error -16 (Device or resource busy) because it can't use CONVST and RESET pins that previous driver already allocated.
The second ADC actually works if I assign some random unused GPIOs, read the value from the first ADC (in order to activate CONVST pin), then read the value from second ADC. This is a workaround used currently.
My question is, is it possible somehow to share GPIO pins between two instances of the same driver in Linux?

Related

How to set GPIO pin output value in device tree

I am using an iMX6 based board and I'd like to set the GPIO value of an arbirtrary ouput to 1 or 0 at boot using the Device Tree.
Is it possible and how can I do that?
I wonder if I have to rely on the gpio-leds feature or if I can define a new node in the DT.
I found some topics on the internet saying I can do as below but doesn't work.
test {
compatible = "gpio-leds";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gpio_leds>;
myout {
label = "myoutlabel";
gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
};
pinctrl_gpio_leds: gpioledsgrp {
fsl,pins = <
MX6QDL_PAD_GPIO_8__GPIO1_IO08 0x80000000 // My output
>;
};
Any hint would be appreciated.
TIA
You can enable/disable the internal Pull-Up/Pull-Down resistor (along with other electrical characteristics) that is attached to that pin, thus forcing a logic 1/0 in the pin. You should seek the "pad control register" for that pad (IOMUXC_SW_PAD_CTL_PAD_GPIO_8) in the processor reference manual, and then look which characteristics you wish to enable/disable by setting the right bits to 1 or 0, as needed, in the aforementioned register. However, I'm not sure if this is exactly what you're looking for.
Maybe this can help to understand the operation: http://cache.freescale.com/files/32bit/doc/app_note/AN5078.pdf

#interrupt-cells is 2 but interrupts is a 3-tuple

I was looking at the device tree for the Beagle Bone Black and started with am57xx-beagle-x15.dts. Drilling down into dra7.dtsi I found gpio1:
gpio1: gpio#4ae10000 {
compatible = "ti,omap4-gpio";
reg = <0x4ae10000 0x200>;
interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "gpio1";
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
};
I had read that #interrupt-cells gave the number of u32s or cells that one would expect in an item in the the interrupts list. But when I look at interrupts I see a 3-tuple: <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>. Would love to know, why does this contain 3 cells and not 2?
It's a very late answer but add one so that someone could get help.
I can't find the exact dts file from my current linux 5.15 source. But the interrupt-parent of the node should have required 3 cells for the interrupts property. For gic, normally it requires 3 values - {interrupt type, interrupt number, flag}. It's in the device binding document of gic (Documentation/devicetree/bindings/interrupt-controller/arm,gic.yaml in linux 5.15)
"#interrupt-cells":
const: 3
description: |
The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI
interrupts.
The 2nd cell contains the interrupt number for the interrupt type.
SPI interrupts are in the range [0-987]. PPI interrupts are in the
range [0-15].
The 3rd cell is the flags, encoded as follows:
bits[3:0] trigger type and level flags.
1 = low-to-high edge triggered
2 = high-to-low edge triggered (invalid for SPIs)
4 = active high level-sensitive
8 = active low level-sensitive (invalid for SPIs).
bits[15:8] PPI interrupt cpu mask. Each bit corresponds to each of
the 8 possible cpus attached to the GIC. A bit set to '1' indicated
the interrupt is wired to that CPU. Only valid for PPI interrupts.
Also note that the configurability of PPI interrupts is IMPLEMENTATION
DEFINED and as such not guaranteed to be present (most SoC available
in 2014 seem to ignore the setting of this flag and use the hardware
default value).

Linux driver for quad spi on Zedboard

I am quite new SoC, and I am currently working with the evaluation platform Zedboard. I have included a quad SPI in my block design and want to communicate with it through Linux running on one of the ARM processors. I need the SPI to transmit/receive 32bits in one burst and handle the communication from C++. However, I can't get it working.
The quad SPI is setup as standard, no FIFO and transaction width = 32 bits. I have updated the Linux device tree as follows:
axi_quad_spi_0#41E00000 {
compatible = "xlnx,xps-spi-2.00.b", "xlnx,xps-spi-2.00.a";
#address-cells = <0x1>;
#size-cells = <0x0>;
interrupt-parent = <0x2>;
interrupts = <0x0 0x39 0x1>;
reg = <0x41e00000 0xffff>;
xlnx,fifo-exist = <0x0>;
xlnx,num-ss-bits = <0x2>;
xlnx,num-transfer-bits = <0x20>;
xlnx,sck-ratio = <0x10>;
device#0 {
compatible = "spidev";
reg = <0x0>;
spi-max-frequency = <0x5f5e10>;
};
device#1 {
compatible = "spidev";
reg = <0x1>;
spi-max-frequency = <0x5f5e10>;
};
After this I can see spidev0.0 and spidev.0.1 in /dev as expected. Furthermore, when writing to the device files with bits_per_word = 8 I get an 8bit burst out of the quad SPI but with 32 clock periods, i.e. I get the first byte out corresponding to 1/4 of the 32 bit burst (seen with debug probes in Vivado). I guess I see this because the transaction width is set to 32bits.
However, when I want to change the burst to 32 bit (bits_per_word = 32) it doesn't work - I get the message "xilinx_spi_setup_transfer, unsupported bits_per_word=32" in my Linux terminal.
I use the following code in C++:
uint8_t tx[] = { 0xAD, 0xEF, 0x01, 0x23 };
uint8_t rx[4] = { 0 };
struct spi_ioc_transfer tr[2];
tr[0].tx_buf = (unsigned long)tx;
tr[0].rx_buf = (unsigned long)rx;
tr[0].len = 4;
tr[0].delay_usecs = delay;
tr[0].speed_hz = speed;
tr[0].bits_per_word = 32;
tr[0].cs_change = 0;
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
I have tried to compile the xilinx driver xilinx-spi.c but when I try to install it (with "modprobe xilinx_spi" in Linux) it says that the "Device or ressource busy".
How do I get this to support 32bit so I can transmit/receive 32bits in one burst? Can anybody help me out here? Thanks!
Br. Jacob

Linux interrupt is not handled by the wrapper driver

I am writing a device specific DMA driver for Zynq AXI DMA. The driver is actually a wrapper driver and uses Xilinx DMA driver under the DMA engine driver framework like this:
+------------------+
| Wrapper driver |
+------------------+
| DMA framework |
+------------------+
| Xilinx DMA Driver|
+------------------+
+ Kernel +
+------------------+
I use interrupt 61 for transfer complete and 62 for receive complete. The interrupt handler for Xilinx DMA driver is properly installed (I checked /proc/interrupts). However, I the driver seems not to handle the interrupt properly by showing me this:
I checked /proc/interrupts. IRQ62 is not handled. Here is the code where the interrupt is registered:
0986 /* find the IRQ line, if it exists in the device tree */
0987 chan->irq = irq_of_parse_and_map(node, 0);
0988 err = devm_request_irq(xdev->dev, chan->irq, dma_intr_handler,
0989 IRQF_SHARED,
0990 "xilinx-dma-controller", chan);
And here is the output of cat /proc/interrupt:
I have two questions:
1) If I only install interrupt handler for Xilinx DMA driver but not the wrapper driver, while I use the wrapper driver as the char device, interrupt will not be handled by the Xilinx DMA driver?
2) If so, how do I let Xilinx DMA driver to handle the interrupt in this case? Is 'irqpoll' the only solution? Is there any performance issue compared to direct interrupt handling rather than polling?
Your devicetree isn't good, more precisely, your pl.dtsi file. My pl file looks like this:
amba_pl: amba_pl {
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
ranges ;
axi_dma_0: dma#40400000 {
compatible = "xlnx,axi-dma";
interrupt-parent = <&intc>;
interrupts = <0 29 4 0 30 4>;
reg = <0x40400000 0x10000>;
xlnx,include-sg ;
dma-channel#40400000 {
compatible = "xlnx,axi-dma-mm2s-channel";
interrupts = <0 29 4>;
xlnx,datawidth = <0x20>;
xlnx,device-id = <0x0>;
};
dma-channel#40400030 {
compatible = "xlnx,axi-dma-s2mm-channel";
interrupts = <0 30 4>;
xlnx,datawidth = <0x20>;
xlnx,device-id = <0x0>;
};
};
};

Understanding the Device Tree mechanism

Was reading the Device Tree Usage and reached to the section describing the ranges key attribute for a node.
external-bus {
#address-cells = <2>
#size-cells = <1>;
ranges = <0 0 0x10100000 0x10000 // Chipselect 1, Ethernet
1 0 0x10160000 0x10000 // Chipselect 2, i2c controller
2 0 0x30000000 0x1000000>; // Chipselect 3, NOR Flash
ethernet#0,0 {
compatible = "smc,smc91c111";
reg = <0 0 0x1000>;
interrupts = < 5 2 >;
};
i2c#1,0 {
compatible = "acme,a1234-i2c-bus";
#address-cells = <1>;
#size-cells = <0>;
reg = <1 0 0x1000>;
interrupts = < 6 2 >;
rtc#58 {
compatible = "maxim,ds1338";
reg = <58>;
interrupts = < 7 3 >;
};
};
flash#2,0 {
compatible = "samsung,k8f1315ebm", "cfi-flash";
reg = <2 0 0x4000000>;
};
};
What is the difference between ranges and reg ?
What are the dimensions for the ranges, how the parser figure out what is written in it?
One missing part I didn't understand yet? Can't include .h files instead of hard-coding values in a the .dts file?
The "range" property maps one or more addresses (the second number from the left of the range) in the current node, the "external bus" node, to addresses in the parent node (probably the CPU) address space (the third number in the range). The fourth number is the length of the range. Buses can have their own idea of addresses on their external side to which peripherals are attached, so the drivers that manage the peripherals on the bus will need to know these ranges in order to read to or write from the the devices.
The "reg" property indicates the address at which a device resides in the address range of the node (the "external bus" in this case) in which the device is defined. So in this case, flash#2,0 resides at address 0 in the external bus range, and extends to address 0x04000000. This corresponds to address range 0x30000000 to 0x34000000 in the parent (CPU) address space.
I am assuming that the length specifier of the third range, 2 0 0x30000000 0x1000000>; // Chipselect 3, NOR Flash should in fact be 0x04000000 rather than 0x1000000.
For this perticular example, Jonathan Ben-Avraham's explanation is correct. But its good to understand the detailed structure of ranges property in device tree.
ranges is a list of address translations.
Each entry in the ranges table is a tuple containing the child
address, the parent address, and the size of the region in the child
address space.
like
ranges = < Child1Address ParentAddressForChild1 sizeofchild1
Child2Address ParentAddressForChild2 sizeofchild2
Child3Address ParentAddressForChild3 sizeofchild3
>;
The size of each field is determined as below
For taking the child Address size check #address-cells value of child node.
For taling the the parent address size check #address-cells value of its parent node,
For taking the length of size check #size-cells value of child node.
Exampe1: Mentioned in as Question
#address-cells = <1>;
#size-cells = <1>;
external-bus {
#address-cells = <2>;
#size-cells = <1>;
ranges = <0 0 0x10100000 0x10000 // Chipselect 1, Ethernet
1 0 0x10160000 0x10000 // Chipselect 2, i2c controller
2 0 0x30000000 0x1000000>; // Chipselect 3, NOR Flash
Let's decode first entry.
Child address-cells size is 2 so first two entry mention child address. (This address is specific to local child addressing only)
Further how to decode these 2 entry are device specific. Device driver should have documentation for these)
parent address-cells size is 1 so next entry is of parent address for that child.
child size-cells is 1 so next entry is of child's range (wrt to parent address.)
Exampe2: PCI device entry
#address-cells = <1>;
#size-cells = <1>;
pci#0x10180000 {
compatible = "arm,versatile-pci-hostbridge", "pci";
reg = <0x10180000 0x1000>;
interrupts = <8 0>;
bus-range = <0 0>;
#address-cells = <3>
#size-cells = <2>;
ranges = <0x42000000 0 0x80000000 0x80000000 0 0x20000000
0x02000000 0 0xa0000000 0xa0000000 0 0x10000000
0x01000000 0 0x00000000 0xb0000000 0 0x01000000>;
Here
0x42000000 0 0x80000000 is the address of child1. How to decode these 3 entry is mentioned in PCI driver documentation.
0x80000000 is the parent address. Parent node is cpu so from cpu this address is used to talk to this devide.
0 0x20000000 is the size of this device in parent address space. (0 to 512MB of address)

Resources