I am currently writing a device tree node to configure SCISIS752 Dual Channel UART with I2C which is connected to the slave address 0x4d. I am also using a clock of 1.8432MHz. The IRQ pin of SCISIS752 is attached to an IO Expander GPIO which is gpiopin 456 in my case.
I am using yocto to create the linux distro. My linux kernel version 4.18.25-yocto-standard
My dts configuration:
/dts-v1/;
#include "am33xx.dtsi"
#include "am335x-bone-common.dtsi"
#include "am335x-boneblack-common.dtsi"
/ {
model = "TI AM335x BeagleBone Black";
compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
};
&am33xx_pinmux {
pinctrl-0 = <&gpio_pins>;
i2c1_pins_default: i2c1_pins_default {
pinctrl-single,pins = <
AM33XX_IOPAD(0x984, PIN_INPUT_PULLUP | MUX_MODE3) /* (D15) uart1_txd.I2C1_SCL */
AM33XX_IOPAD(0x980, PIN_INPUT_PULLUP | MUX_MODE3) /* (D16) uart1_rxd.I2C1_SDA */
>;};
&i2c1 {
pinctrl-names = "default";
pinctrl-0 = <&i2c1_pins_default>;
status = "okay";
clock-frequency = <400000>;
pcf8574a_38: pcf8574a#38 {
compatible = "nxp,pcf8574a";
reg = <0x38>;
gpio-controller;
#gpio-cells = <2>;
};
sc16is752#4d {
compatible = "nxp,sc16is752";
reg = <0x4d>;
clocks = <&sc16is752_clk>;
interrupt-parent = <&gpio3>;
interrupts = <7 2>;
gpio-controller;
#gpio-cells = <2>;
sc16is752_clk: sc16is752_clk {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <1843200>;
};};
};
I am confused on setting the values of interrupt-parent and interrupts to make this configuration work.
I cannot see your entire device tree, nor do I know what kernel you are running... so I can't point to where your exact problem is. But I can provide some guidance in troubleshooting...
First, it appears you've copied your node from the kernel documentation in Documentation/devicetree/bindings/serial/nxp,sc16is7xx.txt. That is a point of reference, but it's simply meant to illustrate.
There is nothing magical about the device tree. It is parsed by drivers in the kernel to describe the electrical configuration. Which means, anytime you're not sure how something works, all you need to do is look at the driver to see how it parses it.
I happen to have the 4.19.0 source code on me. I found your NXP driver in drivers/tty/serial/sc16is7xx.c. I confirmed through the compatible list that it supports nxp,sc16is752.
Start at the probe sc16is7xx_i2c_probe() where the driver is entered and you will immediately see that an IRQ value is being passed in through the i2c_client structure and then setup by the call to devm_request_irq() in sc16is7xx_probe(). This means that the interrupt DT properties aren't processed in this driver. They are passed to it.
You then need to read: https://www.kernel.org/doc/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt to understand how interrupt controllers work. Does your &gpio3 meet the requirements? Is it configured as an interrupt controller? Does the it even exist?
Related
I am writing a kernel platform device driver for booting group of remoteprocs. I am iterating over the groups of remoteprocs (child device nodes) and iomap them by their indexes inside the group with the help of for_each_child_of_node() macro. driver fails on the first devm_of_iomap() function call attempt. Now, I suspected that the platform device driver framework is not recognizing the resources inside the child device nodes (and I was right!), hence I have printed the device resources number from platform.c platform_get_resource() function and the result was 1 (which is the shared-buffer resource).
The Q: Maintaining the current DT format, how can I retrieve (or make them visible to the platform framework) these inner resources (adsp_dtcm, adsp_conf...etc) inside for loop?
// Device Tree
// ----------------------------
// Not the real values of course
// ----------------------------
dsp-cluster {
#address-cells = <2>;
#size-cells = <2>;
compatible = "xxxxxx,dsp_remoteproc";
dsp_count = <2>;
reg = <0x0 0x10000000 0x0 0x100000>; // the only one that recognized by platform framework
reg-names = "share-buffer";
dsp#0 {
reg = <0x0 0xfff00000 0x0 0x40000>,
<0x0 0xfffc0000 0x0 0x20000>,
<0x0 0xfff00000 0x0 0x20000>,
<0x0 0xfffa0000 0x0 0x20000>,
<0x0 0xfffc0000 0x0 0x4000>,
<0x0 0xfffc8000 0x0 0x8000>,
<0x0 0xfffd0000 0x0 0x8000>;
reg-names = "adsp_dtcm", "adsp_conf", "vdsp_dtcm", "vdsp_conf",
"cdsp_dtcm", "cdsp_itcm", "cdsp_conf";
};
dsp#1 {
reg = <0x0 0x10400000 0x0 0x40000>,
<0x0 0xxxx0000 0x0 0x20000>,
<0x0 0xyyy00000 0x0 0x20000>,
<0x0 0xzzza0000 0x0 0x20000>,
<0x0 0xxxxc0000 0x0 0x4000>,
<0x0 0xyyyc8000 0x0 0x8000>,
<0x0 0xeeed0000 0x0 0x8000>;
reg-names = "adsp_dtcm", "adsp_conf", "vdsp_dtcm", "vdsp_conf",
"cdsp_dtcm", "cdsp_itcm", "cdsp_conf";
};
};
My driver code (only the section that trying to iterate and iomap these all resources inside dsp#0 and dsp#1):
static int dsp_remoteproc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
u32 dsp_count = 1;
int ret;
struct device_node *dev_node = dev->of_node;
struct device_node *child = NULL;
unsigned j = 0;
if (of_property_read_u32(dev->of_node, "dsp_count ", &dsp_count))
dev_warn(dev, "dsp_count property not exist, defaulting to 1\n");
for_each_child_of_node(dev_node, child) {
if (!child || (j++ > dsp_count))
break;
void __iomem *iomap_ret;
// iomap adsp conf regs
iomap_ret = devm_of_iomap(dev, dev_node, 1, NULL);
if (IS_ERR(iomap_ret))
return -ENODEV;
}
Translation of addresses in a node's reg property relies on the presence of a ranges property in the parent node. This is checked by the of_translate_one function in "drivers/of/address.c", an extract of which is shown below:
/*
* Normally, an absence of a "ranges" property means we are
* crossing a non-translatable boundary, and thus the addresses
* below the current cannot be converted to CPU physical ones.
* Unfortunately, while this is very clear in the spec, it's not
* what Apple understood, and they do have things like /uni-n or
* /ht nodes with no "ranges" property and a lot of perfectly
* useable mapped devices below them. Thus we treat the absence of
* "ranges" as equivalent to an empty "ranges" property which means
* a 1:1 translation at that level. It's up to the caller not to try
* to translate addresses that aren't supposed to be translated in
* the first place. --BenH.
*
* As far as we know, this damage only exists on Apple machines, so
* This code is only enabled on powerpc. --gcl
*
* This quirk also applies for 'dma-ranges' which frequently exist in
* child nodes without 'dma-ranges' in the parent nodes. --RobH
*/
ranges = of_get_property(parent, rprop, &rlen);
if (ranges == NULL && !of_empty_ranges_quirk(parent) &&
strcmp(rprop, "dma-ranges")) {
pr_debug("no ranges; cannot translate\n");
return 1;
}
Here, parent is the parent node, rprop is the string "ranges" for a normal range (the same function is also used for translating DMA addresses, where rprop would be the string "dma-ranges"), and the non-zero return value indicates failure. (Don't worry about the !of_empty_ranges_quirk(parent). That is just for some weird special cases.) If the parent node doesn't have the ranges property (for a normal range) then the ranges variable will be NULL and the function will return 1 to indicate failure to translate the address.
You may wonder why the code doesn't search up the tree until it finds a ranges property. The reason is that not all reg properties are used for translating physical addresses. This is explained in Device Tree Usage # Ranges (Address Translation) when discussing the reg property for the rtc#58 node (an I2C device) whose parent is the i2c#1,0 node:
You should also notice that there is no ranges property in the i2c#1,0 node. The reason for this is that unlike the external bus, devices on the i2c bus are not memory mapped on the CPU's address domain. Instead, the CPU indirectly accesses the rtc#58 device via the i2c#1,0 device. The lack of a ranges property means that a device cannot be directly accessed by any device other than it's parent.
I have an OrangePi PC Plus board which runs Linux (ubuntu 18.04) with kernel 4.19.57 on Allwinner H3 processor.
We have designed a hardware watchdog using STWD100 ASIC. This IC has a gpio which should be toggled at least once a second, otherwise it resets the board. On the other hand, I have googled on this subject and I realized that Linux kernel has a driver called GPIO watchdog (in drivers/watchdog/gpio_wdt.c file).
Because of the project requirement, watchdog GPIO is connected to pin PA19 of processor should begin toggling as soon as the kernel is decompressed and executed, or board is forced reboot by STWD100. For making the issue more complicated, I should add that we can not make any circuit modification. In order to prevent STWD100 from resetting our board before the kernel is loaded, we have a timer which disables STWD100 for about 5~8 seconds and we can not change this time interval (because it is fixed in the circuit). Therefore, we should run our GPIO watchdog driver in Linux kernel as soon as control is passed to the kernel.
What I have done so far:
Added printk("============================\n"); to gpio_wdt_probe() function of gpio-watchdog driver.
Cross-compiled kernel with CONFIG_GPIO_WATCHDOG=y, CONFIG_GPIO_WATCHDOG_ARCH_INITCALL=y.
Decompiled board device tree using dtc to get device tree source code from dtb file.
Modified my device tree source code as follows (according to this link):
/dts-v1/;
/ {
...
soc {
...
pinctrl#1c20800 {
...
phandle = <0x0a>;
/* Node added by me */
gpio_wdt: gpio_wdt {
pins = "PA19";
function = "gpio_out";
phandle = <0x74>;
};
/* Node added by me */
gpio1: gpio1 {
gpio-controller;
#gpio-cells = <2>;
};
};
...
/* This node is part of original dts file which triggers internal processor watchdog*/
watchdog#1c20ca0 {
compatible = "allwinner,sun6i-a31-wdt";
reg = <0x1c20ca0 0x20>;
interrupts = <0x00 0x19 0x04>;
phandle = <0x57>;
};
...
};
...
/* Node added by me */
watchdog-gpio {
compatible = "linux,wdt-gpio";
gpios = <&gpio1 19 1>; /* PA19 should be toggled */
hw_algo = "toggle";
hw_margin_ms = <200>;
always-running;
phandle = <0x75>;
};
...
__symbols__ {
...
/* Symbol added by me */
gpiowdt = "/watchdog-gpio";
};
};
In the source ... depicts some other nodes which I did not modify.
compiled modified device tree using dtc command.
When kernel runs, I can see ============================ in multiple occasions in kernel logs on UART port. This demonstrates that my builtin GPIO watchdog driver is being probed, but my PA19 pin is not toggling.
In the case above, I do not get any warning from dtc compiler, but if I replace gpio_wdt instead of gpio1 in the watchdog-gpio node, when compiling device tree I get the following warning from dtc compiler:
Warning (gpios_property): /watchdog-gpio: Missing property '#gpio-cells' in node /soc/pinctrl#1c20800/gpio_wdt or bad phandle (referred from gpios[0])
Could anyone help me find the issue?
Eventually, I found the solution.
Definition of neither gpio1 nor gpio_wdt would not be useful. I deleted these definitions and modified gpios property in watchdog-gpio node as follows:
watchdog-gpio {
compatible = "linux,wdt-gpio";
gpios = <0x0a 0 19 1>; /* PA19 should be toggled */
hw_algo = "toggle";
hw_margin_ms = <200>;
always-running;
phandle = <0x75>;
};
where: 0x0a is phandle of pinctrl#1c20800 node, 0 corresponds to PortA (for PortC insert 2, for PortD insert 3 and so on), 19 is pin number and 1 corresponds to GPIO flag GPIO_ACTIVE_LOW (flags, that determine active high or active low, pull-up/pull-down resistor connection and so on, are described here).
The relevant device tree entry that I am using is:
memory {
device_type = "memory";
reg = <0x0 0x40000000>;
};
reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
ranges;
spw_dma#3E000000 {
reg = <0x3E000000 0x2000000>;
};
};
Can I check somewhere in the /sys/class interface to verify that the memory has actually been reserved? Since I am accessing the memory via the /dev/mem interface, I effectively bypass all security measures, and therefore, it would be useful to, at least be able to verify, that no one else will write to that memory region.
Note: I am aware that The Right Way™ would be to write a kernel driver or use a dynamic memory UIO driver
I'm new to the concepts of kernel and device trees. I have a samsung artik module that runs fedora 24. I need to test one of it's I2S peripherals (it has 3 I2S peripherals). The default I2S is driving the main audio jack and is working fine. I have to test the secondary I2S that is available on a set of gpio pins and we have managed to connect it to an AMP board (TAS5731 EVM of texas instruments) via wires. Now the problem is that the amp board is not detected as an audio device. On further investigation I found out that the I2S peripheral is 'disabled' by default in the device tree. Here is the relevant portions of the device tree:
i2s#c0056000 {
reg = <0xc0056000 0x1000>;
frame-bit = <0x20>;
dmas = <0x3b 0xe 0x3b 0xf>;
pinctrl-0 = <0x3f>;
compatible = "nexell,nexell-i2s";
clock-names = "i2s1";
reset-names = "i2s-reset";
mclk-in = <0x0>;
master-mode = <0x1>;
clocks = <0x3e>;
pre-supply-mclk = <0x1>;
resets = <0x10 0x18>;
sample-rate = <0xbb80>;
status = "**disabled**";
dma-names = "tx", "rx";
pinctrl-names = "default";
trans-mode = <0x0>;
};
.
.
.
i2s1 {
nexell,pin-function = <0x3>;
phandle = <0x3f>;
nexell,pin-pull = <0x0>;
nexell,pins = "gpioa-28", "gpioa-30", "gpiob-0", "gpiob-6", "gpiob-9";
nexell,pin-strength = <0x0>;
linux,phandle = <0x3f>;
};
My question is, can I enable the peripheral without having to compile the kernel again, that is, from within the running kernel? If not, what are the alternate ways to get it running? Thanks a lot.
I am writing a linux device driver and need to define the following clock-tree in a device tree file:
Note: Selecting an oscillator in the multiplexer is done by pulling an gpio output high or low. The clock generator is programmed via I2C.
Here is an example of what I have so far:
clocks {
/* fixed clock oscillators */
osc22: oscillator22 {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <22579200>;
};
osc24: oscillator24 {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <24576000>;
};
/* clock multiplexer
* I'm afraid the following is not going to work :( ?
*/
mux: multiplexer {
compatible = "mux-clock"; /* <-------- ??? */
clocks = <&osc22>, <&osc24>; /* parent clocks */
};
};
i2c1 {
/* clock generator */
si5351: si5351c#60 {
#address-cells = <1>;
#size-cells = <0>;
#clock-cells = <1>;
compatible = "silabs,si5351c";
reg = <0x60>;
clocks = <0>, <&mux>;
clock-names = "xtal", "clkin";
status = "okay";
clkout0 {
reg = <0>;
silabs,disable-state = <2>;
silabs,clock-source = <3>;
};
};
};
References:
Clock Bindings
Binding for simple fixed-rate clock sources
Binding for Silicon Labs Si5351a/b/c programmable i2c clock generator
How do I define a simple gpio-controlled clock multiplexer in a device tree?
As correctly pointed out by #h3n, at the time of asking this question, the kernel did not provide support for gpio-controlled clock multiplexers.
So, I had to add a common clock driver for such devices.
This driver (drivers/clk/clk-gpio.c) is in the mainline since 4.3-rc1.
A device tree binding for the above mentioned use-case could look like this:
clocks {
/* fixed clock oscillators */
osc22: oscillator22 {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <22579200>;
};
osc24: oscillator24 {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <24576000>;
};
/* gpio-controlled clock multiplexer */
mux: multiplexer {
compatible = "gpio-mux-clock";
clocks = <&osc22>, <&osc24>; /* parent clocks */
#clock-cells = <0>;
select-gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
};
};
The current kernel does not support that. You have to write your own kernel module.
The simple answer you don't need to have a device tree support for the clock muxing. The idea as far as I can see is to provide the API that your clock driver may use to choose the parent clock.
If you can see to the code of the Silicon Labs si5351c driver (drivers/clk/clk-si5351.c) it has a device tree support. Documentation/devicetree/bindings/clock/silabs,si5351.txt has detailed description of the allowed fields. I guess you have to define as many clkin as you need.
The mux can be used to select one of the parent clocks: osc22 or osc24.
BUT you need to write your own binding for property "mux-clock" in your driver.
I don't know if the below link can help you directly but take a look at it:
https://www.kernel.org/doc/Documentation/devicetree/bindings/clock/ti/mux.txt
Above link defines the mux binding to be used in DT
Here the mux binding "ti,mux-clock" is defined in the driver as per common clk framework:
http://lxr.free-electrons.com/source/drivers/clk/ti/mux.c
May be you can derive some idea how to implement your binding.