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.
Related
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).
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?
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.
The issue that I am looking a solution for is that I have to upgrade the Ethernet controller on my motherboard because the component is going obsolete.
The board is running u-boot and kernel 2.6 with a device tree.
I have to mention that the new Ethernet chip is placed on the new motherboard on a different address location than previous:
phy-handle = <&PHY1>; -old address register,
phy-handle = <&PHY0>; -new address register:
dts file:
mdio#e00 {
compatible = "fsl,mpc885-fec-mdio", "fsl,pq1-fec-mdio";
reg = <0xe00 0x188>;
#address-cells = <1>;
#size-cells = <0>;
PHY0: ethernet-phy#0 {
reg = <0x0>;
device_type = "ethernet-phy";
};
PHY1: ethernet-phy#1 {
reg = <0x1>;
device_type = "ethernet-phy";
};
PHY2: ethernet-phy#2 {
reg = <0x2>;
device_type = "ethernet-phy";
};
...
EMAC0: ethernet#1e00 {
device_type = "network";
compatible = "fsl,mpc885-fec-enet",
"fsl,pq1-fec-enet";
reg = <0x1e00 0x188>;
mac-address = [ 00 00 00 00 00 00 ];
interrupts = <7 1>;
interrupt-parent = <&PIC>;
phy-handle = <&PHY0>;
linux,network-index = <0>;
};
The constrain is that I do not want have 2 separate builds for each board, but a smart piece of code that identifies which Ethernet controller is present on the motherboard.
Now my question is where this identification code should be added?, in u-boot?, in the device tree file?, or in the kernel Ethernet driver?
What I have noticed during the debugging process, is that compared to the kernel that ONLY loads the driver specified by the device tree, the u-boot is smart enough to scan the mii bus and identify the Ethernet controller.
thanks,
regards
This code snippet comes from the device tree for the RIoTBoard (/arch/arm/boot/dts/imx6dl-riotboard.dts)
&hdmi {
ddc-i2c-bus = <&i2c2>;
status = "okay";
};
I have gone through the device tree documentation both on devicetree.org and in the documentation/devicetree folder of the linux kernel, but I am not able to find any description of the meaning of a phandle when used as node name.
You can understand phandle as some kind of pointer for the node which points to the definition of that node which is either kept in the same file or the other file.
I can explain phandle concept taking example from the below link for AM33xx SoC
clocks file:
http://lxr.free-electrons.com/source/arch/arm/boot/dts/am33xx-clocks.dtsi
Below is the functional clock for watchdog:
wdt1_fck: wdt1_fck {
#clock-cells = <0>;
compatible = "ti,mux-clock";
clocks = <&clk_rc32k_ck>, <&clkdiv32k_ick>;
reg = <0x0538>;
};
Now wdt1_fck has two parent clocks sources: clk_rc32k_ck and clkdiv32k_ick
These are phandles or you can say pointers to their clock definitions:
clk_rc32k_ck: clk_rc32k_ck {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <32000>;
};
clkdiv32k_ick: clkdiv32k_ick {
#clock-cells = <0>;
compatible = "ti,gate-clock";
clocks = <&clkdiv32k_ck>;
ti,bit-shift = <1>;
reg = <0x014c>;
};
So basically phandle enables to use the definitions of nodes across the files.
I'll answer with a example:
label:node {
#address-cell = <1>;
#size-cells = <0>;
}
&label {
proporties = <2>;
};
Means:
label:node {
#address-cell = <1>;
#size-cells = <0>;
proporties = <2>;
}
I think the question is more about the &hdmi part of the example, using an & reference for a node name in particular. The & in device tree files has two meanings: one for items in an array, and another for items outside an array.
In an array, the & reference will expand to a phandle.
Outside an arry, the & reference will expand to the path of the node you're referring to.
More information is available here:
https://elinux.org/Device_Tree_Mysteries#Labels
https://elinux.org/Device_Tree_Mysteries#Label_as_a_phandle_vs_Label_as_a_path