ACPI: Linux I2C Driver not binding with the device - linux-kernel

I'm trying to modify an hwmon driver from being Device Tree specific to use the generic property APIs (for compatibility with ACPI). For the purposes of testing I'm trying to bind with the device through _HID instead of PRP0001 at the moment.
I'm running into an issue where the device is never bound to the driver though.
Through some profiling I've found that setup fails at the __acpi_match_device() function call; the !device check fails every time.
I've modified the DSDT as follows, and verified that an entry for this device is present in sysfs (/sys/devices/LNXSYSTM:00/LNXSYBUS:00/).
Device (I2C1) {
...
Device (DEVC) {
Name (_HID, "DEVC1111")
Name (_CRS, ResourceTemplate () {
I2cSerialBusV2 (0x45,ControllerInitiated,
100000,AddressingMode7Bit,
"\\_SB.I2C1",0,ResourceConsumer)
})
Name (_DSD, Package () {
ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () {"reg", 45},
Package () {"ch0-reg", 0},
Package () {"ch1-reg", 1},
Package () {"ch2-reg", 2},
}
})
}
}
Adding some prints to i2c_acpi_get_i2c_resource() shows that the properties in the I2cSerialBusV2() are being read by the kernel as expected at some point.
I've added the relevant ACPI HID entry to the driver as follows (modified driver excerpt):
static const struct acpi_device_id device_acpi_match_table[] = {
{ "DEVC1111" },
{ }
};
MODULE_DEVICE_TABLE(acpi, device_acpi_match_table);
static struct i2c_driver device_i2c_driver = {
.probe_new = device_probe,
.remove = device_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = device_of_match_table,
.acpi_match_table = ACPI_PTR(device_acpi_match_table),
.pm = &device_pm,
},
.id_table = device_ids,
};
module_i2c_driver(device_i2c_driver);
The device is visible on the relevant I2C bus: i2cdetect -r -y 1 shows the address (45) of the device as expected.
echo my_device 0x45 > /sys/bus/i2c/devices/i2c-1/new_device
also probes the driver, but does not recognize the device as an ACPI device: ACPI_HANDLE(&i2c_client->dev) returns false.
I noticed that this devices directory in /sys/devices/LNXSYSTM:00/LNXSYBUS:00/ is the only entry that does not have a physical_node entry. I assume that this may be related to the issue but I am not sure how to fix it; I am quite new to most of this; ACPI and i2c device drivers.
Other ACPI devices in the system bind to their drivers just fine, but none of them are on an I2C bus, so it seems to be possibly an issue with my I2C/ACPI setup.
I am not sure where to go from here; how can I go about root causing this?

Related

kernel module not getting registered with kernel when built as module, though if built-in it works

