The smbus functions
The I/O functions are defined in terms of i2c_smbus_xfer():
- i2c_smbus_xfer(adapter, addr, flags, rw, cmd, size, data)
if the adapter's algorithm has smbus_xfer() method use it,
otherwise use the i2c_smbus_xfer_emulate() method;
- i2c_smbus_xfer_emulate(...) emulates the SMBus on the I2C bus.
It has an array of two messages (uses 2 for READ, 1 for WRITE).
If the size is I2C_SMBUS_QUICK is a zero-length message.
Otherwise sets up the message(s) data properly and calls
i2c_transfer(adapter, msg, num). In case of read, reads the response
back into the data.
- i2c_smbus_write_quick(client, value)
- i2c_smbus_read_byte(client)
- i2c_smbus_write_byte(client, value(;
- i2c_smbus_read_byte_data(client, cmd);
- i2c_smbus_write_byte_data(client, cmd, value);
- i2c_smbus_read_word_data(client, cmd);
- i2c_smbus_write_word_data(client, cmd, value);
- i2c_smbus_process_call(client, cmd, value);
- i2c_smbus_read_block_data(client, cmd, values);
- i2c_smbus_write_block_data(client, cmd, len, values);
- i2c_smbus_write_i2c_block_data(client, cmd, len, values);
The I2C device functions
The module i2c-dev.c provides a /dev interface of i2c adapters
to user applications. Each i2c adapter receives a number from the
I2C core. This number can be seen through the /proc/bus/i2c interface.
The I2C adapters are character devices with major 89 and minor that
number assigned by the I2C core.
The code i2c-dev.c defines a dummy i2c_driver (named i2cdev_driver)
with methods
i2cdev_attach_adapter, i2cdev_detach_client, and i2cdev_command,
and an i2c_client template (named i2cdev_client_template)
with the i2cdev_driver, no adapter, and no private data.
The I2C device operations are
(these oerations act on the client which is stored in the file'
private_data filed)
- i2cdev_lseek (from version 2.4.10 only): return -ESPIPE.
- i2cdev_read: an i2c_master_recv() on the client.
- i2cdev_write: an i2c_master_send() on the client.
- i2cdev_ioctl.
- i2cdev_open, creates a new client (after the i2cdev_client_template)
with adapter the i2cdev_adaps indexed by the inode minor.
Possibly calls the adapter' inc_use().
- i2cdev_release: free the file' private_data (the client) and possibly
calls the adapter' dec_use().
The ioctl commands are (arg is the ioctl argument)
- I2C_SLAVE or I2C_SLAVE_FORCE, set the client address to arg;
- I2C_TENBIT: set (arg != 0)
or clear the flag I2C_M_TEN (ten-bit addresses);
- I2C_FUNCS: get the functionality of the client' adapter;
- I2C_RDWR: arg should point to an i2c_rdwr_ioctl_data structure.
It copies the data from user space, calls i2c_transfer(), and eventually
copies the data back to user space.
- I2C_SMBUS: arg should point to an i2c_smbus_ioctl_data structure.
It calls i2c_smbus_xfer(). The i2c_smbus_ioctl_data struct contains
a rw flag, a command, the size of the data and the data pointer (of type
i2c_smbus_data).
The management functions are
- i2cdev_attach_adapter: inserts the adapter in the i2cdev_adaps[] list.
- i2cdev_detach_client: does nothing, returns 0.
- i2cdev_command: always returns -1.
- i2cdev_init: registers a char device ("i2c") with i2cdev_fops,
and adds to it the dummy driver i2cdev_driver.
- i2cdev_cleanup: (possibly) unregister the char dev.
The SMbus I/O functions are defined in terms of
i2c_smbus_access(file, rw, cmd, size, data), which fills an
i2c_smbus_ioctl_data with the arguments and calls ioctl(file, I2C_SMBUS, args)
which in turns calls i2c_smbus_xfer() to do the actual i/o.
The I2C proc functions
The I2C proc interface is defined in the header file include/linux/i2c-proc.h.
A general callback function type is declared as
i2c_real_callback( client, op, ctl_name, nrels_mag, results )
where "client" is a pointer to a client device we want to interact with,
"op" is an operation flag
that can be one of SENSORS_PROC_REAL_INFO/READ/WRITE.
Before using the callback function a ctl_table must be registered;
ctl_name -s the SYSCTL id of the file being accessed.
The function reads or writes real numbers; these are coded as an integer
("results") and a magnitude ("nrels_mag")
which is the power of 10 by which the integer must be divided
to get the real number (the magnitude can also be negative).
For READ/WRITE operations "nrels_mag" contains on return
the number of elements read or written.
The structure ctl_table (include/linux/sysctl.h) contains
- ctl_name: a binary id;
- procname: string;
- data: private data pointer, and its "maxlen";
- mode: protection rights;
- two callbacks, proc_handler(), for text formatting,
and ctl_handler(), for all i/o;
- a proc_dir_entry pointer;
- two extra generic (void *) pointers.
Four control tables are defined in drivers/linux/i2c-proc.c
(all terminated by a NULL entry),
- sysctl_table, with CTL_DEV, DEV_SENSORS entries, and a zero entry;
- i2c_proc_dev_sensors, with SENSORS_CHIPS entry (callbacks:
i2c_proc_chips, i2c_sysctl_chips);
- i2c_proc_dev, with DEV_SENSORS entry (callback: i2c_proc_dev_sensors);
- i2c_proc, with CTL_DEV entry (callback: i2c_proc_dev).
i2c_register_entry( client, prefix, ctl_table, module) and
i2c_deregister_entry( id ) are used to add and remove an entry in
the /proc/sys/dev/sensors/chips and a directory in /proc/sys/dev/sensors/.
"ctl_table" should be a template for the newly created directory.
A new ctl_table is allocated and filled.
The second extra field is pointed to "client".
The controlling "module" should usually be THIS_MODULE
The new table is registered with sysctl ( register_sysctl_table )
and the etries of the lists
i2c_entries[] (ctl_table_header), i2c_clients[], i2c_inodes[] are updated.
Deregistration is the reversed actions.
i2c_create_name() returns a nice name for a new proc directory.
i2c_fill_inode(inode, fill) increases/decreases the MOD_USE_COUNT,
depending on the "fill" parameter.
i2c_dir_fill_inode(inode, fill) finds the i2c_client with the given
inode number (inode->i_ino), and calls its driver's inc/dec_use().
i2c_proc_chips( ctl_table, rw, filp, buffer, len ) is the proc interface
to the chips names.
For each non-NULL entry in i2c_entries[] writes the
ctl_table->child->child name and procname to the user buffer.
i2c_sysctl_chips(ctl_table, name, len, oldval, oldlen, newval, newlen, context)
is the sysctl interface.
[TO DO]
i2c_sysctl_real( ctl_table, name, len, oldval, oldlen, newval, newlen, context)
and i2c_proc_real( ctl_table, rw, filp, buffer, len)
are the functions that perform the i/o.
i2c_proc_real() firts gets the magnitude, next does the i/o, which consists
of real-long conversion (i2c_parse_reals / i2c_write_reals) and
i/o on the client (using the function callback()).
i2c_sysctl_real() ... [TO DO].
i2c_parse_reals() and i2c_write_reals() are not discussed.
i2c_detect(adapter, addr_data, found_proc) is an inefficient ISA
detect function, similar to i2c_probe().
[TO DO].
The I2C protocol
The I2C bus consists of two active bidirectional wires, besides the ground
wire. One wire carries the data SDA (Serial Data), the other is for clock
SCL (Serial Click Line).
Every device on the bus has its own address, and can act as a receiver and
a transmitter (although some devices act only as one of the two).
The bus is multi-master: more than one IC capable of initiating a data
transfer can be connected to it. The IC that starts the transfer is the
bus master, the other become the bus slaves.
The master issues a START (pull SDA, then pull SCL) to signal the beginning
of a transfer. The end of the transfer will be signalled with a STOP
(release SCL, then release SDA ). Then the master sends one byte
containing the address of the
ather part and a read/write flag: bits are send MSB first, LSB last;
the seven most significant bits are the address, the LSB is the flag
(0 for WRITE). Bits are sent on the SDA line,
one bit for each clock pulse (SCL).
Some addresses are reserved:
0000-000(0) general call
0000-000(1) START byte
0000-001(x) C-bus (obsolete)
0000-010(x) a different bus
0000-011(x) future
0000-1xx(x) future
1111-1xx(x) future
1111-0xx(x) 10-bit slave addressing
EXtended address mode (10-bit addresses) has a two-byte address.
The first byte contains the two most significant bits of the address
and the r/w flag. The second byte contains the other eight bits.
Slaves respond to an address byte that matches and to a data byte
(it they are being addressed) with an ACK: pull SDA, and when the
master has issued the next SCL clock pulse, release SDA.
To receive a byte from the slave, the master must send eight clock pulses
(on SCL) while the slave writes the bits on the SDA (high for 1, low for 0).
Before all the master releases tha SDA and the slaves takes control of it.
Then the master pulses the SCL; when it is high it read the bit from SDA.
Example
References:
G. Kroah-Hartman, I2C drivers, part I, Linux Journal 115, Dec. 2003,
30-35
G. Kroah-Hartman, I2C drivers, part II, Linux Journal 116,
Jan. 2004, ...
Here are some instructions to write a sample adapter and driver
for the I2C layer.
Some of the theory behind I2C has been discussed in the introduction.
Now we come to a working example, ... something you can do even if you do
not have any special i2c device to play with. Of course the first thing to
do is to read the kernel code for the I2C core and supported devices.
To be independent from any hardware i decided to write an I2C
adapter for a virtual bus that exiest only in memory, and a driver for
virtual devices that sit on that bus. I use the I2C core
functionalities and structures to manage adapter and devices and the
data transfer. The figure below shows the main relations between the
I2C core and the driver/adapter callback functions (shown in red).
The i2c_adapter i2c_mem_adpt.c
The adapter i2c_mem_adapter does not have to do anything special;
the list of clients[] is already managed by the i2c_core,
it must specify that it is using the algorithm i2c_mem_algorithm
(about which i will say shortly), and declare an id that is not used
by other adapters (so check include/linux/i2c.h). All the other
functons may be NULL. Here i put some printk to see when they are
invoked.
The algorithm i2c_mem_algorithm implements two important functions.
First functionality() that returns a functionality flag that must be chosen so
that clients that are not "memory" virtual devices do not get
attached to the adapter. I chose a flag that is not already used by
the I2C core (again see include/linux/i2c.h).
Second master_xfer() must be implemented to code the actual data transfer.
If smbus_xfer() is NULL, the algorithm implements a pure "i2c protocol".
In the example i did not conecrn with protocol issues and did a simple
byte copy (after all everything is in memory, and i am more concerned with
the dynamics of the intercations among the I2C layer components).
The adapter i2c_mem_adapter and the algorithm i2c_mem_algorithm are
coded in the file
i2c_mem_adpt.c.
You need also the header file
i2c_mem.h.
Compile with the
Makefile and insert
the module with insmod.
You should see the kernel messages that tell that the adapter
has registerd with the I2C core:
i2c-core.o: i2c core module
i2c_mem version 0001
i2c-core.o: adapter mem adapter registered as adapter 0.
i2c_mem_adpt: initialized 1
Check the /proc/bus/i2c interface.
You should find
i2c-0 smbus/i2c mem adapter mem bus algorithm
where the fields are the device name (as assigned by the I2c core),
the bus, the adapter name, and its description.
/proc/bus/i2c-0 is still empty because there is no client
on the adapter.
The i2c_driver i2c_mem_drv.c
Once the memory virtual adapter is in place, you can go on to the
memory virtual clients and driver.
This driver should manage mamory-based virtual clients, that rely on the
adapter i2c_mem_adapter to transfer data.
The driver and the client are coded in the file
i2c_mem_drv.c.
Compile it with the same makefile, and install it.
After installing check /proc/bus/i2c-0 again and you should see
that the client is now there,
37 i2c_mem_client 0xp001 i2c mem driver
where the fields are the address, the client name, and its driver name.
Accessing the I2C memory client from user space
Our last effort consists in accessing the client from user space.
We need the i2c-dev.c module which provides the /dev interface to I2C
adapters.
After opening the device, the program should bound to the adapter
with an address (not already taken by any client).
This is done with the ioctl I2C_SLAVE, with argument the address.
Next it can transfer data with the ioctl I2C_RDWR;
the argument is a pointer to a i2c_rdwr_ioctl_data structure.
This structure contains
- msgs, a pointer to i2c_msg struct;
- nmsgs, the number of messagges.
Each i2c_msg struct has the following fields
- addr (unsigned short) address of the slave;
- flags (unsigned short), can have I2C_M_TEN, I2C_M_RD,
I2C_M_NOSTART, I2C_M_REV_DIR_ADDR;
- len (short) the message length;
- buf (char *) pointer to the message data.
i2c_test.c is a simple user application
that shows how to read/write to the memory virtual client, through
the i2c_mem_adapter.
Marco Corvi - 2003