Reputation: 31
I have a requirement to create a Linux Kernel Driver to interface with a bunch of MCU's over I2C, through an Interface Board. Because they would be many in number, i.e around 1-18, we are utilising a NXP / TI I2C Multiplexer.
I have imported the NXP / TI I2C Multiplexer kernel driver and have incorporated the same in the DTS file. I have been successfully able to list all the I2C Multiplexers as different i2c-x nodes.
The MCU's all are using the same Address 0x08. And I create a kernel driver which creates a hwmon
+ sysfs
interface for it.
However, the driver upon insmod
only triggers __init
function. And does not bother with probe()
.
Upon referring to many documentations I was able to trigger probe function only when am inserting
static struct i2c_board_info xxxx_i2c_devices[] = {
{
I2C_BOARD_INFO("xxxx", 0x08),
},
};
And its corresponding
i2c_register_board_info(0, xxxx_i2c_devices, ARRAY_SIZE(xxxx_i2c_devices));
However, this creates only one instance in HWMON
and not several as I imagined it to be. I have referred https://www.kernel.org/doc/Documentation/i2c/instantiating-devices
Without the changes in board init
, I tried to utilize the Method 3, however kernel doesn't even call the probe()
and detect function()
, only the __init
function of the driver.
Am following the driver - https://github.com/1119553797/sprd-kernel-common/blob/sprdb2g_gonk4.0/drivers/hwmon/w83l785ts.c
Would post the entire kernel driver if needed, for reference am using the Kernel 3.0.8, a custom board using board level changes to the same mentioned kernel.
Upvotes: 1
Views: 946
Reputation: 31
Ok, after extensive googling and patching different methods heres a workaround.
First and foremost in the DTS, we can assign the I2C address in the Mux addressing directly. For .e.g.
i2c@0 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
adc0: nau7802@2a {
compatible = "nuvoton,nau7802";
reg = <0x2a>;
nuvoton,vldo = <3000>;
};
};
i2c@1 {
#address-cells = <1>;
#size-cells = <0>;
reg = <1>;
adc1: nau7802@2a {
compatible = "nuvoton,nau7802";
reg = <0x2a>;
nuvoton,vldo = <3000>;
};
};
i2c@2 {
#address-cells = <1>;
#size-cells = <0>;
reg = <2>;
adc2: nau7802@2a {
compatible = "nuvoton,nau7802";
reg = <0x2a>;
nuvoton,vldo = <3000>;
};
};
Then in the driver, in order to identify with the VendorID,ProductID structure as in the above example "nuvoton,nau7802", we have to make the following changes :-
static const struct i2c_device_id nau7802_i2c_id[] = {
{ "nau7802", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, nau7802_i2c_id);
static const struct of_device_id nau7802_dt_ids[] = {
{ .compatible = "nuvoton,nau7802" },
{},
};
MODULE_DEVICE_TABLE(of, nau7802_dt_ids);
static struct i2c_driver nau7802_driver = {
.probe = nau7802_probe,
.remove = nau7802_remove,
.id_table = nau7802_i2c_id,
.driver = {
.name = "nau7802",
.of_match_table = nau7802_dt_ids,
},
};
The part "adc1" etc can be simply skipped. "MODULE_DEVICE_TABLE(of," is meant to be device_tree information, from what I could gather.
Please do let me know if you find a better method which does not require a DTS & board _init changes.
Upvotes: 2