This is my first time working with kernel modules at core. I am trying to run a sensor BMC150 for which the kernel already has an IIO-framework driver :
https://elixir.bootlin.com/linux/latest/source/drivers/iio/magnetometer
I can see this :
static const struct of_device_id bmc150_magn_of_match[] = {
{ .compatible = "bosch,bmc150_magn" },
{ .compatible = "bosch,bmc156_magn" },
{ .compatible = "bosch,bmm150_magn" },
{ }
};
So I created my device tree node like this :
magn#13 {
compatible = "bosch,bmc150_magn";
reg = <0x13>;
status = "ok";
};
Now if I have built the module as built-in, I can see the driver under /sys/bus/i2c/drivers and the probe happens and I can see the device under /sys/bus/iio/devices and everything works fine and I am able to get the readings from the sensor.
However, if I would have build the module as 'M' (not built-in), I do not see the module under /sys/bus/i2c/drivers and also no IIO devices get generated. Seems like the kernel does not know about the driver.
What is the problem here ? (I am using busybox rootfs and I used make modules_install to install the modules to the rootfs. If I do "modprobe the driver loads and everything works fine)
i read in this SO post that if a module has other modules yet-to-be loaded as dependencies then these problems may happen. Is this the issue, am not sure. Please guide.

Kernel module probe function is never called

I try to load a sample device tree driver, but the probe function is never called.
The entry in dts file looks like this
dummy1 {
compatible = "ti,dummy";
reg = <0x9f200000 0x1000>,
<0x9f201000 0x8>;
};
And the relevant driver code is:
#define DRV_NAME "dummy"
static const struct of_device_id dummy_of_match[] = {
{
.compatible = "ti,dummy",
}, {
},
};
static struct platform_driver dummy_driver = {
.driver = {
.name = DRV_NAME,
.of_match_table = dummy_of_match,
},
.probe = dummy_probe,
.remove = dummy_remove,
};
MODULE_DEVICE_TABLE(of, dummy_of_match);
module_platform_driver(dummy_driver);
I have recompiled the dtb file (dtdiff shows it contains my device) and have copied it to target, but nothing happens when I insmod the driver.
I also can't find it in /sys/firmware/devicetree/
Trying to solve the issue, I even removed the dtb file...and magically the kernel continued to boot as if nothing happened. I thought dtb could be baked into zImage which is possible with some additional tweaking, but that wasn't the case.
Solution:
Finally, I found out that the uboot was also checking the ./boot directory on the emmc card first! Removing the dtb from there immediately made the file on the NFS 'visible'.
P.S.: If you run into similar issues try to read the outputs carefully. I began to to understand the issue when I saw the .dtb load error when I removed it on NFS, but after that a message appeared that it was successfully loaded to the memory.

Platform device driver autoloading mechanism

As I understand, platform device drivers could be autoloaded when "compatible" field in the device tree matches with "compatible" field in the kernel module. Here is pwm-overlay.dts file from Raspberry Pi distro:
/ {
fragment#0 {
target = <&gpio>;
__overlay__ {
pwm_pins: pwm_pins {
brcm,pins = <18>;
brcm,function = <2>; /* Alt5 */
};
};
};
fragment#1 {
target = <&pwm>;
__overlay__ {
pinctrl-names = "default";
pinctrl-0 = <&pwm_pins>;
status = "okay";
};
};
fragment#2 {
target = <&clk_pwm>;
frag2: __overlay__ {
clock-frequency = <100000000>;
};
};
__overrides__ {
pin = <&pwm_pins>,"brcm,pins:0";
func = <&pwm_pins>,"brcm,function:0";
clock = <&frag2>,"clock-frequency:0";
};
};
First of all, I do not see any "compatible" field, but in pwm-bcm2835.c file there are such strings:
static const struct of_device_id bcm2835_pwm_of_match[] = {
{ .compatible = "brcm,bcm2835-pwm", },
{ /* sentinel */ }
};
Also, when I load overlay, driver successfully autoloaded too. How it works? How it knows what driver to load?
You're right about how "compatible" fields are matched to bind a driver to a device, you're just not looking the right place for it.
The file you are looking at is a device tree overlay. It's added to an existing device tree, adding, removing, or changing some of the nodes and properties. The final device tree is the result of combing the original with some number of overlays. A given property might be (re-)defined in any of the original's and/or overlays' source files. It's an arbitrary decision of the designer how to structure the device tree source code.
But think a bit about why overlays exist. This overlay is for configuring the PWM, as the configuration of the PWM is not identical for every board (you might not use it at all). Using overlays for something that can change lets us make that change without building and booting from a new device tree. The existence of the PWM hardware in the SoC is constant. Even if not used, it's never not there. Certain things about it, like the base address of the device registers, also do not change. So there is no point in putting this in an overlay, as it doesn't change, and it would likely be in the base device tree source.
In the overlay, fragment#1 is modifying an existing target node labeled "pwm". If we look for this node, we find it in bcm283x.dtsi:
pwm: pwm#7e20c000 {
compatible = "brcm,bcm2835-pwm";
reg = <0x7e20c000 0x28>;
clocks = <&clocks BCM2835_CLOCK_PWM>;
assigned-clocks = <&clocks BCM2835_CLOCK_PWM>;
assigned-clock-rates = <10000000>;
#pwm-cells = <2>;
status = "disabled";
};
And there you have the compatible property with value "brcm,bcm2835-pwm". Since it would not need to be changed, it is in the source of the base device tree like we would expect.

