📄 i2c-old-porting
字号:
I2C Conversion Guide for I2C-old to the current I2C APIJuly 2002For Linux Kernel v2.5.xFrank Davis <fdavis@si.rr.com>-------------------------------------------------------There exists several kernel drivers that are using an old version of the I2CAPI. These drivers need to be converted to the current (kernel 2.5.x) version.The following document provides a guideline to make the appropriate changes tothe affected drivers. There maybe slight modifications to this guide that are specific to the driver you are working on. If you see {driver_name}, replace that with the respective name of the driver, such as saa7110.c , {driver_name} = saa7110.-------------------------------------------------------Step 1: Include the right header file Perform the following change within the driver #include <linux/i2c-old.h> --> #include <linux/i2c.h>Step 2: Add and set the i2c modesAdd the following code near the top of the driverstatic unsigned short normal_i2c[] = {34>>1, I2C_CLIENT_END };static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };static unsigned short probe[2] = { I2C_CLIENT_END , I2C_CLIENT_END };static unsigned short probe_range[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; static unsigned short ignore[2] = { I2C_CLIENT_END , I2C_CLIENT_END };static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };static struct i2c_client_address_data addr_data = { normal_i2c , normal_i2c_range, probe , probe_range, ignore , ignore_range, force};static struct i2c_client client_template;Step 3: Modify the driver info structWithin the struct for the driver , such as struct {driver_name} , make the following change ,struct i2c_bus *bus --> struct i2c_client *clientMake changes where this change affects references within the file.Add a semaphore to the driver struct (as above)struct semaphore lock Step 5: Remove specific read and write functionsRemove the driver specific write and read functions, usually in the form:{driver_name}_write , {driver_name}_read , {driver_name}_write_block , etc.Step 6: Update the write and read functions for the current I2C APIReplace all references of {driver_name}_write with i2c_smbus_write_byte_dataReplace all references of {driver_name}_read with i2c_smbus_read_byte_data ori2c_smbus_read_byte , depending on args passed in.** Ensure that these functions pass in the i2c_client *client , NOT thedecoder/encoder that was passed in the driver specific write and readfunctions. Step 7: Modify the driver's attach functionChange the driver attach function prototype :{driver_name}_attach(struct i2c_device *device) --> {driver_name}_attach(struct i2c_adapter *adap, int addr , unsigned short flags, int kind)Create a i2c_client client...Add the following (where "decoder" is a reference to a struct for the driverinfo:struct i2c_client *client;client = kmalloc(sizeof(*client), GFP_KERNEL);if(client == NULL) return -ENOMEM;client_template.adapter = adap;client_template.addr = addr;memcpy(client, &client_template, sizeof(*client));strcpy(client->name , "{driver_name}");decoder->client = client;client->data = decoder;decoder->addr = addr;Towards the end of the function, add:init_MUTEX(&decoder->lock);i2c_attach_client(client);Step 8: Modify the driver's detach functionChange the driver detach function prototype :{driver_name}_detach(struct i2c_device *device) --> {driver_name}_detach(struct i2c_client *client)In the beginning of the detach function, add:i2c_detach_client(client);Towards the end of the detach function, add:kfree(client->data);kfree(client);Step 9: Modify the driver's command functionChange the driver command function prototype :Step 10: Add the probe function after the driver's attach function.Add the following code:static int {driver_name}_probe(struct i2c_adapter *adap){ return i2c_probe(adap, &addr_data, {driver_name}_attach);}Step 11: Modify the driver's i2c_driverFind the i2c_driver , such asstatic struct i2c_driver i2c_driver_saa7110It is usually located towards the end of the driver Replace the values from I2C_DRIVERID_{something} to {driver_name}_attach, and add the followingI2C_DRIVERID_{driver_name} , // verify by looking in include/linux/i2c-id.h I2C_DF_NOTIFY,{driver_name}_probe, ....Step 12: Adding the i2c_client Add the i2c_client to the driver. Add the following code:static struct i2c_client client_template = { "{driver_name}_client", -1, 0, 0, NULL, {i2c_driver reference}};Step 13: Registering and UnregisteringReplace i2c_register_driver with i2c_add_driverReplace i2c_unregister_driver with i2c_del_driver-------------------------------------------------------Example:The following patch provides the i2c coversion patch for the saa7110 driverbased on the above guide (for clarity).--- drivers/media/video/saa7110.c.old Fri Jun 28 10:22:52 2002+++ drivers/media/video/saa7110.c Thu Jul 4 16:51:08 2002@@ -26,7 +26,7 @@ #include <asm/io.h> #include <asm/uaccess.h> -#include <linux/i2c-old.h>+#include <linux/i2c.h> #include <linux/videodev.h> #include "linux/video_decoder.h" @@ -37,13 +37,31 @@ #define I2C_SAA7110 0x9C /* or 0x9E */ +#define IF_NAME "saa7110" #define I2C_DELAY 10 /* 10 us or 100khz */ +static unsigned short normal_i2c[] = {34>>1, I2C_CLIENT_END };+static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };+static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };+static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };+static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };+static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };+static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END };++static struct i2c_client_address_data addr_data = {+ normal_i2c, normal_i2c_range,+ probe, probe_range,+ ignore, ignore_range,+ force+};++static struct i2c_client client_template;+ struct saa7110 {- struct i2c_bus *bus;+ struct i2c_client *client; int addr; unsigned char reg[36];-+ struct semaphore lock; int norm; int input; int enable;@@ -54,67 +72,10 @@ }; /* ----------------------------------------------------------------------- */-/* I2C support functions */-/* ----------------------------------------------------------------------- */-static-int saa7110_write(struct saa7110 *decoder, unsigned char subaddr, unsigned char data)-{- int ack;-- LOCK_I2C_BUS(decoder->bus);- i2c_start(decoder->bus);- i2c_sendbyte(decoder->bus, decoder->addr, I2C_DELAY);- i2c_sendbyte(decoder->bus, subaddr, I2C_DELAY);- ack = i2c_sendbyte(decoder->bus, data, I2C_DELAY);- i2c_stop(decoder->bus);- decoder->reg[subaddr] = data;- UNLOCK_I2C_BUS(decoder->bus);- return ack;-}--static-int saa7110_write_block(struct saa7110* decoder, unsigned const char *data, unsigned int len)-{- unsigned subaddr = *data;-- LOCK_I2C_BUS(decoder->bus);- i2c_start(decoder->bus);- i2c_sendbyte(decoder->bus,decoder->addr,I2C_DELAY);- while (len-- > 0) {- if (i2c_sendbyte(decoder->bus,*data,0)) {- i2c_stop(decoder->bus);- UNLOCK_I2C_BUS(decoder->bus);- return -EAGAIN;- }- decoder->reg[subaddr++] = *data++;- }- i2c_stop(decoder->bus);- UNLOCK_I2C_BUS(decoder->bus);-- return 0;-}--static-int saa7110_read(struct saa7110* decoder)-{- int data;-- LOCK_I2C_BUS(decoder->bus);- i2c_start(decoder->bus);- i2c_sendbyte(decoder->bus, decoder->addr, I2C_DELAY);- i2c_start(decoder->bus);- i2c_sendbyte(decoder->bus, decoder->addr | 1, I2C_DELAY);- data = i2c_readbyte(decoder->bus, 1);- i2c_stop(decoder->bus);- UNLOCK_I2C_BUS(decoder->bus);- return data;-}--/* ----------------------------------------------------------------------- */ /* SAA7110 functions */ /* ----------------------------------------------------------------------- */ static-int saa7110_selmux(struct i2c_device *device, int chan)+int saa7110_selmux(struct i2c_client *client, int chan) { static const unsigned char modes[9][8] = { /* mode 0 */ { 0x00, 0xD9, 0x17, 0x40, 0x03, 0x44, 0x75, 0x16 },@@ -126,61 +87,59 @@ /* mode 6 */ { 0x80, 0x59, 0x17, 0x42, 0xA3, 0x44, 0x75, 0x12 }, /* mode 7 */ { 0x80, 0x9A, 0x17, 0xB1, 0x13, 0x60, 0xB5, 0x14 }, /* mode 8 */ { 0x80, 0x3C, 0x27, 0xC1, 0x23, 0x44, 0x75, 0x21 } };- struct saa7110* decoder = device->data; const unsigned char* ptr = modes[chan]; - saa7110_write(decoder,0x06,ptr[0]); /* Luminance control */- saa7110_write(decoder,0x20,ptr[1]); /* Analog Control #1 */- saa7110_write(decoder,0x21,ptr[2]); /* Analog Control #2 */- saa7110_write(decoder,0x22,ptr[3]); /* Mixer Control #1 */- saa7110_write(decoder,0x2C,ptr[4]); /* Mixer Control #2 */- saa7110_write(decoder,0x30,ptr[5]); /* ADCs gain control */- saa7110_write(decoder,0x31,ptr[6]); /* Mixer Control #3 */- saa7110_write(decoder,0x21,ptr[7]); /* Analog Control #2 */+ i2c_smbus_write_byte_data(client,0x06,ptr[0]); /* Luminance control */+ i2c_smbus_write_byte_data(client,0x20,ptr[1]); /* Analog Control #1 */+ i2c_smbus_write_byte_data(client,0x21,ptr[2]); /* Analog Control #2 */+ i2c_smbus_write_byte_data(client,0x22,ptr[3]); /* Mixer Control #1 */+ i2c_smbus_write_byte_data(client,0x2C,ptr[4]); /* Mixer Control #2 */+ i2c_smbus_write_byte_data(client,0x30,ptr[5]); /* ADCs gain control */+ i2c_smbus_write_byte_data(client,0x31,ptr[6]); /* Mixer Control #3 */+ i2c_smbus_write_byte_data(client,0x21,ptr[7]); /* Analog Control #2 */ return 0; } static-int determine_norm(struct i2c_device* dev)+int determine_norm(struct i2c_client* client) {- struct saa7110* decoder = dev->data; int status; /* mode changed, start automatic detection */- status = saa7110_read(decoder);+ status = i2c_smbus_read_byte(client);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -