Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linux Device Tree (DTS): i2c device on USB-I2C bridge

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.

like image 486
CliffordVienna Avatar asked May 27 '15 12:05

CliffordVienna


People also ask

How do I add I2C device to device tree?

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>; }; };

What is DTS Linux?

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.

How to instantiate I2C device?

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

Why I2C driver is used?

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 .


2 Answers

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>;
            };
    };
like image 159
CliffordVienna Avatar answered Oct 29 '22 15:10

CliffordVienna


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.

like image 24
RDW Avatar answered Oct 29 '22 17:10

RDW