Hello Word Device Tree Based device driver

I have read and almost gone through all the linux kernel documentation on the device tree and device tree overlays.I am not able to understand if we have to create a new entree in the device tree of the platform or to create a new overlay for the device for a new driver based on device tree.
I am looking for a simple led glowing driver example where led is connected to GPIO pin and its configuration is mentioned in the device tree overlay or device tree fragment on the board's platform.How can it be build/pushed and tested using the user space application.
I created a custom device in my device tree:
my_device#ffdf0000 {
compatible = "my_driver";
reg = <0xffdf0000 0x1000>
/*
* reg = address of device and size
* (Minimum is System's Pagesize = 0x1000 Byte in my case
*/
}
I wrote a Kernel stub for this Device:
(Here I took kernel_src/drivers/uio/uio_pdrv_genirq.c and Hans J. Koch: Userspace I/O drivers in a realtime context (device driver tutorial) as basis.)
This stub has following two structs:
The of_device_id struct:
static struct of_device_id my_match_table[] = {
{
.compatible = "my_driver",
},
{0}
};
MODULE_DEVICE_TABLE(of, my_match_table);
and the driver struct itself:
static struct platform_driver my_platform_driver = {
.probe = my_probe,
.remove = my_remove,
.driver = {
.name = "my_driver",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(my_match_table),
},
};
Now I have access to the properties of the device tree in my probe function:
static int my_probe(struct platform_device *dev)
{
struct uio_info *uioinfo;
struct resource *r = &dev->resource[0];
[...]
uioinfo->name = dev->dev.of_node->name /* name from device tree: "my_device" */
uioinfo->mem[0].addr = r->start; /* device address from device tree */
uioinfo->mem[0].size = resource_size(r); /* size from device tree */
[...]
}
When there is a match in compatible with both the kernel stub's entry and the device tree, the probe function is called.
Use QEMU with a minimal custom hardware device
I recommend you code up your own minimal platform device, to also control the hardware and have a full understanding.
I have provided a full runnable Buildroot QEMU example with source code on GitHub as detailed on this answer: How to program Linux .dts device tree files?
The example is also documented on the GitHub repository.

BBB DT based approach

I have successfully implemented a GPIO based driver for my custom protocol using platform device model.
I want to upgrade it using device tree approach. So for starters I have a beaglebone black, and I have cross compiled the kernel using the device tree config enabled and verified during uboot console messages showing
Verifying Checksum ... OK
Flattened Device Tree blob at 80f80000
Booting using the fdt blob at 0x80f80000
XIP Kernel Image ... OK
OK
Using Device Tree in place at 80f80000, end 80f899de
I added my entry into the board common file node name my_gpio {compatible = "my_gpio" }
Then I build the usual process make uImages dtbs LOADADDR....
Finally i get my uImage with dtb.
In my driver i have used the same string "my_gpio" as .name property.
but my probe method is not getting called, which AFAIK is because it is not finding any compatible devices.
Any help suggestions would be great.
In my driver:
static struct platform_driver d_driver = {
.driver = {
.name = "d_gpio",
.of_match_table = d_of_match,
},
.probe = D_probe,
.remove = D_remove
};
Thanks
You need to prepare a structure of type struct of_device_id and use the compatible property on that.
Try in the following manner :
static struct of_device_id my_devs[] = {
{ .compatible = "my_gpio" }, /* This should be the name given in the device tree */
{ }
};
MODULE_DEVICE_TABLE(of, my_devs);
Now build the platform_driver structure, and pass the above table into it :
static struct platform_driver my_plat_driver = {
.probe = my_probe,
.remove = my_remove,
.driver = {
.name = "my_gpio_driver", /* This name is for sysfs, not for matching */
.of_match_table = my_devs /* This turns out as the matching logic */
}
};
May be your board support doesn't understand this protocol, so a node is needed to put in a place where the platform code actually processes it. Please go through below discussion and add a "virtual-devices" node in dtb , hope it would help.
http://web.archiveorange.com/archive/v/9IQA2s6aeZUFXdm6P87Z

Resources