i have connected a hardware to an embedded linux board on i2c lines. I can see the device at /dev/i2c-1
filename = "/dev/i2c-1"
filehandle = open(filename,O_RDWR);
write(filehandle, <buffer to be written>, <number of Bytes>)
(similiarly for read = read(filehandle, <buffer to be read in an array>, <number of Bytes>)
Now my question here is am I using the Linux's i2c-drivers ( read/write) when I am invoking write system calls (and read like above using filehandle).
Also is this implementation independent of i2c module?I verified only after I do modprobe i2c_dev I can see my code running. Is modprobe i2c_dev loading the i2c module and forming the /dev/i2c-1 in the /dev directory since I have connected the i2c device to it.
User-space interface to I2C subsystem is provided via /dev/i2c-*
files and documented at Documentation/i2c/dev-interface. There are two ways to send I2C message:
write()
; you need to include linux/i2c-dev.h for thisi2c_msg
structure via ioctl()
with I2C_RDWR
request; you need to include linux/i2c.h for thisSee this question for examples.
/dev/i2c-1
file is just an interface to I2C subsystem. You can send I2C message, receive I2C message and configure I2C using correspondingly write()
, read()
and ioctl()
syscalls. Once you perform one of these operations over /dev/i2c-1
file, it's being passed through Virtual file system to I2C layer, where those operations are implemented. Actual callbacks for those operations are implemented in drivers/i2c/i2c-dev.c file, more specifically -- in i2cdev_fops structure.
For example, when you perform open()
syscall on /dev/i2c-1
file, the i2cdev_open() function is called in kernel, which creates i2c_client
structure for further send/receive operations, and that structure is being assigned to file's private data field:
/* This creates an anonymous i2c_client, which may later be
* pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE.
*
* This client is ** NEVER REGISTERED ** with the driver model
* or I2C core code!! It just holds private copies of addressing
* information and maybe a PEC flag.
*/
client = kzalloc(sizeof(*client), GFP_KERNEL);
...
file->private_data = client;
When you perform some operations on that /dev/i2c-1
file next, i2c_client
structure will be extracted from file->private_data
field, and corresponding function will be called for that structure.
For write()
syscall the i2cdev_write() function will be called, which leads to i2c_master_send()
function call:
struct i2c_client *client = file->private_data;
...
ret = i2c_master_send(client, tmp, count);
The same way read()
leads to i2cdev_read()
, which leads to i2c_master_recv()
. And ioctl()
leads to i2cdev_ioctl()
, which just assigns corresponding flags to i2c_client
structure.
Operations performed on /dev/i2c-*
file lead eventually to execution of I2C hardware driver functions. Let's see one example of it. When we are doing write()
syscall, the whole chain will be:
write()
-> i2cdev_write()
-> i2c_master_send()
-> i2c_transfer()
-> __i2c_transfer()
-> adap->algo->master_xfer()
, where adap
is i2c_adapter
structure, which stores hardware specific data about I2C controller, such as callbacks of I2C hardware driver. That .master_xfer
callback is implemented in I2C hardware driver. For example, for OMAP platforms it's implemented in drivers/i2c/busses/i2c-omap.c file, see omap_i2c_xfer() function.