I have an i2c device (touch controller). Usually I would add it to the .dts file like this when it is connected to the SoC i2c master (a tegra chip in my case):
i2c@7000c000 {
st1332: touchscreen@55 {
compatible = "sitronix,st1232";
reg = <0x55>;
interrupt-parent = <&gpio>;
interrupts = <189 IRQ_TYPE_EDGE_FALLING>;
};
};
With the i2c controler i2c@7000c000
being defined in the SoC's .dtsi file:
i2c1: i2c@7000c000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "nvidia,tegra124-i2c";
reg = <0x0 0x7000c000 0x0 0x100>;
interrupts = <0 38 0x04>;
scl-gpio = <&gpio 20 0>; /* gpio PC4 */
sda-gpio = <&gpio 21 0>; /* gpio PC5 */
nvidia,memory-clients = <14>;
status = "okay";
clock-frequency = <400000>;
};
However, I don't want to connect the touch controller to one of the i2c masters from the SoC. Instead I have it connected to a cp2112 USB to i2c bridge.
The cp2112 driver works fine: I can use commands such as i2cget
to access it from the command line. But how do I add it to the .dts file so that the touch controller driver will talk to it?
Because USB devices are enumerated automatically, I don't have a node in my .dts file that I can use as parent for the touch controller node. I would assume that I need to create a placeholder node in the .dts file under the usb controller (xusb@70090000
in my case), that is then associated with the enumerated USB device by the kernel, and move the touch controller into this node, but I don't know how to do that. What would such a node for a USB device look like? Or is there a completely different solution to the problem?
I am running Linux 3.10.40 with a backported version of hid-cp2112 from Linux v4.1.0-rc5.
Declare the I2C devices via devicetree 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>; }; };
The device tree is a set of text files in the Linux kernel source tree that describe the hardware of a certain platform. They are located at arch/arm/boot/dts/ and can have two extensions: *. dtsi files are device tree source include files.
Device Creation If you know for a fact that an I2C device is connected to a given I2C bus, you can instantiate that device by simply filling an i2c_board_info structure with the device address and driver name, and calling i2c_new_client_device() .
An I2C “Adapter Driver” abstracts the controller hardware; it binds to a physical device (perhaps a PCI device or platform_device) and exposes a struct i2c_adapter representing each I2C bus segment it manages. On each I2C bus segment will be I2C devices represented by a struct i2c_client .
As the hid-cp2112 driver is probed by the USB device enumeration, it does not even try to find itself in the device tree. I have created the following patch to hid-cp2112.c
that links the found cp2112 device to a /i2c@cp2112
node in the devie tree. (This of course only works for situations where there is only one cp2112 chip on the USB.)
diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c
index 2bd7f97..fa88590 100644
--- a/drivers/hid/hid-cp2112.c
+++ b/drivers/hid/hid-cp2112.c
@@ -31,6 +31,8 @@
#include <linux/module.h>
#include <linux/nls.h>
#include <linux/usb/ch9.h>
+#include <linux/of.h>
+#include <linux/of_i2c.h>
#include "hid-ids.h"
enum {
@@ -1014,6 +1016,7 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
dev->adap.algo = &smbus_algorithm;
dev->adap.algo_data = dev;
dev->adap.dev.parent = &hdev->dev;
+ dev->adap.dev.of_node = of_find_node_by_path("/i2c@cp2112");
snprintf(dev->adap.name, sizeof(dev->adap.name),
"CP2112 SMBus Bridge on hiddev%d", hdev->minor);
init_waitqueue_head(&dev->wait);
@@ -1029,6 +1032,8 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
hid_dbg(hdev, "adapter registered\n");
+ of_i2c_register_devices(&dev->adap);
+
dev->gc.label = "cp2112_gpio";
dev->gc.direction_input = cp2112_gpio_direction_input;
dev->gc.direction_output = cp2112_gpio_direction_output;
The entry in the .dts file for the touch controller looks like this:
i2c@cp2112 {
#address-cells = <1>;
#size-cells = <0>;
st1332: touchscreen@55 {
compatible = "sitronix,st1232";
reg = <0x55>;
interrupt-parent = <&gpio>;
interrupts = <189 IRQ_TYPE_EDGE_FALLING>;
};
};
As a reference for those who may encounter similar problems notice that Clifford
was backporting
the cp2112
driver from Linux 4+
back to v3.10.40
.
If you look at the kernel source for i2c busses it seems that they had to register themselves by using of_i2c_register_devices
, but this need was removed from kernel v3.12
onwards. This is why the cp2112
driver does not call of_i2c_register_devices
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With