I2C Gpio PCA9557
I2C client driver In my last post ,we talked about I2C bus driver implementation.Client driver is otherwise called a chip driver.This driver talks to I2C device attached to the bus. for more information about I2C,refer I2c Details. Initialization of the driver For registering a driver , we need to use i2c_add_driver() and the argument passed is a structure of type i2c_driver.So our structure is define like below.
static struct i2c_driver my_driver = { .probe = my_device_probe, .remove = __devexit_p(my_device_remove), .id_table = my_device_id, .driver = { .pm = &my_device_pm_ops, .owner = THIS_MODULE, .name = "my_device" }, };
We will go little detail about this structure. probe() will be called to make sure that the device exist and the functionality is fine.If device is not hot-pluggable,functionalities of probe() can be put inside init() method.This will reduce driver's run time memory footprint. If there is no support for hotplug,the device cannot be removed from a running system.For this , we use __devexit_p macro which indicates that this function will never be invoked by the PCI layer and will be initialized by NULL. id_table is the list of devices supported by this driver.It can be defined as below.
static const struct i2c_device_id my_device_id[] = { { "my_device", 0 }, { } };
my_device_pm_ops is of type structure dev_pm_ops.This is power management structure.There are many function pointers defined in this structure.In our case , we are using only 2 ie. suspend and resume.For more information about this structure, please refer kernel source.
static const struct dev_pm_ops my_device_pm_ops = { .suspend = my_device_suspend, .resume = my_device_resume };
Here my_device_suspend will be called by kernel in case if system is going to sleep mode and main memory will be preserved.If we need to do some thing for our device, we can implement in this function.For eg:, if you want to power off your device when system is in suspend state or if you want to stop a timer which is running etc. my_device_resume will be executed after system wakes up from a sleep state.Here we can turn on the device or turn on the timer or what ever needed. Now we can go into init function of the module.
static int __init my_init(void) { return i2c_add_driver(&my_driver); }
Here you are calling i2c_add_driver() to register i2c driver to the system. You may be wondering how your probe() is getting called.This will be called by the system when you register your driver Call stack for your probe() is as follows. i2c_add_driver > i2c_register_driver > driver_register > bus_add_driver > driver_attach > __driver_attach > driver_probe_device > really_probe > i2c_device_probe > my_device_probe Writing to I2C We can consider this case with implementation of powering on the device.
- define POWER_REG 0x10;
Here my_device power control register is defined. below function calls device_init() which actually does i2c write operation
static ssize_t my_device_power_on(struct device *dev,struct device_attribute *attr, char *buf) { struct my_device_data *data = dev_get_drvdata(dev); int err; err = device_init(data); if (err < 0) { pr_err("[My_device] %s: device_init() failed\n", __func__); return 0; } return sprintf(buf, "%d\n", (err < 0 ? 0 : 1)); }
Actual implementation of device_init() is as follows
static int device_init(struct my_device_data *data) { int err = 0; u8 buf[5]; buf[0] = 0x4A; buf[1] = 0x00; buf[2] = 0x00; buf[3] = 0x00; buf[4] = 0x00; err = i2c_smbus_write_i2c_block_data(data->client, POWER_REG | AC, sizeof(buf), buf); if (err < 0) pr_err("%s: POWER_REGs i2c writing failed\n", __func__); return err; }
Here i2c_smbus_write_i2c_block_data() is SMBus block write protocol.Here data->client is the handle to the slave device,POWER_REG is the byte interpreted by the slave device,next argument is the size of the data block ( maximum supported is 32 bytes ) and buf is byte array which will be written.
Similarly i2c_smbus_read_i2c_block_data() is used to read from the device.
Other API's for I2C transfer are.
i2c_smbus_write_word_data()
i2c_smbus_read_word_data()
i2c_smbus_write_byte_data()
i2c_smbus_read_byte_data()
Transfer in the bus is as follows.
for i2c_smbus_write_byte_data()
S 0x50 Wr [A] 0 [A] 0xAB [A] P S - start bit 0x50 - 7 bit slave address Wr - Write command ( 0b ) 0 - Address offset of the slave device where data has to be written. 0xAB - Data to be written. P - stop bit. [A] - Accept bit or acknowledgement. Data in square brackets([]) is send from slave to host wile rest is from host to slave. for i2c_smbus_read_byte_data()
S 0x50 Wr [A] 0 [A] S 0x50 Rd [A] [0xAB] NA P Rd-Read command (1b) 0xAB - Data received from slave. NA - Reverse accept bit. Every host adapter might not support all commands that i2c-core supports.A client driver has to check whether command is supported by adapter or not.
i2c_check_functionality() checks whether a particular function is supported. i2c_get_functionality() returns a mask containing all supported functions.