--- linux-old/Documentation/i2c/dev-interface Thu Dec 19 16:26:36 CET 2002 +++ linux/Documentation/i2c/dev-interface Thu Dec 19 16:26:36 CET 2002 @@ -88,5 +88,10 @@ ioctl(file,I2C_TENBIT,long select) Selects ten bit addresses if select not equals 0, selects normal 7 bit - addresses if select equals 0. + addresses if select equals 0. Default 0. + +ioctl(file,I2C_PEC,long select) + Selects SMBus PEC (packet error checking) generation and verification + if select not equals 0, disables if select equals 0. Default 0. + Used only for SMBus transactions. ioctl(file,I2C_FUNCS,unsigned long *funcs) --- linux-old/Documentation/i2c/functionality Thu Dec 19 16:26:36 CET 2002 +++ linux/Documentation/i2c/functionality Thu Dec 19 16:26:36 CET 2002 --- linux-old/Documentation/i2c/i2c-old-porting Thu Dec 19 16:26:36 CET 2002 +++ linux/Documentation/i2c/i2c-old-porting Thu Dec 19 16:26:36 CET 2002 @@ -0,0 +1,626 @@ +I2C Conversion Guide for I2C-old to the current I2C API +July 2002 +For Linux Kernel v2.5.x +Frank Davis +------------------------------------------------------- + +There exists several kernel drivers that are using an old version of the I2C +API. 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 to +the 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 --> #include + +Step 2: Add and set the i2c modes + +Add the following code near the top of the driver + +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; + +Step 3: Modify the driver info struct + +Within the struct for the driver , such as struct {driver_name} , make the +following change , +struct i2c_bus *bus --> struct i2c_client *client + +Make 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 functions + +Remove 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 API + +Replace all references of {driver_name}_write with i2c_smbus_write_byte_data +Replace all references of {driver_name}_read with i2c_smbus_read_byte_data or +i2c_smbus_read_byte , depending on args passed in. + +** Ensure that these functions pass in the i2c_client *client , NOT the +decoder/encoder that was passed in the driver specific write and read +functions. + +Step 7: Modify the driver's attach function + +Change 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 driver +info: + +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 function + +Change 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 function + +Change 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_driver + +Find the i2c_driver , such as +static struct i2c_driver i2c_driver_saa7110 +It is usually located towards the end of the driver +Replace the values from I2C_DRIVERID_{something} to {driver_name}_attach, and +add the following +I2C_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 Unregistering + +Replace i2c_register_driver with i2c_add_driver +Replace i2c_unregister_driver with i2c_del_driver + +------------------------------------------------------- + +Example: + +The following patch provides the i2c coversion patch for the saa7110 driver +based 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 + #include + +-#include ++#include + #include + #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); + if ((status & 3) == 0) { +- saa7110_write(decoder,0x06,0x80); ++ i2c_smbus_write_byte_data(client,0x06,0x80); + if (status & 0x20) { +- DEBUG(printk(KERN_INFO "%s: norm=bw60\n",dev->name)); +- saa7110_write(decoder,0x2E,0x81); ++ DEBUG(printk(KERN_INFO "%s: norm=bw60\n",adp->name)); ++ i2c_smbus_write_byte_data(client,0x2E,0x81); + return VIDEO_MODE_NTSC; + } +- DEBUG(printk(KERN_INFO "%s: norm=bw50\n",dev->name)); +- saa7110_write(decoder,0x2E,0x9A); ++ DEBUG(printk(KERN_INFO "%s: norm=bw50\n",adp->name)); ++ i2c_smbus_write_byte_data(client,0x2E,0x9A); + return VIDEO_MODE_PAL; + } + +- saa7110_write(decoder,0x06,0x00); ++ i2c_smbus_write_byte_data(client,0x06,0x00); + if (status & 0x20) { /* 60Hz */ +- DEBUG(printk(KERN_INFO "%s: norm=ntsc\n",dev->name)); +- saa7110_write(decoder,0x0D,0x06); +- saa7110_write(decoder,0x11,0x2C); +- saa7110_write(decoder,0x2E,0x81); ++ DEBUG(printk(KERN_INFO "%s: norm=ntsc\n",adp->name)); ++ i2c_smbus_write_byte_data(client,0x0D,0x06); ++ i2c_smbus_write_byte_data(client,0x11,0x2C); ++ i2c_smbus_write_byte_data(client,0x2E,0x81); + return VIDEO_MODE_NTSC; + } + + /* 50Hz -> PAL/SECAM */ +- saa7110_write(decoder,0x0D,0x06); +- saa7110_write(decoder,0x11,0x59); +- saa7110_write(decoder,0x2E,0x9A); ++ i2c_smbus_write_byte_data(client,0x0D,0x06); ++ i2c_smbus_write_byte_data(client,0x11,0x59); ++ i2c_smbus_write_byte_data(client,0x2E,0x9A); + + mdelay(150); /* pause 150 ms */ + +- status = saa7110_read(decoder); ++ status = i2c_smbus_read_byte(client); + if ((status & 0x03) == 0x01) { + DEBUG(printk(KERN_INFO "%s: norm=secam\n",dev->name)); +- saa7110_write(decoder,0x0D,0x07); ++ i2c_smbus_write_byte_data(client,0x0D,0x07); + return VIDEO_MODE_SECAM; + } + DEBUG(printk(KERN_INFO "%s: norm=pal\n",dev->name)); +@@ -188,7 +147,7 @@ + } + + static +-int saa7110_attach(struct i2c_device *device) ++int saa7110_attach(struct i2c_adapter *adap, int addr, unsigned short flags, int kind) + { + static const unsigned char initseq[] = { + 0, 0x4C, 0x3C, 0x0D, 0xEF, 0xBD, 0xF0, 0x00, 0x00, +@@ -198,20 +157,28 @@ + 0xD9, 0x17, 0x40, 0x41, 0x80, 0x41, 0x80, 0x4F, + 0xFE, 0x01, 0xCF, 0x0F, 0x03, 0x01, 0x81, 0x03, + 0x40, 0x75, 0x01, 0x8C, 0x03}; +- struct saa7110* decoder; ++ struct saa7110 *decoder; ++ struct i2c_client *client; + int rv; +- +- device->data = decoder = kmalloc(sizeof(struct saa7110), GFP_KERNEL); +- if (device->data == 0) ++ client=kmalloc(sizeof(*client), GFP_KERNEL); ++ if(client == NULL) + return -ENOMEM; +- +- MOD_INC_USE_COUNT; ++ client_template.adapter = adap; ++ client_template.addr = addr; ++ memcpy(client, &client_template, sizeof(*client)); ++ ++ decoder = kmalloc(sizeof(*decoder), GFP_KERNEL); ++ if (decoder == NULL) { ++ kfree(client); ++ return -ENOMEM; ++ } + + /* clear our private data */ +- memset(decoder, 0, sizeof(struct saa7110)); +- strcpy(device->name, "saa7110"); +- decoder->bus = device->bus; +- decoder->addr = device->addr; ++ memset(decoder, 0, sizeof(*decoder)); ++ strcpy(client->name, IF_NAME); ++ decoder->client = client; ++ client->data = decoder; ++ decoder->addr = addr; + decoder->norm = VIDEO_MODE_PAL; + decoder->input = 0; + decoder->enable = 1; +@@ -220,40 +187,52 @@ + decoder->hue = 32768; + decoder->sat = 32768; + +- rv = saa7110_write_block(decoder, initseq, sizeof(initseq)); ++ rv = i2c_master_send(client, initseq, sizeof(initseq)); + if (rv < 0) +- printk(KERN_ERR "%s_attach: init status %d\n", device->name, rv); ++ printk(KERN_ERR "%s_attach: init status %d\n", client->name, rv); + else { +- saa7110_write(decoder,0x21,0x16); +- saa7110_write(decoder,0x0D,0x04); +- DEBUG(printk(KERN_INFO "%s_attach: chip version %x\n", device->name, saa7110_read(decoder))); +- saa7110_write(decoder,0x0D,0x06); ++ i2c_smbus_write_byte_data(client,0x21,0x16); ++ i2c_smbus_write_byte_data(client,0x0D,0x04); ++ DEBUG(printk(KERN_INFO "%s_attach: chip version %x\n", client->name, i2c_smbus_read_byte(client))); ++ i2c_smbus_write_byte_data(client,0x0D,0x06); + } + ++ init_MUTEX(&decoder->lock); ++ i2c_attach_client(client); ++ MOD_INC_USE_COUNT; + /* setup and implicit mode 0 select has been performed */ + return 0; + } + ++static ++int saa7110_probe(struct i2c_adapter *adap) ++{ ++ return i2c_probe(adap, &addr_data, saa7110_attach); ++} ++ + static +-int saa7110_detach(struct i2c_device *device) ++int saa7110_detach(struct i2c_client *client) + { +- struct saa7110* decoder = device->data; ++ struct saa7110* decoder = client->data; + +- DEBUG(printk(KERN_INFO "%s_detach\n",device->name)); ++ i2c_detach_client(client); ++ ++ DEBUG(printk(KERN_INFO "%s_detach\n",client->name)); + + /* stop further output */ +- saa7110_write(decoder,0x0E,0x00); ++ i2c_smbus_write_byte_data(client,0x0E,0x00); + +- kfree(device->data); ++ kfree(decoder); ++ kfree(client); + + MOD_DEC_USE_COUNT; + return 0; + } + + static +-int saa7110_command(struct i2c_device *device, unsigned int cmd, void *arg) ++int saa7110_command(struct i2c_client *client, unsigned int cmd, void *arg) + { +- struct saa7110* decoder = device->data; ++ struct saa7110* decoder = client->data; + int v; + + switch (cmd) { +@@ -272,11 +251,11 @@ + + case DECODER_GET_STATUS: + { +- struct saa7110* decoder = device->data; ++ struct saa7110* decoder = client->data; + int status; + int res = 0; + +- status = i2c_read(device->bus,device->addr|1); ++ status = i2c_smbus_read_byte(client); + if (status & 0x40) + res |= DECODER_STATUS_GOOD; + if (status & 0x03) +@@ -301,26 +280,26 @@ + v = *(int*)arg; + if (decoder->norm != v) { + decoder->norm = v; +- saa7110_write(decoder, 0x06, 0x00); ++ i2c_smbus_write_byte_data(client, 0x06, 0x00); + switch (v) { + case VIDEO_MODE_NTSC: +- saa7110_write(decoder, 0x0D, 0x06); +- saa7110_write(decoder, 0x11, 0x2C); +- saa7110_write(decoder, 0x30, 0x81); +- saa7110_write(decoder, 0x2A, 0xDF); ++ i2c_smbus_write_byte_data(client, 0x0D, 0x06); ++ i2c_smbus_write_byte_data(client, 0x11, 0x2C); ++ i2c_smbus_write_byte_data(client, 0x30, 0x81); ++ i2c_smbus_write_byte_data(client, 0x2A, 0xDF); + break; + case VIDEO_MODE_PAL: +- saa7110_write(decoder, 0x0D, 0x06); +- saa7110_write(decoder, 0x11, 0x59); +- saa7110_write(decoder, 0x2E, 0x9A); ++ i2c_smbus_write_byte_data(client, 0x0D, 0x06); ++ i2c_smbus_write_byte_data(client, 0x11, 0x59); ++ i2c_smbus_write_byte_data(client, 0x2E, 0x9A); + break; + case VIDEO_MODE_SECAM: +- saa7110_write(decoder, 0x0D, 0x07); +- saa7110_write(decoder, 0x11, 0x59); +- saa7110_write(decoder, 0x2E, 0x9A); ++ i2c_smbus_write_byte_data(client, 0x0D, 0x07); ++ i2c_smbus_write_byte_data(client, 0x11, 0x59); ++ i2c_smbus_write_byte_data(client, 0x2E, 0x9A); + break; + case VIDEO_MODE_AUTO: +- *(int*)arg = determine_norm(device); ++ *(int*)arg = determine_norm(client); + break; + default: + return -EPERM; +@@ -334,7 +313,7 @@ + return -EINVAL; + if (decoder->input != v) { + decoder->input = v; +- saa7110_selmux(device, v); ++ saa7110_selmux(client, v); + } + break; + +@@ -349,7 +328,7 @@ + v = *(int*)arg; + if (decoder->enable != v) { + decoder->enable = v; +- saa7110_write(decoder,0x0E, v ? 0x18 : 0x00); ++ i2c_smbus_write_byte_data(client,0x0E, v ? 0x18 : 0x00); + } + break; + +@@ -360,22 +339,22 @@ + if (decoder->bright != pic->brightness) { + /* We want 0 to 255 we get 0-65535 */ + decoder->bright = pic->brightness; +- saa7110_write(decoder, 0x19, decoder->bright >> 8); ++ i2c_smbus_write_byte_data(client, 0x19, decoder->bright >> 8); + } + if (decoder->contrast != pic->contrast) { + /* We want 0 to 127 we get 0-65535 */ + decoder->contrast = pic->contrast; +- saa7110_write(decoder, 0x13, decoder->contrast >> 9); ++ i2c_smbus_write_byte_data(client, 0x13, decoder->contrast >> 9); + } + if (decoder->sat != pic->colour) { + /* We want 0 to 127 we get 0-65535 */ + decoder->sat = pic->colour; +- saa7110_write(decoder, 0x12, decoder->sat >> 9); ++ i2c_smbus_write_byte_data(client, 0x12, decoder->sat >> 9); + } + if (decoder->hue != pic->hue) { + /* We want -128 to 127 we get 0-65535 */ + decoder->hue = pic->hue; +- saa7110_write(decoder, 0x07, (decoder->hue>>8)-128); ++ i2c_smbus_write_byte_data(client, 0x07, (decoder->hue>>8)-128); + } + } + break; +@@ -383,7 +362,7 @@ + case DECODER_DUMP: + for (v=0; v<34; v+=16) { + int j; +- DEBUG(printk(KERN_INFO "%s: %03x\n",device->name,v)); ++ DEBUG(printk(KERN_INFO "%s: %03x\n",client->name,v)); + for (j=0; j<16; j++) { + DEBUG(printk(KERN_INFO " %02x",decoder->reg[v+j])); + } +@@ -402,24 +381,30 @@ + + static struct i2c_driver i2c_driver_saa7110 = + { +- "saa7110", /* name */ +- +- I2C_DRIVERID_VIDEODECODER, /* in i2c.h */ +- I2C_SAA7110, I2C_SAA7110+1, /* Addr range */ +- +- saa7110_attach, ++ IF_NAME, /* name */ ++ I2C_DRIVERID_SAA7110, /* in i2c.h */ ++ I2C_DF_NOTIFY, /* Addr range */ ++ saa7110_probe, + saa7110_detach, + saa7110_command + }; ++static struct i2c_client client_template = { ++ "saa7110_client", ++ -1, ++ 0, ++ 0, ++ NULL, ++ &i2c_driver_saa7110 ++}; + + static int saa7110_init(void) + { +- return i2c_register_driver(&i2c_driver_saa7110); ++ return i2c_add_driver(&i2c_driver_saa7110); + } + + static void saa7110_exit(void) + { +- i2c_unregister_driver(&i2c_driver_saa7110); ++ i2c_del_driver(&i2c_driver_saa7110); + } + + + + --- linux-old/Documentation/i2c/i2c-pport Thu Dec 19 16:26:36 CET 2002 +++ linux/Documentation/i2c/i2c-pport Thu Dec 19 16:26:36 CET 2002 @@ -0,0 +1,45 @@ +Primitive parallel port is driver for i2c bus, which exploits +features of modern bidirectional parallel ports. + +Bidirectional ports have particular bits connected in following way: + + | + /-----| R + --o| |-----| + read \-----| /------- Out pin + |/ + - -|\ + write V + | + --- + + +It means when output is set to 1 we can read the port. Therefore +we can use 2 pins of parallel port as SDA and SCL for i2c bus. It +is not necessary to add any external - additional parts, we can +read and write the same port simultaneously. + I only use register base+2 so it is possible to use all +8 data bits of parallel port for other applications (I have +connected EEPROM and LCD display). I do not use bit Enable Bi-directional + Port. The only disadvantage is we can only support 5V chips. + +Layout: + +Cannon 25 pin + +SDA - connect to pin 14 (Auto Linefeed) +SCL - connect to pin 16 (Initialize Printer) +GND - connect to pin 18-25 ++5V - use external supply (I use 5V from 3.5" floppy connector) + +no pullups requied + +Module parameters: + +base = 0xXXX +XXX - 278 or 378 + +That's all. + +Daniel Smolik +marvin@sitour.cz --- linux-old/Documentation/i2c/i2c-protocol Thu Dec 19 16:26:36 CET 2002 +++ linux/Documentation/i2c/i2c-protocol Thu Dec 19 16:26:36 CET 2002 @@ -53,8 +53,8 @@ Flag I2C_M_NOSTART: - In a combined transaction, no 'S Addr' is generated at some point. - For example, setting I2C_M_NOSTART on the second partial message + In a combined transaction, no 'S Addr Wr/Rd [A]' is generated at some + point. For example, setting I2C_M_NOSTART on the second partial message generates something like: - S Addr Rd [A] [Data] NA Wr [A] Data [A] P + S Addr Rd [A] [Data] NA Data [A] P If you set the I2C_M_NOSTART variable for the first partial message, we do not generate Addr, but we do generate the startbit S. This will @@ -66,3 +66,11 @@ flag. For example: S Addr Rd [A] Data [A] Data [A] ... [A] Data [A] P - + + Flags I2C_M_IGNORE_NAK + Normally message is interrupted immediately if there is [NA] from the + client. Setting this flag treats any [NA] as [A], and all of + message is sent. + These messages may still fail to SCL lo->hi timeout. + + Flags I2C_M_NO_RD_ACK + In a read message, master A/NA bit is skipped. --- linux-old/Documentation/i2c/i2c-velleman Thu Dec 19 16:26:36 CET 2002 +++ linux/Documentation/i2c/i2c-velleman Thu Dec 19 16:26:36 CET 2002 @@ -0,0 +1,27 @@ +i2c-velleman driver +------------------- +This is a driver for i2c-hw access for Velleman K9000 and other adapters. + +Useful links +------------ +Velleman: + http://www.velleman.be/ + +Velleman K8000 Howto: + http://howto.htlw16.ac.at/k8000-howto.html + + +K8000 and K8005 libraries +------------------------- +The project has lead to new libs for the Velleman K8000 and K8005.. +LIBK8000 v1.99.1 and LIBK8005 v0.21 + +With these libs you can control the K8000 and K8005 with the original +simple commands which are in the original Velleman software. +Like SetIOchannel, ReadADchannel, SendStepCCWFull and many more. +Via i2c kernel device /dev/velleman + +The libs can be found on http://groups.yahoo.com/group/k8000/files/linux/ + +The Velleman K8000 interface card on http://www.velleman.be/kits/k8000.htm +The Velleman K8005 steppermotorcard on http://www.velleman.be/kits/k8005.htm --- linux-old/Documentation/i2c/proc-interface Thu Dec 19 16:26:36 CET 2002 +++ linux/Documentation/i2c/proc-interface Thu Dec 19 16:26:36 CET 2002 --- linux-old/Documentation/i2c/smbus-protocol Thu Dec 19 16:26:37 CET 2002 +++ linux/Documentation/i2c/smbus-protocol Thu Dec 19 16:26:37 CET 2002 @@ -1,2 +1,9 @@ +SMBus Protocol Summary +====================== +The following is a summary of the SMBus protocol. It applies to +all revisions of the protocol (1.0, 1.1, and 2.0). +Certain protocol features which are not supported by +this package are briefly described at the end of this document. + Some adapters understand only the SMBus (System Management Bus) protocol, which is a subset from the I2C protocol. Fortunately, many devices use @@ -7,5 +14,5 @@ SMBus adapters and I2C adapters (the SMBus command set is automatically translated to I2C on I2C adapters, but plain I2C commands can not be -handled at all on a pure SMBus adapter). +handled at all on most pure SMBus adapters). Below is a list of SMBus commands. @@ -55,5 +62,5 @@ See Read Byte for more information. -S Addr Wr [A] Data NA P +S Addr Wr [A] Data [A] P @@ -110,5 +117,5 @@ ================ -This command reads a block of upto 32 bytes from a device, from a +This command reads a block of up to 32 bytes from a device, from a designated register that is specified through the Comm byte. The amount of data is specified by the device in the Count byte. @@ -121,7 +128,89 @@ ================= -The opposite of the Block Read command, this writes upto 32 bytes to +The opposite of the Block Read command, this writes up to 32 bytes to a device, to a designated register that is specified through the Comm byte. The amount of data is specified in the Count byte. S Addr Wr [A] Comm [A] Count [A] Data [A] Data [A] ... [A] Data [A] P + + +SMBus Block Process Call +======================== + +SMBus Block Process Call was introduced in Revision 2.0 of the specification. + +This command selects a device register (through the Comm byte), sends +1 to 31 bytes of data to it, and reads 1 to 31 bytes of data in return. + +S Addr Wr [A] Comm [A] Count [A] Data [A] ... + S Addr Rd [A] [Count] A [Data] ... A P + + +SMBus Host Notify +================= + +This command is sent from a SMBus device acting as a master to the +SMBus host acting as a slave. +It is the same form as Write Word, with the command code replaced by the +alerting device's address. + +[S] [HostAddr] [Wr] A [DevAddr] A [DataLow] A [DataHigh] A [P] + + +Packet Error Checking (PEC) +=========================== +Packet Error Checking was introduced in Revision 1.1 of the specification. + +PEC adds a CRC-8 error-checking byte to all transfers. + + +Address Resolution Protocol (ARP) +================================= +The Address Resolution Protocol was introduced in Revision 2.0 of +the specification. It is a higher-layer protocol which uses the +messages above. + +ARP adds device enumeration and dynamic address assignment to +the protocol. All ARP communications use slave address 0x61 and +require PEC checksums. + + +I2C Block Transactions +====================== +The following I2C block transactions are supported by the +SMBus layer and are described here for completeness. +I2C block transactions do not limit the number of bytes transferred +but the SMBus layer places a limit of 32 bytes. + + +I2C Block Read +============== + +This command reads a block of bytes from a device, from a +designated register that is specified through the Comm byte. + +S Addr Wr [A] Comm [A] + S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P + + +I2C Block Read (2 Comm bytes) +============================= + +This command reads a block of bytes from a device, from a +designated register that is specified through the two Comm bytes. + +S Addr Wr [A] Comm1 [A] Comm2 [A] + S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P + + +I2C Block Write +=============== + +The opposite of the Block Read command, this writes bytes to +a device, to a designated register that is specified through the +Comm byte. Note that command lengths of 0, 2, or more bytes are +supported as they are indistinguishable from data. + +S Addr Wr [A] Comm [A] Data [A] Data [A] ... [A] Data [A] P + + --- linux-old/Documentation/i2c/summary Thu Dec 19 16:26:37 CET 2002 +++ linux/Documentation/i2c/summary Thu Dec 19 16:26:37 CET 2002 @@ -5,5 +5,5 @@ I2C (pronounce: I squared C) is a protocol developed by Philips. It is a -slow two-wire protocol (10-100 kHz), but it suffices for many types of +slow two-wire protocol (10-400 kHz), but it suffices for many types of devices. @@ -44,5 +44,5 @@ Included Bus Drivers ==================== -Note that not only stable drivers are patched into the kernel by 'mkpatch'. +Note that only stable drivers are patched into the kernel by 'mkpatch'. @@ -50,7 +50,7 @@ ------------ -i2c-core: The basic I2C code, including the /proc interface -i2c-dev: The /dev interface -i2c-proc: The /proc interface for device (client) drivers +i2c-core: The basic I2C code, including the /proc/bus/i2c* interface +i2c-dev: The /dev/i2c-* interface +i2c-proc: The /proc/sys/dev/sensors interface for device (client) drivers Algorithm drivers @@ -60,5 +60,5 @@ i2c-algo-bit: A bit-banging algorithm i2c-algo-pcf: A PCF 8584 style algorithm -i2c-algo-ppc405: An algorithm for the I2C device in IBM 405xx processors (NOT BUILT BY DEFAULT) +i2c-algo-ibm_ocp: An algorithm for the I2C device in IBM 4xx processors (NOT BUILT BY DEFAULT) Adapter drivers @@ -67,7 +67,7 @@ i2c-elektor: Elektor ISA card (uses i2c-algo-pcf) i2c-elv: ELV parallel port adapter (uses i2c-algo-bit) -i2c-pcf-epp: PCF8584 on a EPP parallel port (uses i2c-algo-pcf) (BROKEN - missing i2c-pcf-epp.h) +i2c-pcf-epp: PCF8584 on a EPP parallel port (uses i2c-algo-pcf) (NOT mkpatched) i2c-philips-par: Philips style parallel port adapter (uses i2c-algo-bit) -i2c-ppc405: IBM 405xx processor I2C device (uses i2c-algo-ppc405) (NOT BUILT BY DEFAULT) +i2c-adap-ibm_ocp: IBM 4xx processor I2C device (uses i2c-algo-ibm_ocp) (NOT BUILT BY DEFAULT) i2c-pport: Primitive parallel port adapter (uses i2c-algo-bit) i2c-rpx: RPX board Motorola 8xx I2C device (uses i2c-algo-8xx) (NOT BUILT BY DEFAULT) --- linux-old/Documentation/i2c/ten-bit-addresses Thu Dec 19 16:26:37 CET 2002 +++ linux/Documentation/i2c/ten-bit-addresses Thu Dec 19 16:26:37 CET 2002 --- linux-old/Documentation/i2c/writing-clients Thu Dec 19 16:26:37 CET 2002 +++ linux/Documentation/i2c/writing-clients Thu Dec 19 16:26:37 CET 2002 @@ -366,5 +366,5 @@ The detect client function is called by i2c_probe or i2c_detect. The `kind' parameter contains 0 if this call is due to a `force' -parameter, and 0 otherwise (for i2c_detect, it contains 0 if +parameter, and -1 otherwise (for i2c_detect, it contains 0 if this call is due to the generic `force' parameter, and the chip type number if it is due to a specific `force' parameter). @@ -449,7 +449,7 @@ need it, remove it. We do it here to help to lessen memory fragmentation. */ - if (! (new_client = kmalloc(sizeof(struct i2c_client)) + + if (! (new_client = kmalloc(sizeof(struct i2c_client) + sizeof(struct foo_data), - GFP_KERNEL)) { + GFP_KERNEL))) { err = -ENOMEM; goto ERROR0; --- linux-old/drivers/i2c/i2c-adap-ibm_ocp.c Thu Dec 19 16:26:37 CET 2002 +++ linux/drivers/i2c/i2c-adap-ibm_ocp.c Thu Dec 19 16:26:37 CET 2002 @@ -0,0 +1,401 @@ +/* + ------------------------------------------------------------------------- + i2c-adap-ibm_ocp.c i2c-hw access for the IIC peripheral on the IBM PPC 405 + ------------------------------------------------------------------------- + + Ian DaSilva, MontaVista Software, Inc. + idasilva@mvista.com or source@mvista.com + + Copyright 2000 MontaVista Software Inc. + + Changes made to support the IIC peripheral on the IBM PPC 405 + + + ---------------------------------------------------------------------------- + This file was highly leveraged from i2c-elektor.c, which was created + by Simon G. Vogl and Hans Berglund: + + + Copyright (C) 1995-97 Simon G. Vogl + 1998-99 Hans Berglund + + With some changes from Kyösti Mälkki and even + Frodo Looijaard + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + ---------------------------------------------------------------------------- + + History: 01/20/12 - Armin + akuster@mvista.com + ported up to 2.4.16+ + + Version 02/03/25 - Armin + converted to ocp format + removed commented out or #if 0 code + + TODO: convert to ocp_register + add PM hooks + +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif + +/* + * This next section is configurable, and it is used to set the number + * of i2c controllers in the system. The default number of instances is 1, + * however, this should be changed to reflect your system's configuration. + */ + +/* + * The STB03xxx, with a PPC405 core, has two i2c controllers. + */ +//(sizeof(IIC_ADDR)/sizeof(struct iic_regs)) +extern iic_t *IIC_ADDR[]; +static struct iic_ibm iic_ibmocp_adaps[IIC_NUMS][5]; + +static struct i2c_algo_iic_data *iic_ibmocp_data[IIC_NUMS]; +static struct i2c_adapter *iic_ibmocp_ops[IIC_NUMS]; + +static int i2c_debug=0; +static wait_queue_head_t iic_wait[IIC_NUMS]; +static int iic_pending; +spinlock_t irq_driver_lock = SPIN_LOCK_UNLOCKED; + + +/* ----- global defines ----------------------------------------------- */ +#define DEB(x) if (i2c_debug>=1) x +#define DEB2(x) if (i2c_debug>=2) x +#define DEB3(x) if (i2c_debug>=3) x +#define DEBE(x) x /* error messages */ + +/* ----- local functions ---------------------------------------------- */ + +// +// Description: Write a byte to IIC hardware +// +static void iic_ibmocp_setbyte(void *data, int ctl, int val) +{ + // writeb resolves to a write to the specified memory location + // plus a call to eieio. eieio ensures that all instructions + // preceding it are completed before any further stores are + // completed. + // Delays at this level (to protect writes) are not needed here. + writeb(val, ctl); +} + + +// +// Description: Read a byte from IIC hardware +// +static int iic_ibmocp_getbyte(void *data, int ctl) +{ + int val; + + val = readb(ctl); + return (val); +} + + +// +// Description: Return our slave address. This is the address +// put on the I2C bus when another master on the bus wants to address us +// as a slave +// +static int iic_ibmocp_getown(void *data) +{ + return(((struct iic_ibm *)(data))->iic_own); +} + + +// +// Description: Return the clock rate +// +static int iic_ibmocp_getclock(void *data) +{ + return(((struct iic_ibm *)(data))->iic_clock); +} + + +#if 0 +static void iic_ibmocp_sleep(unsigned long timeout) +{ + schedule_timeout( timeout * HZ); +} +#endif + + +// +// Description: Put this process to sleep. We will wake up when the +// IIC controller interrupts. +// +static void iic_ibmocp_waitforpin(void *data) { + + int timeout = 2; + struct iic_ibm *priv_data = data; + + // + // If interrupts are enabled (which they are), then put the process to + // sleep. This process will be awakened by two events -- either the + // the IIC peripheral interrupts or the timeout expires. + // + if (priv_data->iic_irq > 0) { + spin_lock_irq(&irq_driver_lock); + if (iic_pending == 0) { + interruptible_sleep_on_timeout(&(iic_wait[priv_data->index]), timeout*HZ ); + } else + iic_pending = 0; + spin_unlock_irq(&irq_driver_lock); + } else { + // + // If interrupts are not enabled then delay for a reasonable amount + // of time and return. We expect that by time we return to the calling + // function that the IIC has finished our requested transaction and + // the status bit reflects this. + // + // udelay is probably not the best choice for this since it is + // the equivalent of a busy wait + // + udelay(100); + } + //printk("iic_ibmocp_waitforpin: exitting\n"); +} + + +// +// Description: The registered interrupt handler +// +static void iic_ibmocp_handler(int this_irq, void *dev_id, struct pt_regs *regs) +{ + int ret; + struct iic_regs *iic; + struct iic_ibm *priv_data = dev_id; + iic = (struct iic_regs *) priv_data->iic_base; + iic_pending = 1; + DEB2(printk("iic_ibmocp_handler: in interrupt handler\n")); + // Read status register + ret = readb((int) &(iic->sts)); + DEB2(printk("iic_ibmocp_handler: status = %x\n", ret)); + // Clear status register. See IBM PPC 405 reference manual for details + writeb(0x0a, (int) &(iic->sts)); + wake_up_interruptible(&(iic_wait[priv_data->index])); +} + + +// +// Description: This function is very hardware dependent. First, we lock +// the region of memory where out registers exist. Next, we request our +// interrupt line and register its associated handler. Our IIC peripheral +// uses interrupt number 2, as specified by the 405 reference manual. +// +static int iic_hw_resrc_init(int instance) +{ + + DEB(printk("iic_hw_resrc_init: Physical Base address: 0x%x\n", (u32) IIC_ADDR[instance] )); + iic_ibmocp_adaps[instance]->iic_base = (u32)ioremap((unsigned long)IIC_ADDR[instance],PAGE_SIZE); + + DEB(printk("iic_hw_resrc_init: ioremapped base address: 0x%x\n", iic_ibmocp_adaps[instance]->iic_base)); + + if (iic_ibmocp_adaps[instance]->iic_irq > 0) { + + if (request_irq(iic_ibmocp_adaps[instance]->iic_irq, iic_ibmocp_handler, + 0, "IBM OCP IIC", iic_ibmocp_adaps[instance]) < 0) { + printk(KERN_ERR "iic_hw_resrc_init: Request irq%d failed\n", + iic_ibmocp_adaps[instance]->iic_irq); + iic_ibmocp_adaps[instance]->iic_irq = 0; + } else { + DEB3(printk("iic_hw_resrc_init: Enabled interrupt\n")); + } + } + return 0; +} + + +// +// Description: Release irq and memory +// +static void iic_ibmocp_release(void) +{ + int i; + + for(i=0; idata; + if (priv_data->iic_irq > 0) { + disable_irq(priv_data->iic_irq); + free_irq(priv_data->iic_irq, 0); + } + kfree(iic_ibmocp_data[i]); + kfree(iic_ibmocp_ops[i]); + } +} + + +// +// Description: Does nothing +// +static int iic_ibmocp_reg(struct i2c_client *client) +{ + return 0; +} + + +// +// Description: Does nothing +// +static int iic_ibmocp_unreg(struct i2c_client *client) +{ + return 0; +} + + +// +// Description: If this compiled as a module, then increment the count +// +static void iic_ibmocp_inc_use(struct i2c_adapter *adap) +{ +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif +} + + +// +// Description: If this is a module, then decrement the count +// +static void iic_ibmocp_dec_use(struct i2c_adapter *adap) +{ +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif +} + +// +// Description: Called when the module is loaded. This function starts the +// cascade of calls up through the heirarchy of i2c modules (i.e. up to the +// algorithm layer and into to the core layer) +// +int __init iic_ibmocp_init(void) +{ + int i; + + printk(KERN_INFO "iic_ibmocp_init: IBM on-chip iic adapter module\n"); + + for(i=0; iiic_irq = IIC_IRQ(0); + break; + case 1: + iic_ibmocp_adaps[i]->iic_irq = IIC_IRQ(1); + break; + } + iic_ibmocp_adaps[i]->iic_clock = IIC_CLOCK; + iic_ibmocp_adaps[i]->iic_own = IIC_OWN; + iic_ibmocp_adaps[i]->index = i; + + DEB(printk("irq %x\n", iic_ibmocp_adaps[i]->iic_irq)); + DEB(printk("clock %x\n", iic_ibmocp_adaps[i]->iic_clock)); + DEB(printk("own %x\n", iic_ibmocp_adaps[i]->iic_own)); + DEB(printk("index %x\n", iic_ibmocp_adaps[i]->index)); + + + iic_ibmocp_data[i]->data = (struct iic_regs *)iic_ibmocp_adaps[i]; + iic_ibmocp_data[i]->setiic = iic_ibmocp_setbyte; + iic_ibmocp_data[i]->getiic = iic_ibmocp_getbyte; + iic_ibmocp_data[i]->getown = iic_ibmocp_getown; + iic_ibmocp_data[i]->getclock = iic_ibmocp_getclock; + iic_ibmocp_data[i]->waitforpin = iic_ibmocp_waitforpin; + iic_ibmocp_data[i]->udelay = 80; + iic_ibmocp_data[i]->mdelay = 80; + iic_ibmocp_data[i]->timeout = 100; + + iic_ibmocp_ops[i] = kmalloc(sizeof(struct i2c_adapter), GFP_KERNEL); + if(iic_ibmocp_ops[i] == NULL) { + return -ENOMEM; + } + memset(iic_ibmocp_ops[i], 0, sizeof(struct i2c_adapter)); + strcpy(iic_ibmocp_ops[i]->name, "IBM OCP IIC adapter"); + iic_ibmocp_ops[i]->id = I2C_HW_OCP; + iic_ibmocp_ops[i]->algo = NULL; + iic_ibmocp_ops[i]->algo_data = iic_ibmocp_data[i]; + iic_ibmocp_ops[i]->inc_use = iic_ibmocp_inc_use; + iic_ibmocp_ops[i]->dec_use = iic_ibmocp_dec_use; + iic_ibmocp_ops[i]->client_register = iic_ibmocp_reg; + iic_ibmocp_ops[i]->client_unregister = iic_ibmocp_unreg; + + + init_waitqueue_head(&(iic_wait[i])); + if (iic_hw_resrc_init(i) == 0) { + if (i2c_ocp_add_bus(iic_ibmocp_ops[i]) < 0) + return -ENODEV; + } else { + return -ENODEV; + } + DEB(printk(KERN_INFO "iic_ibmocp_init: found device at %#x.\n\n", iic_ibmocp_adaps[i]->iic_base)); + } + return 0; +} + + +static void iic_ibmocp_exit(void) +{ + int i; + + for(i=0; i"); +MODULE_DESCRIPTION("I2C-Bus adapter routines for PPC 405 IIC bus adapter"); +MODULE_PARM(base, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(clock, "i"); +MODULE_PARM(own, "i"); +MODULE_PARM(i2c_debug,"i"); + + +module_init(iic_ibmocp_init); +module_exit(iic_ibmocp_exit); --- linux-old/drivers/i2c/i2c-algo-8xx.c Thu Dec 19 16:26:38 CET 2002 +++ linux/drivers/i2c/i2c-algo-8xx.c Thu Dec 19 16:26:38 CET 2002 @@ -0,0 +1,676 @@ +/* + * i2c-algo-8xx.c i2x driver algorithms for MPC8XX CPM + * Copyright (c) 1999 Dan Malek (dmalek@jlc.net). + * + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * moved into proper i2c interface; separated out platform specific + * parts into i2c-rpx.c + * Brad Parker (brad@heeltoe.com) + */ + +// XXX todo +// timeout sleep? + +/* $Id: i2c-algo-8xx.c,v 1.8 2002/11/18 21:35:27 mds Exp $ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#define CPM_MAX_READ 513 +/* #define I2C_CHIP_ERRATA */ /* Try uncomment this if you have an older CPU(earlier than rev D4) */ +static wait_queue_head_t iic_wait; +static ushort r_tbase, r_rbase; + +int cpm_scan = 0; +int cpm_debug = 0; + +static void +cpm_iic_interrupt(void *dev_id, struct pt_regs *regs) +{ + volatile i2c8xx_t *i2c = (i2c8xx_t *)dev_id; + if (cpm_debug > 1) + printk("cpm_iic_interrupt(dev_id=%p)\n", dev_id); +#if 0 + /* Chip errata, clear enable. This is not needed on rev D4 CPUs */ + /* This should probably be removed and replaced by I2C_CHIP_ERRATA stuff */ + /* Someone with a buggy CPU needs to confirm that */ + i2c->i2c_i2mod &= ~1; +#endif + /* Clear interrupt. + */ + i2c->i2c_i2cer = 0xff; + + /* Get 'me going again. + */ + wake_up_interruptible(&iic_wait); +} + +static void +cpm_iic_init(struct i2c_algo_8xx_data *cpm_adap) +{ + volatile iic_t *iip = cpm_adap->iip; + volatile i2c8xx_t *i2c = cpm_adap->i2c; + unsigned char brg; + bd_t *bd = (bd_t *)__res; + + if (cpm_debug) printk(KERN_DEBUG "cpm_iic_init()\n"); + + /* Initialize the parameter ram. + * We need to make sure many things are initialized to zero, + * especially in the case of a microcode patch. + */ + iip->iic_rstate = 0; + iip->iic_rdp = 0; + iip->iic_rbptr = 0; + iip->iic_rbc = 0; + iip->iic_rxtmp = 0; + iip->iic_tstate = 0; + iip->iic_tdp = 0; + iip->iic_tbptr = 0; + iip->iic_tbc = 0; + iip->iic_txtmp = 0; + + /* Set up the IIC parameters in the parameter ram. + */ + iip->iic_tbase = r_tbase = cpm_adap->dp_addr; + iip->iic_rbase = r_rbase = cpm_adap->dp_addr + sizeof(cbd_t)*2; + + iip->iic_tfcr = SMC_EB; + iip->iic_rfcr = SMC_EB; + + /* Set maximum receive size. + */ + iip->iic_mrblr = CPM_MAX_READ; + + /* Initialize Tx/Rx parameters. + */ + if (cpm_adap->reloc == 0) { + volatile cpm8xx_t *cp = cpm_adap->cp; + + cp->cp_cpcr = + mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + } else { + iip->iic_rbptr = iip->iic_rbase; + iip->iic_tbptr = iip->iic_tbase; + iip->iic_rstate = 0; + iip->iic_tstate = 0; + } + + /* Select an arbitrary address. Just make sure it is unique. + */ + i2c->i2c_i2add = 0xfe; + + /* Make clock run at 60 KHz. + */ + brg = (unsigned char) (bd->bi_intfreq/(32*2*60000) -3); + i2c->i2c_i2brg = brg; + + i2c->i2c_i2mod = 0x00; + i2c->i2c_i2com = 0x01; /* Master mode */ + + /* Disable interrupts. + */ + i2c->i2c_i2cmr = 0; + i2c->i2c_i2cer = 0xff; + + init_waitqueue_head(&iic_wait); + + /* Install interrupt handler. + */ + if (cpm_debug) { + printk ("%s[%d] Install ISR for IRQ %d\n", + __func__,__LINE__, CPMVEC_I2C); + } + (*cpm_adap->setisr)(CPMVEC_I2C, cpm_iic_interrupt, (void *)i2c); +} + + +static int +cpm_iic_shutdown(struct i2c_algo_8xx_data *cpm_adap) +{ + volatile i2c8xx_t *i2c = cpm_adap->i2c; + + /* Shut down IIC. + */ + i2c->i2c_i2mod &= ~1; + i2c->i2c_i2cmr = 0; + i2c->i2c_i2cer = 0xff; + + return(0); +} + +static void +cpm_reset_iic_params(volatile iic_t *iip) +{ + iip->iic_tbase = r_tbase; + iip->iic_rbase = r_rbase; + + iip->iic_tfcr = SMC_EB; + iip->iic_rfcr = SMC_EB; + + iip->iic_mrblr = CPM_MAX_READ; + + iip->iic_rstate = 0; + iip->iic_rdp = 0; + iip->iic_rbptr = iip->iic_rbase; + iip->iic_rbc = 0; + iip->iic_rxtmp = 0; + iip->iic_tstate = 0; + iip->iic_tdp = 0; + iip->iic_tbptr = iip->iic_tbase; + iip->iic_tbc = 0; + iip->iic_txtmp = 0; +} + +#define BD_SC_NAK ((ushort)0x0004) /* NAK - did not respond */ +#define BD_SC_OV ((ushort)0x0002) /* OV - receive overrun */ +#define CPM_CR_CLOSE_RXBD ((ushort)0x0007) + +static void force_close(struct i2c_algo_8xx_data *cpm) +{ + volatile i2c8xx_t *i2c = cpm->i2c; + if (cpm->reloc == 0) { /* micro code disabled */ + volatile cpm8xx_t *cp = cpm->cp; + + if (cpm_debug) printk("force_close()\n"); + cp->cp_cpcr = + mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_CLOSE_RXBD) | + CPM_CR_FLG; + + while (cp->cp_cpcr & CPM_CR_FLG); + } + i2c->i2c_i2cmr = 0x00; /* Disable all interrupts */ + i2c->i2c_i2cer = 0xff; +} + + +/* Read from IIC... + * abyte = address byte, with r/w flag already set + */ +static int +cpm_iic_read(struct i2c_algo_8xx_data *cpm, u_char abyte, char *buf, int count) +{ + volatile iic_t *iip = cpm->iip; + volatile i2c8xx_t *i2c = cpm->i2c; + volatile cpm8xx_t *cp = cpm->cp; + volatile cbd_t *tbdf, *rbdf; + u_char *tb; + unsigned long flags, tmo; + + if (count >= CPM_MAX_READ) + return -EINVAL; + + /* check for and use a microcode relocation patch */ + if (cpm->reloc) { + cpm_reset_iic_params(iip); + } + + tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase]; + rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase]; + + /* To read, we need an empty buffer of the proper length. + * All that is used is the first byte for address, the remainder + * is just used for timing (and doesn't really have to exist). + */ + tb = cpm->temp; + tb = (u_char *)(((uint)tb + 15) & ~15); + tb[0] = abyte; /* Device address byte w/rw flag */ + + flush_dcache_range((unsigned long) tb, (unsigned long) (tb+1)); + + if (cpm_debug) printk("cpm_iic_read(abyte=0x%x)\n", abyte); + + tbdf->cbd_bufaddr = __pa(tb); + tbdf->cbd_datlen = count + 1; + tbdf->cbd_sc = + BD_SC_READY | BD_SC_LAST | + BD_SC_WRAP | BD_IIC_START; + + iip->iic_mrblr = count +1; /* prevent excessive read, +1 + is needed otherwise will the + RXB interrupt come too early */ + + /* flush will invalidate too. */ + flush_dcache_range((unsigned long) buf, (unsigned long) (buf+count)); + + rbdf->cbd_datlen = 0; + rbdf->cbd_bufaddr = __pa(buf); + rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP| BD_SC_INTRPT; + if(count > 16){ + /* Chip bug, set enable here */ + local_irq_save(flags); + i2c->i2c_i2cmr = 0x13; /* Enable some interupts */ + i2c->i2c_i2cer = 0xff; + i2c->i2c_i2mod |= 1; /* Enable */ + i2c->i2c_i2com |= 0x80; /* Begin transmission */ + + /* Wait for IIC transfer */ + tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ); + local_irq_restore(flags); + } else { /* busy wait for small transfers, its faster */ + i2c->i2c_i2cmr = 0x00; /* Disable I2C interupts */ + i2c->i2c_i2cer = 0xff; + i2c->i2c_i2mod |= 1; /* Enable */ + i2c->i2c_i2com |= 0x80; /* Begin transmission */ + tmo = jiffies + 1*HZ; + while(!(i2c->i2c_i2cer & 0x11 || time_after(jiffies, tmo))); /* Busy wait, with a timeout */ + } + + if (signal_pending(current) || !tmo){ + force_close(cpm); + if(cpm_debug) + printk("IIC read: timeout!\n"); + return -EIO; + } +#ifdef I2C_CHIP_ERRATA + /* Chip errata, clear enable. This is not needed on rev D4 CPUs. + Disabling I2C too early may cause too short stop condition */ + udelay(4); + i2c->i2c_i2mod &= ~1; +#endif + if (cpm_debug) { + printk("tx sc %04x, rx sc %04x\n", + tbdf->cbd_sc, rbdf->cbd_sc); + } + + if (tbdf->cbd_sc & BD_SC_READY) { + printk("IIC read; complete but tbuf ready\n"); + force_close(cpm); + printk("tx sc %04x, rx sc %04x\n", + tbdf->cbd_sc, rbdf->cbd_sc); + } + + if (tbdf->cbd_sc & BD_SC_NAK) { + if (cpm_debug) + printk("IIC read; no ack\n"); + return -EREMOTEIO; + } + + if (rbdf->cbd_sc & BD_SC_EMPTY) { + /* force_close(cpm); */ + if (cpm_debug){ + printk("IIC read; complete but rbuf empty\n"); + printk("tx sc %04x, rx sc %04x\n", + tbdf->cbd_sc, rbdf->cbd_sc); + } + return -EREMOTEIO; + } + + if (rbdf->cbd_sc & BD_SC_OV) { + if (cpm_debug) + printk("IIC read; Overrun\n"); + return -EREMOTEIO;; + } + + if (cpm_debug) printk("read %d bytes\n", rbdf->cbd_datlen); + + if (rbdf->cbd_datlen < count) { + if (cpm_debug) + printk("IIC read; short, wanted %d got %d\n", + count, rbdf->cbd_datlen); + return 0; + } + + return count; +} + +/* Write to IIC... + * addr = address byte, with r/w flag already set + */ +static int +cpm_iic_write(struct i2c_algo_8xx_data *cpm, u_char abyte, char *buf,int count) +{ + volatile iic_t *iip = cpm->iip; + volatile i2c8xx_t *i2c = cpm->i2c; + volatile cpm8xx_t *cp = cpm->cp; + volatile cbd_t *tbdf; + u_char *tb; + unsigned long flags, tmo; + + /* check for and use a microcode relocation patch */ + if (cpm->reloc) { + cpm_reset_iic_params(iip); + } + tb = cpm->temp; + tb = (u_char *)(((uint)tb + 15) & ~15); + *tb = abyte; /* Device address byte w/rw flag */ + + flush_dcache_range((unsigned long) tb, (unsigned long) (tb+1)); + flush_dcache_range((unsigned long) buf, (unsigned long) (buf+count)); + + if (cpm_debug) printk("cpm_iic_write(abyte=0x%x)\n", abyte); + + /* set up 2 descriptors */ + tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase]; + + tbdf[0].cbd_bufaddr = __pa(tb); + tbdf[0].cbd_datlen = 1; + tbdf[0].cbd_sc = BD_SC_READY | BD_IIC_START; + + tbdf[1].cbd_bufaddr = __pa(buf); + tbdf[1].cbd_datlen = count; + tbdf[1].cbd_sc = BD_SC_READY | BD_SC_INTRPT | BD_SC_LAST | BD_SC_WRAP; + + if(count > 16){ + /* Chip bug, set enable here */ + local_irq_save(flags); + i2c->i2c_i2cmr = 0x13; /* Enable some interupts */ + i2c->i2c_i2cer = 0xff; + i2c->i2c_i2mod |= 1; /* Enable */ + i2c->i2c_i2com |= 0x80; /* Begin transmission */ + + /* Wait for IIC transfer */ + tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ); + local_irq_restore(flags); + } else { /* busy wait for small transfers, its faster */ + i2c->i2c_i2cmr = 0x00; /* Disable I2C interupts */ + i2c->i2c_i2cer = 0xff; + i2c->i2c_i2mod |= 1; /* Enable */ + i2c->i2c_i2com |= 0x80; /* Begin transmission */ + tmo = jiffies + 1*HZ; + while(!(i2c->i2c_i2cer & 0x12 || time_after(jiffies, tmo))); /* Busy wait, with a timeout */ + } + + if (signal_pending(current) || !tmo){ + force_close(cpm); + if(cpm_debug && !tmo) + printk("IIC write: timeout!\n"); + return -EIO; + } + +#if I2C_CHIP_ERRATA + /* Chip errata, clear enable. This is not needed on rev D4 CPUs. + Disabling I2C too early may cause too short stop condition */ + udelay(4); + i2c->i2c_i2mod &= ~1; +#endif + if (cpm_debug) { + printk("tx0 sc %04x, tx1 sc %04x\n", + tbdf[0].cbd_sc, tbdf[1].cbd_sc); + } + + if (tbdf->cbd_sc & BD_SC_NAK) { + if (cpm_debug) + printk("IIC write; no ack\n"); + return 0; + } + + if (tbdf->cbd_sc & BD_SC_READY) { + if (cpm_debug) + printk("IIC write; complete but tbuf ready\n"); + return 0; + } + + return count; +} + +/* See if an IIC address exists.. + * addr = 7 bit address, unshifted + */ +static int +cpm_iic_tryaddress(struct i2c_algo_8xx_data *cpm, int addr) +{ + volatile iic_t *iip = cpm->iip; + volatile i2c8xx_t *i2c = cpm->i2c; + volatile cpm8xx_t *cp = cpm->cp; + volatile cbd_t *tbdf, *rbdf; + u_char *tb; + unsigned long flags, len, tmo; + + if (cpm_debug > 1) + printk("cpm_iic_tryaddress(cpm=%p,addr=%d)\n", cpm, addr); + + /* check for and use a microcode relocation patch */ + if (cpm->reloc) { + cpm_reset_iic_params(iip); + } + + if (cpm_debug && addr == 0) { + printk("iip %p, dp_addr 0x%x\n", cpm->iip, cpm->dp_addr); + printk("iic_tbase %d, r_tbase %d\n", iip->iic_tbase, r_tbase); + } + + tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase]; + rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase]; + + tb = cpm->temp; + tb = (u_char *)(((uint)tb + 15) & ~15); + + /* do a simple read */ + tb[0] = (addr << 1) | 1; /* device address (+ read) */ + len = 2; + + flush_dcache_range((unsigned long) tb, (unsigned long) (tb+2)); + + tbdf->cbd_bufaddr = __pa(tb); + tbdf->cbd_datlen = len; + tbdf->cbd_sc = + BD_SC_READY | BD_SC_LAST | + BD_SC_WRAP | BD_IIC_START; + + rbdf->cbd_datlen = 0; + rbdf->cbd_bufaddr = __pa(tb+2); + rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP | BD_SC_INTRPT; + + local_irq_save(flags); + i2c->i2c_i2cmr = 0x13; /* Enable some interupts */ + i2c->i2c_i2cer = 0xff; + i2c->i2c_i2mod |= 1; /* Enable */ + i2c->i2c_i2com |= 0x80; /* Begin transmission */ + + if (cpm_debug > 1) printk("about to sleep\n"); + + /* wait for IIC transfer */ + tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ); + local_irq_restore(flags); + +#ifdef I2C_CHIP_ERRATA + /* Chip errata, clear enable. This is not needed on rev D4 CPUs. + Disabling I2C too early may cause too short stop condition */ + udelay(4); + i2c->i2c_i2mod &= ~1; +#endif + + if (signal_pending(current) || !tmo){ + force_close(cpm); + if(cpm_debug && !tmo) + printk("IIC tryaddress: timeout!\n"); + return -EIO; + } + + if (cpm_debug > 1) printk("back from sleep\n"); + + if (tbdf->cbd_sc & BD_SC_NAK) { + if (cpm_debug > 1) printk("IIC try; no ack\n"); + return 0; + } + + if (tbdf->cbd_sc & BD_SC_READY) { + printk("IIC try; complete but tbuf ready\n"); + } + + return 1; +} + +static int cpm_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg msgs[], + int num) +{ + struct i2c_algo_8xx_data *adap = i2c_adap->algo_data; + struct i2c_msg *pmsg; + int i, ret; + u_char addr; + + for (i = 0; i < num; i++) { + pmsg = &msgs[i]; + + if (cpm_debug) + printk("i2c-algo-8xx.o: " + "#%d addr=0x%x flags=0x%x len=%d\n buf=%lx\n", + i, pmsg->addr, pmsg->flags, pmsg->len, (unsigned long)pmsg->buf); + + addr = pmsg->addr << 1; + if (pmsg->flags & I2C_M_RD ) + addr |= 1; + if (pmsg->flags & I2C_M_REV_DIR_ADDR ) + addr ^= 1; + + if (!(pmsg->flags & I2C_M_NOSTART)) { + } + if (pmsg->flags & I2C_M_RD ) { + /* read bytes into buffer*/ + ret = cpm_iic_read(adap, addr, pmsg->buf, pmsg->len); + if (cpm_debug) + printk("i2c-algo-8xx.o: read %d bytes\n", ret); + if (ret < pmsg->len ) { + return (ret<0)? ret : -EREMOTEIO; + } + } else { + /* write bytes from buffer */ + ret = cpm_iic_write(adap, addr, pmsg->buf, pmsg->len); + if (cpm_debug) + printk("i2c-algo-8xx.o: wrote %d\n", ret); + if (ret < pmsg->len ) { + return (ret<0) ? ret : -EREMOTEIO; + } + } + } + return (num); +} + +static int algo_control(struct i2c_adapter *adapter, + unsigned int cmd, unsigned long arg) +{ + return 0; +} + +static u32 cpm_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | + I2C_FUNC_PROTOCOL_MANGLING; +} + +/* -----exported algorithm data: ------------------------------------- */ + +static struct i2c_algorithm cpm_algo = { + "MPC8xx CPM algorithm", + I2C_ALGO_MPC8XX, + cpm_xfer, + NULL, + NULL, /* slave_xmit */ + NULL, /* slave_recv */ + algo_control, /* ioctl */ + cpm_func, /* functionality */ +}; + +/* + * registering functions to load algorithms at runtime + */ +int i2c_8xx_add_bus(struct i2c_adapter *adap) +{ + int i; + struct i2c_algo_8xx_data *cpm_adap = adap->algo_data; + + if (cpm_debug) + printk("i2c-algo-8xx.o: hw routines for %s registered.\n", + adap->name); + + /* register new adapter to i2c module... */ + + adap->id |= cpm_algo.id; + adap->algo = &cpm_algo; + +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + + i2c_add_adapter(adap); + cpm_iic_init(cpm_adap); + + /* scan bus */ + if (cpm_scan) { + printk(KERN_INFO " i2c-algo-8xx.o: scanning bus %s...\n", + adap->name); + for (i = 0; i < 128; i++) { + if (cpm_iic_tryaddress(cpm_adap, i)) { + printk("(%02x)",i<<1); + } + } + printk("\n"); + } + return 0; +} + + +int i2c_8xx_del_bus(struct i2c_adapter *adap) +{ + int res; + struct i2c_algo_8xx_data *cpm_adap = adap->algo_data; + + cpm_iic_shutdown(cpm_adap); + + if ((res = i2c_del_adapter(adap)) < 0) + return res; + + printk("i2c-algo-8xx.o: adapter unregistered: %s\n",adap->name); + +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + return 0; +} + +EXPORT_SYMBOL(i2c_8xx_add_bus); +EXPORT_SYMBOL(i2c_8xx_del_bus); + +int __init i2c_algo_8xx_init (void) +{ + printk("i2c-algo-8xx.o: i2c mpc8xx algorithm module version %s (%s)\n", I2C_VERSION, I2C_DATE); + return 0; +} + + +#ifdef MODULE +MODULE_AUTHOR("Brad Parker "); +MODULE_DESCRIPTION("I2C-Bus MPC8XX algorithm"); +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif + +int init_module(void) +{ + return i2c_algo_8xx_init(); +} + +void cleanup_module(void) +{ +} +#endif --- linux-old/include/linux/i2c-algo-8xx.h Thu Dec 19 16:26:38 CET 2002 +++ linux/include/linux/i2c-algo-8xx.h Thu Dec 19 16:26:38 CET 2002 @@ -0,0 +1,43 @@ +/* ------------------------------------------------------------------------- */ +/* i2c-algo-8xx.h i2c driver algorithms for MPX8XX CPM */ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* ------------------------------------------------------------------------- */ + +/* $Id: i2c-algo-8xx.h,v 1.3 2002/06/12 02:29:54 mds Exp $ */ + +#ifndef I2C_ALGO_8XX_H +#define I2C_ALGO_8XX_H 1 + +#include + +struct i2c_algo_8xx_data { + uint dp_addr; + int reloc; + volatile i2c8xx_t *i2c; + volatile iic_t *iip; + volatile cpm8xx_t *cp; + + int (*setisr) (int irq, + void (*func)(void *, void *), + void *data); + + u_char temp[513]; +}; + +int i2c_8xx_add_bus(struct i2c_adapter *); +int i2c_8xx_del_bus(struct i2c_adapter *); + +#endif /* I2C_ALGO_8XX_H */ --- linux-old/drivers/i2c/i2c-algo-bit.c Thu Dec 19 16:26:38 CET 2002 +++ linux/drivers/i2c/i2c-algo-bit.c Thu Dec 19 16:26:38 CET 2002 @@ -22,5 +22,5 @@ Frodo Looijaard */ -/* $Id: i2c-algo-bit.c,v 1.30 2001/07/29 02:44:25 mds Exp $ */ +/* $Id: i2c-algo-bit.c,v 1.40 2002/12/03 22:31:34 kmalkki Exp $ */ #include @@ -34,5 +34,4 @@ #include #include - #include #include @@ -50,5 +49,5 @@ /* might not like this, as they have an internal timeout of some mils */ /* -#define SLO_IO jif=jiffies;while(time_before_eq(jiffies, jif+i2c_table[minor].veryslow))\ +#define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\ if (need_resched) schedule(); */ @@ -101,15 +100,14 @@ static inline int sclhi(struct i2c_algo_bit_data *adap) { - int start=jiffies; + int start; setscl(adap,1); - udelay(adap->udelay); - /* Not all adapters have scl sense line... */ if (adap->getscl == NULL ) return 0; - while (! getscl(adap) ) { + start=jiffies; + while (! getscl(adap) ) { /* the hw knows how to read the clock line, * so we wait until it actually gets high. @@ -117,12 +115,16 @@ * while they are processing data internally. */ - setscl(adap,1); - if (time_after_eq(jiffies, start+adap->timeout)) { + if ( time_after(jiffies, start+adap->timeout) ) { return -ETIMEDOUT; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) if (current->need_resched) schedule(); +#else + cond_resched(); +#endif } - DEBSTAT(printk("needed %ld jiffies\n", jiffies-start)); + DEBSTAT(printk(KERN_DEBUG "needed %ld jiffies\n", jiffies-start)); + udelay(adap->udelay); #ifdef SLO_IO SLO_IO @@ -146,5 +148,5 @@ DEBPROTO(printk(" Sr ")); setsda(adap,1); - setscl(adap,1); + sclhi(adap); udelay(adap->udelay); @@ -180,12 +182,12 @@ /* assert: scl is low */ - DEB2(printk(" i2c_outb:%2.2X\n",c&0xff)); for ( i=7 ; i>=0 ; i-- ) { sb = c & ( 1 << i ); setsda(adap,sb); udelay(adap->udelay); - DEBPROTO(printk("%d",sb!=0)); + DEBPROTO(printk(KERN_DEBUG "%d",sb!=0)); if (sclhi(adap)<0) { /* timed out */ sdahi(adap); /* we don't want to block the net */ + DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x, timeout at bit #%d\n", c&0xff, i)); return -ETIMEDOUT; }; @@ -198,12 +200,13 @@ sdahi(adap); if (sclhi(adap)<0){ /* timeout */ - return -ETIMEDOUT; + DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x, timeout at ack\n", c&0xff)); + return -ETIMEDOUT; }; /* read ack: SDA should be pulled down by slave */ ack=getsda(adap); /* ack: sda is pulled low ->success. */ - DEB2(printk(" i2c_outb: getsda() = 0x%2.2x\n", ~ack )); + DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x , getsda() = %d\n", c & 0xff, ack)); - DEBPROTO( printk("[%2.2x]",c&0xff) ); - DEBPROTO(if (0==ack){ printk(" A ");} else printk(" NA ") ); + DEBPROTO( printk(KERN_DEBUG "[%2.2x]",c&0xff) ); + DEBPROTO(if (0==ack){ printk(KERN_DEBUG " A ");} else printk(KERN_DEBUG " NA ") ); scllo(adap); return 0==ack; /* return 1 if device acked */ @@ -221,9 +224,8 @@ /* assert: scl is low */ - DEB2(printk("i2c_inb.\n")); - sdahi(adap); for (i=0;i<8;i++) { if (sclhi(adap)<0) { /* timeout */ + DEB2(printk(KERN_DEBUG " i2c_inb: timeout at bit #%d\n", 7-i)); return -ETIMEDOUT; }; @@ -234,5 +236,7 @@ } /* assert: scl is low */ - DEBPROTO(printk(" %2.2x", indata & 0xff)); + DEB2(printk(KERN_DEBUG "i2c_inb: 0x%02x\n", indata & 0xff)); + + DEBPROTO(printk(KERN_DEBUG " 0x%02x", indata & 0xff)); return (int) (indata & 0xff); } @@ -246,67 +250,67 @@ sda=getsda(adap); if (adap->getscl==NULL) { - printk("i2c-algo-bit.o: Warning: Adapter can't read from clock line - skipping test.\n"); + printk(KERN_WARNING "i2c-algo-bit.o: Warning: Adapter can't read from clock line - skipping test.\n"); return 0; } scl=getscl(adap); - printk("i2c-algo-bit.o: Adapter: %s scl: %d sda: %d -- testing...\n", + printk(KERN_INFO "i2c-algo-bit.o: Adapter: %s scl: %d sda: %d -- testing...\n", name,getscl(adap),getsda(adap)); if (!scl || !sda ) { - printk("i2c-algo-bit.o: %s seems to be busy.\n",name); + printk(KERN_INFO " i2c-algo-bit.o: %s seems to be busy.\n",name); goto bailout; } sdalo(adap); - printk("i2c-algo-bit.o:1 scl: %d sda: %d \n",getscl(adap), + printk(KERN_DEBUG "i2c-algo-bit.o:1 scl: %d sda: %d \n",getscl(adap), getsda(adap)); if ( 0 != getsda(adap) ) { - printk("i2c-algo-bit.o: %s SDA stuck high!\n",name); + printk(KERN_WARNING "i2c-algo-bit.o: %s SDA stuck high!\n",name); sdahi(adap); goto bailout; } if ( 0 == getscl(adap) ) { - printk("i2c-algo-bit.o: %s SCL unexpected low while pulling SDA low!\n", + printk(KERN_WARNING "i2c-algo-bit.o: %s SCL unexpected low while pulling SDA low!\n", name); goto bailout; } sdahi(adap); - printk("i2c-algo-bit.o:2 scl: %d sda: %d \n",getscl(adap), + printk(KERN_DEBUG "i2c-algo-bit.o:2 scl: %d sda: %d \n",getscl(adap), getsda(adap)); if ( 0 == getsda(adap) ) { - printk("i2c-algo-bit.o: %s SDA stuck low!\n",name); + printk(KERN_WARNING "i2c-algo-bit.o: %s SDA stuck low!\n",name); sdahi(adap); goto bailout; } if ( 0 == getscl(adap) ) { - printk("i2c-algo-bit.o: %s SCL unexpected low while SDA high!\n", + printk(KERN_WARNING "i2c-algo-bit.o: %s SCL unexpected low while SDA high!\n", name); goto bailout; } scllo(adap); - printk("i2c-algo-bit.o:3 scl: %d sda: %d \n",getscl(adap), + printk(KERN_DEBUG "i2c-algo-bit.o:3 scl: %d sda: %d \n",getscl(adap), getsda(adap)); if ( 0 != getscl(adap) ) { - printk("i2c-algo-bit.o: %s SCL stuck high!\n",name); + printk(KERN_WARNING "i2c-algo-bit.o: %s SCL stuck high!\n",name); sclhi(adap); goto bailout; } if ( 0 == getsda(adap) ) { - printk("i2c-algo-bit.o: %s SDA unexpected low while pulling SCL low!\n", + printk(KERN_WARNING "i2c-algo-bit.o: %s SDA unexpected low while pulling SCL low!\n", name); goto bailout; } sclhi(adap); - printk("i2c-algo-bit.o:4 scl: %d sda: %d \n",getscl(adap), + printk(KERN_DEBUG "i2c-algo-bit.o:4 scl: %d sda: %d \n",getscl(adap), getsda(adap)); if ( 0 == getscl(adap) ) { - printk("i2c-algo-bit.o: %s SCL stuck low!\n",name); + printk(KERN_WARNING "i2c-algo-bit.o: %s SCL stuck low!\n",name); sclhi(adap); goto bailout; } if ( 0 == getsda(adap) ) { - printk("i2c-algo-bit.o: %s SDA unexpected low while SCL high!\n", + printk(KERN_WARNING "i2c-algo-bit.o: %s SDA unexpected low while SCL high!\n", name); goto bailout; } - printk("i2c-algo-bit.o: %s passed test.\n",name); + printk(KERN_INFO "i2c-algo-bit.o: %s passed test.\n",name); return 0; bailout: @@ -342,14 +346,19 @@ udelay(adap->udelay); } - DEB2(if (i) printk("i2c-algo-bit.o: needed %d retries for %d\n", - i,addr)); + DEB2(if (i) + printk(KERN_DEBUG "i2c-algo-bit.o: Used %d tries to %s client at 0x%02x : %s\n", + i+1, addr & 1 ? "read" : "write", addr>>1, + ret==1 ? "success" : ret==0 ? "no ack" : "failed, timeout?" ) + ); return ret; } -static int sendbytes(struct i2c_adapter *i2c_adap,const char *buf, int count) +static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) { struct i2c_algo_bit_data *adap = i2c_adap->algo_data; char c; - const char *temp = buf; + const char *temp = msg->buf; + int count = msg->len; + unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK; int retval; int wrcount=0; @@ -357,13 +366,13 @@ while (count > 0) { c = *temp; - DEB2(printk("i2c-algo-bit.o: %s i2c_write: writing %2.2X\n", + DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: %s sendbytes: writing %2.2X\n", i2c_adap->name, c&0xff)); retval = i2c_outb(i2c_adap,c); - if (retval>0) { + if ((retval>0) || (nak_ok && (retval==0))) { /* ok or ignored NAK */ count--; temp++; wrcount++; } else { /* arbitration or no acknowledge */ - printk("i2c-algo-bit.o: %s i2c_write: error - bailout.\n", + printk(KERN_ERR "i2c-algo-bit.o: %s sendbytes: error - bailout.\n", i2c_adap->name); i2c_stop(adap); @@ -379,10 +388,11 @@ } -static inline int readbytes(struct i2c_adapter *i2c_adap,char *buf,int count) +static inline int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) { - char *temp = buf; int inval; int rdcount=0; /* counts bytes read */ struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + char *temp = msg->buf; + int count = msg->len; while (count > 0) { @@ -393,5 +403,5 @@ rdcount++; } else { /* read timed out */ - printk("i2c-algo-bit.o: i2c_read: i2c_inb timed out.\n"); + printk(KERN_ERR "i2c-algo-bit.o: readbytes: i2c_inb timed out.\n"); break; } @@ -406,5 +416,5 @@ if (sclhi(adap)<0) { /* timeout */ sdahi(adap); - printk("i2c-algo-bit.o: i2c_read: Timeout at ack\n"); + printk(KERN_ERR "i2c-algo-bit.o: readbytes: Timeout at ack\n"); return -ETIMEDOUT; }; @@ -421,31 +431,34 @@ * reads, writes as well as 10bit-addresses. * returns: - * 0 everything went okay, the chip ack'ed + * 0 everything went okay, the chip ack'ed, or IGNORE_NAK flag was set * -x an error occurred (like: -EREMOTEIO if the device did not answer, or * -ETIMEDOUT, for example if the lines are stuck...) */ -static inline int bit_doAddress(struct i2c_adapter *i2c_adap, - struct i2c_msg *msg, int retries) +static inline int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) { unsigned short flags = msg->flags; + unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK; struct i2c_algo_bit_data *adap = i2c_adap->algo_data; unsigned char addr; - int ret; + int ret, retries; + + retries = nak_ok ? 0 : i2c_adap->retries; + if ( (flags & I2C_M_TEN) ) { /* a ten bit address */ addr = 0xf0 | (( msg->addr >> 7) & 0x03); - DEB2(printk("addr0: %d\n",addr)); + DEB2(printk(KERN_DEBUG "addr0: %d\n",addr)); /* try extended address code...*/ ret = try_address(i2c_adap, addr, retries); - if (ret!=1) { - printk("died at extended address code.\n"); + if ((ret != 1) && !nak_ok) { + printk(KERN_ERR "died at extended address code.\n"); return -EREMOTEIO; } /* the remaining 8 bit address */ ret = i2c_outb(i2c_adap,msg->addr & 0x7f); - if (ret != 1) { + if ((ret != 1) && !nak_ok) { /* the chip did not ack / xmission error occurred */ - printk("died at 2nd address code.\n"); + printk(KERN_ERR "died at 2nd address code.\n"); return -EREMOTEIO; } @@ -455,7 +468,7 @@ addr |= 0x01; ret = try_address(i2c_adap, addr, retries); - if (ret!=1) { - printk("died at extended address code.\n"); - return -EREMOTEIO; + if ((ret!=1) && !nak_ok) { + printk(KERN_ERR "died at extended address code.\n"); + return -EREMOTEIO; } } @@ -467,8 +480,8 @@ addr ^= 1; ret = try_address(i2c_adap, addr, retries); - if (ret!=1) { + if ((ret!=1) && !nak_ok) return -EREMOTEIO; - } } + return 0; } @@ -481,23 +494,25 @@ int i,ret; + unsigned short nak_ok; i2c_start(adap); for (i=0;iflags & I2C_M_IGNORE_NAK; if (!(pmsg->flags & I2C_M_NOSTART)) { if (i) { i2c_repstart(adap); } - ret = bit_doAddress(i2c_adap,pmsg,i2c_adap->retries); - if (ret != 0) { - DEB2(printk("i2c-algo-bit.o: NAK from device adr %#2x msg #%d\n" - ,msgs[i].addr,i)); - return (ret<0) ? ret : -EREMOTEIO; + ret = bit_doAddress(i2c_adap, pmsg); + if ((ret != 0) && !nak_ok) { + DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: NAK from device addr %2.2x msg #%d\n" + ,msgs[i].addr,i)); + return (ret<0) ? ret : -EREMOTEIO; } } if (pmsg->flags & I2C_M_RD ) { /* read bytes into buffer*/ - ret = readbytes(i2c_adap,pmsg->buf,pmsg->len); - DEB2(printk("i2c-algo-bit.o: read %d bytes.\n",ret)); + ret = readbytes(i2c_adap, pmsg); + DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: read %d bytes.\n",ret)); if (ret < pmsg->len ) { return (ret<0)? ret : -EREMOTEIO; @@ -505,6 +520,6 @@ } else { /* write bytes from buffer */ - ret = sendbytes(i2c_adap,pmsg->buf,pmsg->len); - DEB2(printk("i2c-algo-bit.o: wrote %d bytes.\n",ret)); + ret = sendbytes(i2c_adap, pmsg); + DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: wrote %d bytes.\n",ret)); if (ret < pmsg->len ) { return (ret<0) ? ret : -EREMOTEIO; @@ -516,5 +531,5 @@ } -static int algo_control(struct i2c_adapter *adapter, +static int algo_control(struct i2c_adapter *i2c_adap, unsigned int cmd, unsigned long arg) { @@ -522,5 +537,5 @@ } -static u32 bit_func(struct i2c_adapter *adap) +static u32 bit_func(struct i2c_adapter *i2c_adap) { return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | @@ -545,25 +560,25 @@ * registering functions to load algorithms at runtime */ -int i2c_bit_add_bus(struct i2c_adapter *adap) +int i2c_bit_add_bus(struct i2c_adapter *i2c_adap) { int i; - struct i2c_algo_bit_data *bit_adap = adap->algo_data; + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; if (bit_test) { - int ret = test_bus(bit_adap, adap->name); + int ret = test_bus(adap, i2c_adap->name); if (ret<0) return -ENODEV; } - DEB2(printk("i2c-algo-bit.o: hw routines for %s registered.\n", - adap->name)); + DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: hw routines for %s registered.\n", + i2c_adap->name)); /* register new adapter to i2c module... */ - adap->id |= i2c_bit_algo.id; - adap->algo = &i2c_bit_algo; + i2c_adap->id |= i2c_bit_algo.id; + i2c_adap->algo = &i2c_bit_algo; - adap->timeout = 100; /* default values, should */ - adap->retries = 3; /* be replaced by defines */ + i2c_adap->timeout = HZ; /* default values, should */ + i2c_adap->retries = 3; /* be replaced by defines */ /* scan bus */ @@ -571,9 +586,9 @@ int ack; printk(KERN_INFO " i2c-algo-bit.o: scanning bus %s.\n", - adap->name); + i2c_adap->name); for (i = 0x00; i < 0xff; i+=2) { - i2c_start(bit_adap); - ack = i2c_outb(adap,i); - i2c_stop(bit_adap); + i2c_start(adap); + ack = i2c_outb(i2c_adap,i); + i2c_stop(adap); if (ack>0) { printk("(%02x)",i>>1); @@ -587,5 +602,5 @@ MOD_INC_USE_COUNT; #endif - i2c_add_adapter(adap); + i2c_add_adapter(i2c_adap); return 0; @@ -593,12 +608,12 @@ -int i2c_bit_del_bus(struct i2c_adapter *adap) +int i2c_bit_del_bus(struct i2c_adapter *i2c_adap) { int res; - if ((res = i2c_del_adapter(adap)) < 0) + if ((res = i2c_del_adapter(i2c_adap)) < 0) return res; - DEB2(printk("i2c-algo-bit.o: adapter unregistered: %s\n",adap->name)); + DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: adapter unregistered: %s\n",i2c_adap->name)); #ifdef MODULE @@ -610,5 +625,5 @@ int __init i2c_algo_bit_init (void) { - printk("i2c-algo-bit.o: i2c bit algorithm module\n"); + printk(KERN_INFO "i2c-algo-bit.o: i2c bit algorithm module version %s (%s)\n", I2C_VERSION, I2C_DATE); return 0; } @@ -622,5 +637,7 @@ MODULE_AUTHOR("Simon G. Vogl "); MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm"); +#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); +#endif MODULE_PARM(bit_test, "i"); --- linux-old/include/linux/i2c-algo-bit.h Thu Dec 19 16:26:38 CET 2002 +++ linux/include/linux/i2c-algo-bit.h Thu Dec 19 16:26:38 CET 2002 @@ -22,5 +22,5 @@ Frodo Looijaard */ -/* $Id: i2c-algo-bit.h,v 1.7 1999/12/21 23:45:58 frodo Exp $ */ +/* $Id: i2c-algo-bit.h,v 1.9 2002/11/26 00:10:52 mds Exp $ */ #ifndef I2C_ALGO_BIT_H @@ -43,7 +43,8 @@ /* local settings */ - int udelay; - int mdelay; - int timeout; + int udelay; /* half-clock-cycle time in microsecs */ + /* i.e. clock is (500 / udelay) KHz */ + int mdelay; /* in millisecs, unused */ + int timeout; /* in jiffies */ }; --- linux-old/drivers/i2c/i2c-algo-ibm_ocp.c Thu Dec 19 16:26:38 CET 2002 +++ linux/drivers/i2c/i2c-algo-ibm_ocp.c Thu Dec 19 16:26:38 CET 2002 @@ -0,0 +1,966 @@ +/* + ------------------------------------------------------------------------- + i2c-algo-ibm_ocp.c i2c driver algorithms for IBM PPC 405 adapters + ------------------------------------------------------------------------- + + Ian DaSilva, MontaVista Software, Inc. + idasilva@mvista.com or source@mvista.com + + Copyright 2000 MontaVista Software Inc. + + Changes made to support the IIC peripheral on the IBM PPC 405 + + + --------------------------------------------------------------------------- + This file was highly leveraged from i2c-algo-pcf.c, which was created + by Simon G. Vogl and Hans Berglund: + + + Copyright (C) 1995-1997 Simon G. Vogl + 1998-2000 Hans Berglund + + With some changes from Kyösti Mälkki and + Frodo Looijaard ,and also from Martin Bailey + + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + --------------------------------------------------------------------------- + + History: 01/20/12 - Armin + akuster@mvista.com + ported up to 2.4.16+ + + Version 02/03/25 - Armin + converted to ocp format + removed commented out or #if 0 code + added Gérard Basler's fix to iic_combined_transaction() such that it + returns the number of successfully completed transfers . +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif + + +/* ----- global defines ----------------------------------------------- */ +#define DEB(x) if (i2c_debug>=1) x +#define DEB2(x) if (i2c_debug>=2) x +#define DEB3(x) if (i2c_debug>=3) x /* print several statistical values*/ +#define DEBPROTO(x) if (i2c_debug>=9) x; + /* debug the protocol by showing transferred bits */ +#define DEF_TIMEOUT 5 + +/* debugging - slow down transfer to have a look at the data .. */ +/* I use this with two leds&resistors, each one connected to sda,scl */ +/* respectively. This makes sure that the algorithm works. Some chips */ +/* might not like this, as they have an internal timeout of some mils */ +/* +#define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\ + if (need_resched) schedule(); +*/ + + +/* ----- global variables --------------------------------------------- */ + +#ifdef SLO_IO + int jif; +#endif + +/* module parameters: + */ +static int i2c_debug=0; +static int iic_scan=0; /* have a look at what's hanging 'round */ + +/* --- setting states on the bus with the right timing: --------------- */ + +#define iic_outb(adap, reg, val) adap->setiic(adap->data, (int) &(reg), val) +#define iic_inb(adap, reg) adap->getiic(adap->data, (int) &(reg)) + +#define IICO_I2C_SDAHIGH 0x0780 +#define IICO_I2C_SDALOW 0x0781 +#define IICO_I2C_SCLHIGH 0x0782 +#define IICO_I2C_SCLLOW 0x0783 +#define IICO_I2C_LINEREAD 0x0784 + +#define IIC_SINGLE_XFER 0 +#define IIC_COMBINED_XFER 1 + +#define IIC_ERR_LOST_ARB -2 +#define IIC_ERR_INCOMPLETE_XFR -3 +#define IIC_ERR_NACK -1 + +/* --- other auxiliary functions -------------------------------------- */ + + +// +// Description: Puts this process to sleep for a period equal to timeout +// +static inline void iic_sleep(unsigned long timeout) +{ + schedule_timeout( timeout * HZ); +} + + +// +// Description: This performs the IBM PPC 405 IIC initialization sequence +// as described in the PPC405GP data book. +// +static int iic_init (struct i2c_algo_iic_data *adap) +{ + struct iic_regs *iic; + struct iic_ibm *adap_priv_data = adap->data; + unsigned short retval; + iic = (struct iic_regs *) adap_priv_data->iic_base; + + /* Clear master low master address */ + iic_outb(adap,iic->lmadr, 0); + + /* Clear high master address */ + iic_outb(adap,iic->hmadr, 0); + + /* Clear low slave address */ + iic_outb(adap,iic->lsadr, 0); + + /* Clear high slave address */ + iic_outb(adap,iic->hsadr, 0); + + /* Clear status */ + iic_outb(adap,iic->sts, 0x0a); + + /* Clear extended status */ + iic_outb(adap,iic->extsts, 0x8f); + + /* Set clock division */ + iic_outb(adap,iic->clkdiv, 0x04); + + retval = iic_inb(adap, iic->clkdiv); + DEB(printk("iic_init: CLKDIV register = %x\n", retval)); + + /* Enable interrupts on Requested Master Transfer Complete */ + iic_outb(adap,iic->intmsk, 0x01); + + /* Clear transfer count */ + iic_outb(adap,iic->xfrcnt, 0x0); + + /* Clear extended control and status */ + iic_outb(adap,iic->xtcntlss, 0xf0); + + /* Set mode control (flush master data buf, enable hold SCL, exit */ + /* unknown state. */ + iic_outb(adap,iic->mdcntl, 0x47); + + /* Clear control register */ + iic_outb(adap,iic->cntl, 0x0); + + DEB2(printk(KERN_DEBUG "iic_init: Initialized IIC on PPC 405\n")); + return 0; +} + + +// +// Description: After we issue a transaction on the IIC bus, this function +// is called. It puts this process to sleep until we get an interrupt from +// from the controller telling us that the transaction we requested in complete. +// +static int wait_for_pin(struct i2c_algo_iic_data *adap, int *status) +{ + + int timeout = DEF_TIMEOUT; + int retval; + struct iic_regs *iic; + struct iic_ibm *adap_priv_data = adap->data; + iic = (struct iic_regs *) adap_priv_data->iic_base; + + + *status = iic_inb(adap, iic->sts); +#ifndef STUB_I2C + + while (timeout-- && (*status & 0x01)) { + adap->waitforpin(adap->data); + *status = iic_inb(adap, iic->sts); + } +#endif + if (timeout <= 0) { + /* Issue stop signal on the bus, and force an interrupt */ + retval = iic_inb(adap, iic->cntl); + iic_outb(adap, iic->cntl, retval | 0x80); + /* Clear status register */ + iic_outb(adap, iic->sts, 0x0a); + /* Exit unknown bus state */ + retval = iic_inb(adap, iic->mdcntl); + iic_outb(adap, iic->mdcntl, (retval | 0x02)); + + // Check the status of the controller. Does it still see a + // pending transfer, even though we've tried to stop any + // ongoing transaction? + retval = iic_inb(adap, iic->sts); + retval = retval & 0x01; + if(retval) { + // The iic controller is hosed. It is not responding to any + // of our commands. We have already tried to force it into + // a known state, but it has not worked. Our only choice now + // is a soft reset, which will clear all registers, and force + // us to re-initialize the controller. + /* Soft reset */ + iic_outb(adap, iic->xtcntlss, 0x01); + udelay(500); + iic_init(adap); + /* Is the pending transfer bit in the sts reg finally cleared? */ + retval = iic_inb(adap, iic->sts); + retval = retval & 0x01; + if(retval) { + printk(KERN_CRIT "The IIC Controller is hosed. A processor reset is required\n"); + } + // For some reason, even though the interrupt bit in this + // register was set during iic_init, it didn't take. We + // need to set it again. Don't ask me why....this is just what + // I saw when testing timeouts. + iic_outb(adap, iic->intmsk, 0x01); + } + return(-1); + } + else + return(0); +} + + +//------------------------------------ +// Utility functions +// + + +// +// Description: Look at the status register to see if there was an error +// in the requested transaction. If there is, look at the extended status +// register and determine the exact cause. +// +int analyze_status(struct i2c_algo_iic_data *adap, int *error_code) +{ + int ret; + struct iic_regs *iic; + struct iic_ibm *adap_priv_data = adap->data; + iic = (struct iic_regs *) adap_priv_data->iic_base; + + + ret = iic_inb(adap, iic->sts); + if(ret & 0x04) { + // Error occurred + ret = iic_inb(adap, iic->extsts); + if(ret & 0x04) { + // Lost arbitration + *error_code = IIC_ERR_LOST_ARB; + } + if(ret & 0x02) { + // Incomplete transfer + *error_code = IIC_ERR_INCOMPLETE_XFR; + } + if(ret & 0x01) { + // Master transfer aborted by a NACK during the transfer of the + // address byte + *error_code = IIC_ERR_NACK; + } + return -1; + } + return 0; +} + + +// +// Description: This function is called by the upper layers to do the +// grunt work for a master send transaction +// +static int iic_sendbytes(struct i2c_adapter *i2c_adap,const char *buf, + int count, int xfer_flag) +{ + struct iic_regs *iic; + struct i2c_algo_iic_data *adap = i2c_adap->algo_data; + struct iic_ibm *adap_priv_data = adap->data; + int wrcount, status, timeout; + int loops, remainder, i, j; + int ret, error_code; + iic = (struct iic_regs *) adap_priv_data->iic_base; + + + if( count == 0 ) return 0; + wrcount = 0; + loops = count / 4; + remainder = count % 4; + + if((loops > 1) && (remainder == 0)) { + for(i=0; i<(loops-1); i++) { + // + // Write four bytes to master data buffer + // + for(j=0; j<4; j++) { + iic_outb(adap, iic->mdbuf, + buf[wrcount++]); + } + // + // Issue command to IICO device to begin transmission + // + iic_outb(adap, iic->cntl, 0x35); + // + // Wait for transmission to complete. When it does, + //loop to the top of the for statement and write the + // next four bytes. + // + timeout = wait_for_pin(adap, &status); + if(timeout < 0) { + // + // Error handling + // + //printk(KERN_ERR "Error: write timeout\n"); + return wrcount; + } + ret = analyze_status(adap, &error_code); + if(ret < 0) { + if(error_code == IIC_ERR_INCOMPLETE_XFR) { + // Return the number of bytes transferred + ret = iic_inb(adap, iic->xfrcnt); + ret = ret & 0x07; + return (wrcount-4+ret); + } + else return error_code; + } + } + } + else if((loops >= 1) && (remainder > 0)){ + //printk(KERN_DEBUG "iic_sendbytes: (loops >= 1)\n"); + for(i=0; imdbuf, + buf[wrcount++]); + } + // + // Issue command to IICO device to begin transmission + // + iic_outb(adap, iic->cntl, 0x35); + // + // Wait for transmission to complete. When it does, + //loop to the top of the for statement and write the + // next four bytes. + // + timeout = wait_for_pin(adap, &status); + if(timeout < 0) { + // + // Error handling + // + //printk(KERN_ERR "Error: write timeout\n"); + return wrcount; + } + ret = analyze_status(adap, &error_code); + if(ret < 0) { + if(error_code == IIC_ERR_INCOMPLETE_XFR) { + // Return the number of bytes transferred + ret = iic_inb(adap, iic->xfrcnt); + ret = ret & 0x07; + return (wrcount-4+ret); + } + else return error_code; + } + } + } + + //printk(KERN_DEBUG "iic_sendbytes: expedite write\n"); + if(remainder == 0) remainder = 4; + // remainder = remainder - 1; + // + // Write the remaining bytes (less than or equal to 4) + // + for(i=0; imdbuf, buf[wrcount++]); + //printk(KERN_DEBUG "iic_sendbytes: data transferred = %x, wrcount = %d\n", buf[wrcount-1], (wrcount-1)); + } + //printk(KERN_DEBUG "iic_sendbytes: Issuing write\n"); + + if(xfer_flag == IIC_COMBINED_XFER) { + iic_outb(adap, iic->cntl, (0x09 | ((remainder-1) << 4))); + } + else { + iic_outb(adap, iic->cntl, (0x01 | ((remainder-1) << 4))); + } + DEB2(printk(KERN_DEBUG "iic_sendbytes: Waiting for interrupt\n")); + timeout = wait_for_pin(adap, &status); + if(timeout < 0) { + // + // Error handling + // + //printk(KERN_ERR "Error: write timeout\n"); + return wrcount; + } + ret = analyze_status(adap, &error_code); + if(ret < 0) { + if(error_code == IIC_ERR_INCOMPLETE_XFR) { + // Return the number of bytes transferred + ret = iic_inb(adap, iic->xfrcnt); + ret = ret & 0x07; + return (wrcount-4+ret); + } + else return error_code; + } + DEB2(printk(KERN_DEBUG "iic_sendbytes: Got interrupt\n")); + return wrcount; +} + + +// +// Description: Called by the upper layers to do the grunt work for +// a master read transaction. +// +static int iic_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count, int xfer_type) +{ + struct iic_regs *iic; + int rdcount=0, i, status, timeout; + struct i2c_algo_iic_data *adap = i2c_adap->algo_data; + struct iic_ibm *adap_priv_data = adap->data; + int loops, remainder, j; + int ret, error_code; + iic = (struct iic_regs *) adap_priv_data->iic_base; + + if(count == 0) return 0; + loops = count / 4; + remainder = count % 4; + + //printk(KERN_DEBUG "iic_readbytes: loops = %d, remainder = %d\n", loops, remainder); + + if((loops > 1) && (remainder == 0)) { + //printk(KERN_DEBUG "iic_readbytes: (loops > 1) && (remainder == 0)\n"); + for(i=0; i<(loops-1); i++) { + // + // Issue command to begin master read (4 bytes maximum) + // + //printk(KERN_DEBUG "--->Issued read command\n"); + iic_outb(adap, iic->cntl, 0x37); + // + // Wait for transmission to complete. When it does, + // loop to the top of the for statement and write the + // next four bytes. + // + //printk(KERN_DEBUG "--->Waiting for interrupt\n"); + timeout = wait_for_pin(adap, &status); + if(timeout < 0) { + // Error Handler + //printk(KERN_ERR "Error: read timed out\n"); + return rdcount; + } + //printk(KERN_DEBUG "--->Got interrupt\n"); + + ret = analyze_status(adap, &error_code); + if(ret < 0) { + if(error_code == IIC_ERR_INCOMPLETE_XFR) + return rdcount; + else + return error_code; + } + + for(j=0; j<4; j++) { + // Wait for data to shuffle to top of data buffer + // This value needs to optimized. + udelay(1); + buf[rdcount] = iic_inb(adap, iic->mdbuf); + rdcount++; + //printk(KERN_DEBUG "--->Read one byte\n"); + } + } + } + + else if((loops >= 1) && (remainder > 0)){ + //printk(KERN_DEBUG "iic_readbytes: (loops >=1) && (remainder > 0)\n"); + for(i=0; iIssued read command\n"); + iic_outb(adap, iic->cntl, 0x37); + // + // Wait for transmission to complete. When it does, + // loop to the top of the for statement and write the + // next four bytes. + // + //printk(KERN_DEBUG "--->Waiting for interrupt\n"); + timeout = wait_for_pin(adap, &status); + if(timeout < 0) { + // Error Handler + //printk(KERN_ERR "Error: read timed out\n"); + return rdcount; + } + //printk(KERN_DEBUG "--->Got interrupt\n"); + + ret = analyze_status(adap, &error_code); + if(ret < 0) { + if(error_code == IIC_ERR_INCOMPLETE_XFR) + return rdcount; + else + return error_code; + } + + for(j=0; j<4; j++) { + // Wait for data to shuffle to top of data buffer + // This value needs to optimized. + udelay(1); + buf[rdcount] = iic_inb(adap, iic->mdbuf); + rdcount++; + //printk(KERN_DEBUG "--->Read one byte\n"); + } + } + } + + //printk(KERN_DEBUG "iic_readbytes: expedite read\n"); + if(remainder == 0) remainder = 4; + DEB2(printk(KERN_DEBUG "iic_readbytes: writing %x to IICO_CNTL\n", (0x03 | ((remainder-1) << 4)))); + + if(xfer_type == IIC_COMBINED_XFER) { + iic_outb(adap, iic->cntl, (0x0b | ((remainder-1) << 4))); + } + else { + iic_outb(adap, iic->cntl, (0x03 | ((remainder-1) << 4))); + } + DEB2(printk(KERN_DEBUG "iic_readbytes: Wait for pin\n")); + timeout = wait_for_pin(adap, &status); + DEB2(printk(KERN_DEBUG "iic_readbytes: Got the interrupt\n")); + if(timeout < 0) { + // Error Handler + //printk(KERN_ERR "Error: read timed out\n"); + return rdcount; + } + + ret = analyze_status(adap, &error_code); + if(ret < 0) { + if(error_code == IIC_ERR_INCOMPLETE_XFR) + return rdcount; + else + return error_code; + } + + //printk(KERN_DEBUG "iic_readbyte: Begin reading data buffer\n"); + for(i=0; imdbuf); + // printk(KERN_DEBUG "iic_readbytes: Character read = %x\n", buf[rdcount]); + rdcount++; + } + + return rdcount; +} + + +// +// Description: This function implements combined transactions. Combined +// transactions consist of combinations of reading and writing blocks of data. +// Each transfer (i.e. a read or a write) is separated by a repeated start +// condition. +// +static int iic_combined_transaction(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) +{ + int i; + struct i2c_msg *pmsg; + int ret; + + DEB2(printk(KERN_DEBUG "Beginning combined transaction\n")); + for(i=0; i < num; i++) { + pmsg = &msgs[i]; + if(pmsg->flags & I2C_M_RD) { + + // Last read or write segment needs to be terminated with a stop + if(i < num-1) { + DEB2(printk(KERN_DEBUG "This one is a read\n")); + } + else { + DEB2(printk(KERN_DEBUG "Doing the last read\n")); + } + ret = iic_readbytes(i2c_adap, pmsg->buf, pmsg->len, (i < num-1) ? IIC_COMBINED_XFER : IIC_SINGLE_XFER); + + if (ret != pmsg->len) { + DEB2(printk("i2c-algo-ppc405.o: fail: " + "only read %d bytes.\n",ret)); + return i; + } + else { + DEB2(printk("i2c-algo-ppc405.o: read %d bytes.\n",ret)); + } + } + else if(!(pmsg->flags & I2C_M_RD)) { + + // Last read or write segment needs to be terminated with a stop + if(i < num-1) { + DEB2(printk(KERN_DEBUG "This one is a write\n")); + } + else { + DEB2(printk(KERN_DEBUG "Doing the last write\n")); + } + ret = iic_sendbytes(i2c_adap, pmsg->buf, pmsg->len, (i < num-1) ? IIC_COMBINED_XFER : IIC_SINGLE_XFER); + + if (ret != pmsg->len) { + DEB2(printk("i2c-algo-ppc405.o: fail: " + "only wrote %d bytes.\n",ret)); + return i; + } + else { + DEB2(printk("i2c-algo-ppc405.o: wrote %d bytes.\n",ret)); + } + } + } + + return num; +} + + +// +// Description: Whenever we initiate a transaction, the first byte clocked +// onto the bus after the start condition is the address (7 bit) of the +// device we want to talk to. This function manipulates the address specified +// so that it makes sense to the hardware when written to the IIC peripheral. +// +// Note: 10 bit addresses are not supported in this driver, although they are +// supported by the hardware. This functionality needs to be implemented. +// +static inline int iic_doAddress(struct i2c_algo_iic_data *adap, + struct i2c_msg *msg, int retries) +{ + struct iic_regs *iic; + unsigned short flags = msg->flags; + unsigned char addr; + struct iic_ibm *adap_priv_data = adap->data; + iic = (struct iic_regs *) adap_priv_data->iic_base; + +// +// The following segment for 10 bit addresses needs to be ported +// +/* Ten bit addresses not supported right now + if ( (flags & I2C_M_TEN) ) { + // a ten bit address + addr = 0xf0 | (( msg->addr >> 7) & 0x03); + DEB2(printk(KERN_DEBUG "addr0: %d\n",addr)); + // try extended address code... + ret = try_address(adap, addr, retries); + if (ret!=1) { + printk(KERN_ERR "iic_doAddress: died at extended address code.\n"); + return -EREMOTEIO; + } + // the remaining 8 bit address + iic_outb(adap,msg->addr & 0x7f); + // Status check comes here + if (ret != 1) { + printk(KERN_ERR "iic_doAddress: died at 2nd address code.\n"); + return -EREMOTEIO; + } + if ( flags & I2C_M_RD ) { + i2c_repstart(adap); + // okay, now switch into reading mode + addr |= 0x01; + ret = try_address(adap, addr, retries); + if (ret!=1) { + printk(KERN_ERR "iic_doAddress: died at extended address code.\n"); + return -EREMOTEIO; + } + } + } else ----------> // normal 7 bit address + +Ten bit addresses not supported yet */ + + addr = ( msg->addr << 1 ); + if (flags & I2C_M_RD ) + addr |= 1; + if (flags & I2C_M_REV_DIR_ADDR ) + addr ^= 1; + // + // Write to the low slave address + // + iic_outb(adap, iic->lmadr, addr); + // + // Write zero to the high slave register since we are + // only using 7 bit addresses + // + iic_outb(adap, iic->hmadr, 0); + + return 0; +} + + +// +// Description: Prepares the controller for a transaction (clearing status +// registers, data buffers, etc), and then calls either iic_readbytes or +// iic_sendbytes to do the actual transaction. +// +static int iic_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg msgs[], + int num) +{ + struct iic_regs *iic; + struct i2c_algo_iic_data *adap = i2c_adap->algo_data; + struct iic_ibm *adap_priv_data = adap->data; + struct i2c_msg *pmsg; + int i = 0; + int ret; + iic = (struct iic_regs *) adap_priv_data->iic_base; + + pmsg = &msgs[i]; + + // + // Clear status register + // + DEB2(printk(KERN_DEBUG "iic_xfer: iic_xfer: Clearing status register\n")); + iic_outb(adap, iic->sts, 0x0a); + + // + // Wait for any pending transfers to complete + // + DEB2(printk(KERN_DEBUG "iic_xfer: Waiting for any pending transfers to complete\n")); + while((ret = iic_inb(adap, iic->sts)) == 0x01) { + ; + } + + // + // Flush master data buf + // + DEB2(printk(KERN_DEBUG "iic_xfer: Clearing master data buffer\n")); + ret = iic_inb(adap, iic->mdcntl); + iic_outb(adap, iic->mdcntl, ret | 0x40); + + // + // Load slave address + // + DEB2(printk(KERN_DEBUG "iic_xfer: Loading slave address\n")); + ret = iic_doAddress(adap, pmsg, i2c_adap->retries); + + // + // Check to see if the bus is busy + // + ret = iic_inb(adap, iic->extsts); + // Mask off the irrelevent bits + ret = ret & 0x70; + // When the bus is free, the BCS bits in the EXTSTS register are 0b100 + if(ret != 0x40) return IIC_ERR_LOST_ARB; + + // + // Combined transaction (read and write) + // + if(num > 1) { + DEB2(printk(KERN_DEBUG "iic_xfer: Call combined transaction\n")); + ret = iic_combined_transaction(i2c_adap, msgs, num); + } + // + // Read only + // + else if((num == 1) && (pmsg->flags & I2C_M_RD)) { + // + // Tell device to begin reading data from the master data + // + DEB2(printk(KERN_DEBUG "iic_xfer: Call adapter's read\n")); + ret = iic_readbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_SINGLE_XFER); + } + // + // Write only + // + else if((num == 1 ) && (!(pmsg->flags & I2C_M_RD))) { + // + // Write data to master data buffers and tell our device + // to begin transmitting + // + DEB2(printk(KERN_DEBUG "iic_xfer: Call adapter's write\n")); + ret = iic_sendbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_SINGLE_XFER); + } + + return ret; +} + + +// +// Description: Implements device specific ioctls. Higher level ioctls can +// be found in i2c-core.c and are typical of any i2c controller (specifying +// slave address, timeouts, etc). These ioctls take advantage of any hardware +// features built into the controller for which this algorithm-adapter set +// was written. These ioctls allow you to take control of the data and clock +// lines on the IBM PPC 405 IIC controller and set the either high or low, +// similar to a GPIO pin. +// +static int algo_control(struct i2c_adapter *adapter, + unsigned int cmd, unsigned long arg) +{ + struct iic_regs *iic; + struct i2c_algo_iic_data *adap = adapter->algo_data; + struct iic_ibm *adap_priv_data = adap->data; + int ret=0; + int lines; + iic = (struct iic_regs *) adap_priv_data->iic_base; + + lines = iic_inb(adap, iic->directcntl); + + if (cmd == IICO_I2C_SDAHIGH) { + lines = lines & 0x01; + if( lines ) lines = 0x04; + else lines = 0; + iic_outb(adap, iic->directcntl,(0x08|lines)); + } + else if (cmd == IICO_I2C_SDALOW) { + lines = lines & 0x01; + if( lines ) lines = 0x04; + else lines = 0; + iic_outb(adap, iic->directcntl,(0x00|lines)); + } + else if (cmd == IICO_I2C_SCLHIGH) { + lines = lines & 0x02; + if( lines ) lines = 0x08; + else lines = 0; + iic_outb(adap, iic->directcntl,(0x04|lines)); + } + else if (cmd == IICO_I2C_SCLLOW) { + lines = lines & 0x02; + if( lines ) lines = 0x08; + else lines = 0; + iic_outb(adap, iic->directcntl,(0x00|lines)); + } + else if (cmd == IICO_I2C_LINEREAD) { + ret = lines; + } + return ret; +} + + +static u32 iic_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | + I2C_FUNC_PROTOCOL_MANGLING; +} + + +/* -----exported algorithm data: ------------------------------------- */ + +static struct i2c_algorithm iic_algo = { + "IBM on-chip IIC algorithm", + I2C_ALGO_OCP, + iic_xfer, + NULL, + NULL, /* slave_xmit */ + NULL, /* slave_recv */ + algo_control, /* ioctl */ + iic_func, /* functionality */ +}; + + +/* + * registering functions to load algorithms at runtime + */ + + +// +// Description: Register bus structure +// +int i2c_ocp_add_bus(struct i2c_adapter *adap) +{ + struct i2c_algo_iic_data *iic_adap = adap->algo_data; + + DEB2(printk(KERN_DEBUG "i2c-algo-iic.o: hw routines for %s registered.\n", + adap->name)); + + /* register new adapter to i2c module... */ + + adap->id |= iic_algo.id; + adap->algo = &iic_algo; + + adap->timeout = 100; /* default values, should */ + adap->retries = 3; /* be replaced by defines */ + +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + + iic_init(iic_adap); + i2c_add_adapter(adap); + + /* scan bus */ + /* By default scanning the bus is turned off. */ + if (iic_scan) { + printk(KERN_INFO " i2c-algo-iic.o: scanning bus %s.\n", + adap->name); + } + return 0; +} + + +// +// Done +// +int i2c_ocp_del_bus(struct i2c_adapter *adap) +{ + int res; + if ((res = i2c_del_adapter(adap)) < 0) + return res; + DEB2(printk(KERN_DEBUG "i2c-algo-iic.o: adapter unregistered: %s\n",adap->name)); + +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + return 0; +} + + +// +// Done +// +int __init i2c_algo_iic_init (void) +{ + printk(KERN_INFO "IBM On-chip iic (i2c) algorithm module 2002.27.03\n"); + return 0; +} + + +void i2c_algo_iic_exit(void) +{ + return; +} + + +EXPORT_SYMBOL(i2c_ocp_add_bus); +EXPORT_SYMBOL(i2c_ocp_del_bus); + +// +// The MODULE_* macros resolve to nothing if MODULES is not defined +// when this file is compiled. +// +MODULE_AUTHOR("MontaVista Software "); +MODULE_DESCRIPTION("PPC 405 iic algorithm"); + +MODULE_PARM(iic_test, "i"); +MODULE_PARM(iic_scan, "i"); +MODULE_PARM(i2c_debug,"i"); + +MODULE_PARM_DESC(iic_test, "Test if the I2C bus is available"); +MODULE_PARM_DESC(iic_scan, "Scan for active chips on the bus"); +MODULE_PARM_DESC(i2c_debug, + "debug level - 0 off; 1 normal; 2,3 more verbose; 9 iic-protocol"); + + +module_init(i2c_algo_iic_init); +module_exit(i2c_algo_iic_exit); --- linux-old/include/linux/i2c-algo-ibm_ocp.h Thu Dec 19 16:26:38 CET 2002 +++ linux/include/linux/i2c-algo-ibm_ocp.h Thu Dec 19 16:26:38 CET 2002 @@ -0,0 +1,55 @@ +/* ------------------------------------------------------------------------- */ +/* i2c-algo-ibm_ocp.h i2c driver algorithms for IBM PPC 405 IIC adapters */ +/* ------------------------------------------------------------------------- */ +/* Copyright (C) 1995-97 Simon G. Vogl + 1998-99 Hans Berglund + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* ------------------------------------------------------------------------- */ + +/* With some changes from Kyösti Mälkki and even + Frodo Looijaard */ + +/* Modifications by MontaVista Software, August 2000 + Changes made to support the IIC peripheral on the IBM PPC 405 */ + +#ifndef I2C_ALGO_IIC_H +#define I2C_ALGO_IIC_H 1 + +/* --- Defines for pcf-adapters --------------------------------------- */ +#include + +struct i2c_algo_iic_data { + struct iic_regs *data; /* private data for lolevel routines */ + void (*setiic) (void *data, int ctl, int val); + int (*getiic) (void *data, int ctl); + int (*getown) (void *data); + int (*getclock) (void *data); + void (*waitforpin) (void *data); + + /* local settings */ + int udelay; + int mdelay; + int timeout; +}; + + +#define I2C_IIC_ADAP_MAX 16 + + +int i2c_ocp_add_bus(struct i2c_adapter *); +int i2c_ocp_del_bus(struct i2c_adapter *); + +#endif /* I2C_ALGO_IIC_H */ --- linux-old/drivers/i2c/i2c-algo-pcf.c Thu Dec 19 16:26:39 CET 2002 +++ linux/drivers/i2c/i2c-algo-pcf.c Thu Dec 19 16:26:39 CET 2002 @@ -38,5 +38,4 @@ #include #include - #include #include @@ -100,5 +99,5 @@ #endif if (timeout <= 0) { - printk("Timeout waiting for Bus Busy\n"); + printk(KERN_ERR "Timeout waiting for Bus Busy\n"); } @@ -145,5 +144,5 @@ unsigned char temp; - DEB3(printk("i2c-algo-pcf.o: PCF state 0x%02x\n", get_pcf(adap, 1))); + DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: PCF state 0x%02x\n", get_pcf(adap, 1))); /* S1=0x80: S0 selected, serial interface off */ @@ -151,7 +150,6 @@ /* check to see S1 now used as R/W ctrl - PCF8584 does that when ESO is zero */ - /* PCF also resets PIN bit */ - if ((temp = get_pcf(adap, 1)) != (0)) { - DEB2(printk("i2c-algo-pcf.o: PCF detection failed -- can't select S0 (0x%02x).\n", temp)); + if (((temp = get_pcf(adap, 1)) & 0x7f) != (0)) { + DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S0 (0x%02x).\n", temp)); return -ENXIO; /* definetly not PCF8584 */ } @@ -161,5 +159,5 @@ /* check it's realy writen */ if ((temp = i2c_inb(adap)) != get_own(adap)) { - DEB2(printk("i2c-algo-pcf.o: PCF detection failed -- can't set S0 (0x%02x).\n", temp)); + DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S0 (0x%02x).\n", temp)); return -ENXIO; } @@ -168,6 +166,6 @@ set_pcf(adap, 1, I2C_PCF_PIN | I2C_PCF_ES1); /* check to see S2 now selected */ - if ((temp = get_pcf(adap, 1)) != I2C_PCF_ES1) { - DEB2(printk("i2c-algo-pcf.o: PCF detection failed -- can't select S2 (0x%02x).\n", temp)); + if (((temp = get_pcf(adap, 1)) & 0x7f) != I2C_PCF_ES1) { + DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S2 (0x%02x).\n", temp)); return -ENXIO; } @@ -177,5 +175,5 @@ /* check it's realy writen, the only 5 lowest bits does matter */ if (((temp = i2c_inb(adap)) & 0x1f) != get_clock(adap)) { - DEB2(printk("i2c-algo-pcf.o: PCF detection failed -- can't set S2 (0x%02x).\n", temp)); + DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S2 (0x%02x).\n", temp)); return -ENXIO; } @@ -186,9 +184,9 @@ /* check to see PCF is realy idled and we can access status register */ if ((temp = get_pcf(adap, 1)) != (I2C_PCF_PIN | I2C_PCF_BB)) { - DEB2(printk("i2c-algo-pcf.o: PCF detection failed -- can't select S1` (0x%02x).\n", temp)); + DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S1` (0x%02x).\n", temp)); return -ENXIO; } - printk("i2c-algo-pcf.o: deteted and initialized PCF8584.\n"); + printk(KERN_DEBUG "i2c-algo-pcf.o: deteted and initialized PCF8584.\n"); return 0; @@ -216,5 +214,5 @@ udelay(adap->udelay); } - DEB2(if (i) printk("i2c-algo-pcf.o: needed %d retries for %d\n",i, + DEB2(if (i) printk(KERN_DEBUG "i2c-algo-pcf.o: needed %d retries for %d\n",i, addr)); return ret; @@ -229,5 +227,5 @@ for (wrcount=0; wrcountname, buf[wrcount]&0xff)); i2c_outb(adap, buf[wrcount]); @@ -235,5 +233,5 @@ if (timeout) { i2c_stop(adap); - printk("i2c-algo-pcf.o: %s i2c_write: " + printk(KERN_ERR "i2c-algo-pcf.o: %s i2c_write: " "error - timeout.\n", i2c_adap->name); return -EREMOTEIO; /* got a better one ?? */ @@ -242,5 +240,5 @@ if (status & I2C_PCF_LRB) { i2c_stop(adap); - printk("i2c-algo-pcf.o: %s i2c_write: " + printk(KERN_ERR "i2c-algo-pcf.o: %s i2c_write: " "error - no ack.\n", i2c_adap->name); return -EREMOTEIO; /* got a better one ?? */ @@ -270,5 +268,5 @@ if (wait_for_pin(adap, &status)) { i2c_stop(adap); - printk("i2c-algo-pcf.o: pcf_readbytes timed out.\n"); + printk(KERN_ERR "i2c-algo-pcf.o: pcf_readbytes timed out.\n"); return (-1); } @@ -277,5 +275,5 @@ if ((status & I2C_PCF_LRB) && (i != count)) { i2c_stop(adap); - printk("i2c-algo-pcf.o: i2c_read: i2c_inb, No ack.\n"); + printk(KERN_ERR "i2c-algo-pcf.o: i2c_read: i2c_inb, No ack.\n"); return (-1); } @@ -313,9 +311,9 @@ /* a ten bit address */ addr = 0xf0 | (( msg->addr >> 7) & 0x03); - DEB2(printk("addr0: %d\n",addr)); + DEB2(printk(KERN_DEBUG "addr0: %d\n",addr)); /* try extended address code...*/ ret = try_address(adap, addr, retries); if (ret!=1) { - printk("died at extended address code.\n"); + printk(KERN_ERR "died at extended address code.\n"); return -EREMOTEIO; } @@ -324,5 +322,5 @@ /* Status check comes here */ if (ret != 1) { - printk("died at 2nd address code.\n"); + printk(KERN_ERR "died at 2nd address code.\n"); return -EREMOTEIO; } @@ -333,5 +331,5 @@ ret = try_address(adap, addr, retries); if (ret!=1) { - printk("died at extended address code.\n"); + printk(KERN_ERR "died at extended address code.\n"); return -EREMOTEIO; } @@ -361,5 +359,5 @@ timeout = wait_for_bb(adap); if (timeout) { - DEB2(printk("i2c-algo-pcf.o: " + DEB2(printk(KERN_ERR "i2c-algo-pcf.o: " "Timeout waiting for BB in pcf_xfer\n");) return -EIO; @@ -369,5 +367,5 @@ pmsg = &msgs[i]; - DEB2(printk("i2c-algo-pcf.o: Doing %s %d bytes to 0x%02x - %d of %d messages\n", + DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: Doing %s %d bytes to 0x%02x - %d of %d messages\n", pmsg->flags & I2C_M_RD ? "read" : "write", pmsg->len, pmsg->addr, i + 1, num);) @@ -384,5 +382,5 @@ if (timeout) { i2c_stop(adap); - DEB2(printk("i2c-algo-pcf.o: Timeout waiting " + DEB2(printk(KERN_ERR "i2c-algo-pcf.o: Timeout waiting " "for PIN(1) in pcf_xfer\n");) return (-EREMOTEIO); @@ -393,10 +391,10 @@ if (status & I2C_PCF_LRB) { i2c_stop(adap); - DEB2(printk("i2c-algo-pcf.o: No LRB(1) in pcf_xfer\n");) + DEB2(printk(KERN_ERR "i2c-algo-pcf.o: No LRB(1) in pcf_xfer\n");) return (-EREMOTEIO); } #endif - DEB3(printk("i2c-algo-pcf.o: Msg %d, addr=0x%x, flags=0x%x, len=%d\n", + DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: Msg %d, addr=0x%x, flags=0x%x, len=%d\n", i, msgs[i].addr, msgs[i].flags, msgs[i].len);) @@ -408,8 +406,8 @@ if (ret != pmsg->len) { - DEB2(printk("i2c-algo-pcf.o: fail: " + DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: fail: " "only read %d bytes.\n",ret)); } else { - DEB2(printk("i2c-algo-pcf.o: read %d bytes.\n",ret)); + DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: read %d bytes.\n",ret)); } } else { /* Write */ @@ -418,8 +416,8 @@ if (ret != pmsg->len) { - DEB2(printk("i2c-algo-pcf.o: fail: " + DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: fail: " "only wrote %d bytes.\n",ret)); } else { - DEB2(printk("i2c-algo-pcf.o: wrote %d bytes.\n",ret)); + DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: wrote %d bytes.\n",ret)); } } @@ -462,5 +460,5 @@ struct i2c_algo_pcf_data *pcf_adap = adap->algo_data; - DEB2(printk("i2c-algo-pcf.o: hw routines for %s registered.\n", + DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: hw routines for %s registered.\n", adap->name)); @@ -515,5 +513,5 @@ if ((res = i2c_del_adapter(adap)) < 0) return res; - DEB2(printk("i2c-algo-pcf.o: adapter unregistered: %s\n",adap->name)); + DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: adapter unregistered: %s\n",adap->name)); #ifdef MODULE @@ -525,5 +523,5 @@ int __init i2c_algo_pcf_init (void) { - printk("i2c-algo-pcf.o: i2c pcf8584 algorithm module\n"); + printk(KERN_INFO "i2c-algo-pcf.o: i2c pcf8584 algorithm module version %s (%s)\n", I2C_VERSION, I2C_DATE); return 0; } @@ -536,5 +534,7 @@ MODULE_AUTHOR("Hans Berglund "); MODULE_DESCRIPTION("I2C-Bus PCF8584 algorithm"); +#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); +#endif MODULE_PARM(pcf_scan, "i"); --- linux-old/include/linux/i2c-algo-pcf.h Thu Dec 19 16:26:39 CET 2002 +++ linux/include/linux/i2c-algo-pcf.h Thu Dec 19 16:26:39 CET 2002 --- linux-old/drivers/i2c/i2c-core.c Thu Dec 19 16:26:39 CET 2002 +++ linux/drivers/i2c/i2c-core.c Thu Dec 19 16:26:39 CET 2002 @@ -19,7 +19,8 @@ /* With some changes from Kyösti Mälkki . - All SMBus-related things are written by Frodo Looijaard */ + All SMBus-related things are written by Frodo Looijaard + SMBus 2.0 support by Mark Studebaker */ -/* $Id: i2c-core.c,v 1.64 2001/08/13 01:35:56 mds Exp $ */ +/* $Id: i2c-core.c,v 1.90 2002/11/23 20:58:13 mds Exp $ */ #include @@ -29,5 +30,4 @@ #include #include - #include @@ -37,5 +37,5 @@ #include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) #define init_MUTEX(s) do { *(s) = MUTEX; } while(0) #endif @@ -73,5 +73,5 @@ /**** debug level */ -static int i2c_debug=1; +static int i2c_debug; /* --------------------------------------------------- @@ -97,5 +97,5 @@ implementation of the read hook */ static struct file_operations i2cproc_operations = { - read: i2cproc_bus_read, + .read = i2cproc_bus_read, }; @@ -159,5 +159,5 @@ proc_entry = create_proc_entry(name,0,proc_bus); if (! proc_entry) { - printk("i2c-core.o: Could not create /proc/bus/%s\n", + printk(KERN_ERR "i2c-core.o: Could not create /proc/bus/%s\n", name); res = -ENOENT; @@ -189,5 +189,5 @@ DRV_UNLOCK(); - DEB(printk("i2c-core.o: adapter %s registered as adapter %d.\n", + DEB(printk(KERN_DEBUG "i2c-core.o: adapter %s registered as adapter %d.\n", adap->name,i)); @@ -215,5 +215,5 @@ break; if (I2C_ADAP_MAX == i) { - printk( "i2c-core.o: unregister_adapter adap [%s] not found.\n", + printk( KERN_WARNING "i2c-core.o: unregister_adapter adap [%s] not found.\n", adap->name); res = -ENODEV; @@ -230,5 +230,5 @@ if (drivers[j] && (drivers[j]->flags & I2C_DF_DUMMY)) if ((res = drivers[j]->attach_adapter(adap))) { - printk("i2c-core.o: can't detach adapter %s " + printk(KERN_WARNING "i2c-core.o: can't detach adapter %s " "while detaching driver %s: driver not " "detached!",adap->name,drivers[j]->name); @@ -248,5 +248,5 @@ */ if ((res=client->driver->detach_client(client))) { - printk("i2c-core.o: adapter %s not " + printk(KERN_ERR "i2c-core.o: adapter %s not " "unregistered, because client at " "address %02x can't be detached. ", @@ -267,5 +267,5 @@ ADAP_UNLOCK(); - DEB(printk("i2c-core.o: adapter unregistered: %s\n",adap->name)); + DEB(printk(KERN_DEBUG "i2c-core.o: adapter unregistered: %s\n",adap->name)); return 0; @@ -306,5 +306,5 @@ DRV_UNLOCK(); /* driver was successfully added */ - DEB(printk("i2c-core.o: driver %s registered.\n",driver->name)); + DEB(printk(KERN_DEBUG "i2c-core.o: driver %s registered.\n",driver->name)); ADAP_LOCK(); @@ -341,5 +341,5 @@ * afterwards. */ - DEB2(printk("i2c-core.o: unregister_driver - looking for clients.\n")); + DEB2(printk(KERN_DEBUG "i2c-core.o: unregister_driver - looking for clients.\n")); /* removing clients does not depend on the notify flag, else * invalid operation might (will!) result, when using stale client @@ -351,5 +351,5 @@ if (adap == NULL) /* skip empty entries. */ continue; - DEB2(printk("i2c-core.o: examining adapter %s:\n", + DEB2(printk(KERN_DEBUG "i2c-core.o: examining adapter %s:\n", adap->name)); if (driver->flags & I2C_DF_DUMMY) { @@ -360,5 +360,5 @@ */ if ((res = driver->attach_adapter(adap))) { - printk("i2c-core.o: while unregistering " + printk(KERN_WARNING "i2c-core.o: while unregistering " "dummy driver %s, adapter %s could " "not be detached properly; driver " @@ -373,5 +373,5 @@ if (client != NULL && client->driver == driver) { - DEB2(printk("i2c-core.o: " + DEB2(printk(KERN_DEBUG "i2c-core.o: " "detaching client %s:\n", client->name)); @@ -379,11 +379,9 @@ detach_client(client))) { - printk("i2c-core.o: while " + printk(KERN_ERR "i2c-core.o: while " "unregistering driver " "`%s', the client at " - "address %02x of " - "adapter `%s' could not" - "be detached; driver" - "not unloaded!", + "address %02x of adapter `%s' could not be " + "detached; driver not unloaded!", driver->name, client->addr, @@ -401,5 +399,5 @@ DRV_UNLOCK(); - DEB(printk("i2c-core.o: driver unregistered: %s\n",driver->name)); + DEB(printk(KERN_DEBUG "i2c-core.o: driver unregistered: %s\n",driver->name)); return 0; } @@ -437,8 +435,8 @@ if (adapter->client_register) if (adapter->client_register(client)) - printk("i2c-core.o: warning: client_register seems " + printk(KERN_DEBUG "i2c-core.o: warning: client_register seems " "to have failed for client %02x at adapter %s\n", client->addr,adapter->name); - DEB(printk("i2c-core.o: client [%s] registered to adapter [%s](pos. %d).\n", + DEB(printk(KERN_DEBUG "i2c-core.o: client [%s] registered to adapter [%s](pos. %d).\n", client->name, adapter->name,i)); @@ -471,5 +469,5 @@ if (adapter->client_unregister != NULL) if ((res = adapter->client_unregister(client))) { - printk("i2c-core.o: client_unregister [%s] failed, " + printk(KERN_ERR "i2c-core.o: client_unregister [%s] failed, " "client not detached",client->name); return res; @@ -479,5 +477,5 @@ adapter->client_count--; - DEB(printk("i2c-core.o: client [%s] unregistered.\n",client->name)); + DEB(printk(KERN_DEBUG "i2c-core.o: client [%s] unregistered.\n",client->name)); return 0; } @@ -660,16 +658,17 @@ size_t len_total; int order[I2C_CLIENT_MAX]; +#define OUTPUT_LENGTH_PER_LINE 70 - if (count > 4000) - return -EINVAL; len_total = file->f_pos + count; - /* Too bad if this gets longer (unlikely) */ - if (len_total > 4000) - len_total = 4000; + if (len_total > (I2C_CLIENT_MAX * OUTPUT_LENGTH_PER_LINE) ) + /* adjust to maximum file size */ + len_total = (I2C_CLIENT_MAX * OUTPUT_LENGTH_PER_LINE); for (i = 0; i < I2C_ADAP_MAX; i++) if (adapters[i]->inode == inode->i_ino) { /* We need a bit of slack in the kernel buffer; this makes the sprintf safe. */ - if (! (kbuf = kmalloc(count + 80,GFP_KERNEL))) + if (! (kbuf = kmalloc(len_total + + OUTPUT_LENGTH_PER_LINE, + GFP_KERNEL))) return -ENOMEM; /* Order will hold the indexes of the clients @@ -722,5 +721,5 @@ if (! proc_bus) { - printk("i2c-core.o: /proc/bus/ does not exist"); + printk(KERN_ERR "i2c-core.o: /proc/bus/ does not exist"); i2cproc_cleanup(); return -ENOENT; @@ -728,5 +727,5 @@ proc_bus_i2c = create_proc_entry("i2c",0,proc_bus); if (!proc_bus_i2c) { - printk("i2c-core.o: Could not create /proc/bus/i2c"); + printk(KERN_ERR "i2c-core.o: Could not create /proc/bus/i2c"); i2cproc_cleanup(); return -ENOENT; @@ -765,5 +764,5 @@ if (adap->algo->master_xfer) { - DEB2(printk("i2c-core.o: master_xfer: %s with %d msgs.\n", + DEB2(printk(KERN_DEBUG "i2c-core.o: master_xfer: %s with %d msgs.\n", adap->name,num)); @@ -774,5 +773,5 @@ return ret; } else { - printk("i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n", + printk(KERN_ERR "i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n", adap->id); return -ENOSYS; @@ -792,5 +791,5 @@ (const char *)msg.buf = buf; - DEB2(printk("i2c-core.o: master_send: writing %d bytes on %s.\n", + DEB2(printk(KERN_DEBUG "i2c-core.o: master_send: writing %d bytes on %s.\n", count,client->adapter->name)); @@ -804,5 +803,5 @@ return (ret == 1 )? count : ret; } else { - printk("i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n", + printk(KERN_ERR "i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n", client->adapter->id); return -ENOSYS; @@ -822,5 +821,5 @@ msg.buf = buf; - DEB2(printk("i2c-core.o: master_recv: reading %d bytes on %s.\n", + DEB2(printk(KERN_DEBUG "i2c-core.o: master_recv: reading %d bytes on %s.\n", count,client->adapter->name)); @@ -829,5 +828,5 @@ I2C_UNLOCK(adap); - DEB2(printk("i2c-core.o: master_recv: return:%d (count:%d, addr:0x%02x)\n", + DEB2(printk(KERN_DEBUG "i2c-core.o: master_recv: return:%d (count:%d, addr:0x%02x)\n", ret, count, client->addr)); @@ -837,5 +836,5 @@ return (ret == 1 )? count : ret; } else { - printk("i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n", + printk(KERN_DEBUG "i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n", client->adapter->id); return -ENOSYS; @@ -850,5 +849,5 @@ struct i2c_adapter *adap = client->adapter; - DEB2(printk("i2c-core.o: i2c ioctl, cmd: 0x%x, arg: %#lx\n", cmd, arg)); + DEB2(printk(KERN_DEBUG "i2c-core.o: i2c ioctl, cmd: 0x%x, arg: %#lx\n", cmd, arg)); switch ( cmd ) { case I2C_RETRIES: @@ -895,5 +894,5 @@ (address_data->force[i] == ANY_I2C_BUS)) && (addr == address_data->force[i+1])) { - DEB2(printk("i2c-core.o: found force parameter for adapter %d, addr %04x\n", + DEB2(printk(KERN_DEBUG "i2c-core.o: found force parameter for adapter %d, addr %04x\n", adap_id,addr)); if ((err = found_proc(adapter,addr,0,0))) @@ -913,5 +912,5 @@ ((address_data->ignore[i] == ANY_I2C_BUS))) && (addr == address_data->ignore[i+1])) { - DEB2(printk("i2c-core.o: found ignore parameter for adapter %d, " + DEB2(printk(KERN_DEBUG "i2c-core.o: found ignore parameter for adapter %d, " "addr %04x\n", adap_id ,addr)); found = 1; @@ -925,5 +924,5 @@ (addr >= address_data->ignore_range[i+1]) && (addr <= address_data->ignore_range[i+2])) { - DEB2(printk("i2c-core.o: found ignore_range parameter for adapter %d, " + DEB2(printk(KERN_DEBUG "i2c-core.o: found ignore_range parameter for adapter %d, " "addr %04x\n", adap_id,addr)); found = 1; @@ -940,5 +939,5 @@ if (addr == address_data->normal_i2c[i]) { found = 1; - DEB2(printk("i2c-core.o: found normal i2c entry for adapter %d, " + DEB2(printk(KERN_DEBUG "i2c-core.o: found normal i2c entry for adapter %d, " "addr %02x", adap_id,addr)); } @@ -951,5 +950,5 @@ (addr <= address_data->normal_i2c_range[i+1])) { found = 1; - DEB2(printk("i2c-core.o: found normal i2c_range entry for adapter %d, " + DEB2(printk(KERN_DEBUG "i2c-core.o: found normal i2c_range entry for adapter %d, " "addr %04x\n", adap_id,addr)); } @@ -963,5 +962,5 @@ (addr == address_data->probe[i+1])) { found = 1; - DEB2(printk("i2c-core.o: found probe parameter for adapter %d, " + DEB2(printk(KERN_DEBUG "i2c-core.o: found probe parameter for adapter %d, " "addr %04x\n", adap_id,addr)); } @@ -975,5 +974,5 @@ (addr <= address_data->probe_range[i+2])) { found = 1; - DEB2(printk("i2c-core.o: found probe_range parameter for adapter %d, " + DEB2(printk(KERN_DEBUG "i2c-core.o: found probe_range parameter for adapter %d, " "addr %04x\n", adap_id,addr)); } @@ -1005,4 +1004,121 @@ /* The SMBus parts */ +#define POLY (0x1070U << 3) +static u8 +crc8(u16 data) +{ + int i; + + for(i = 0; i < 8; i++) { + if (data & 0x8000) + data = data ^ POLY; + data = data << 1; + } + return (u8)(data >> 8); +} + +/* CRC over count bytes in the first array plus the bytes in the rest + array if it is non-null. rest[0] is the (length of rest) - 1 + and is included. */ +u8 i2c_smbus_partial_pec(u8 crc, int count, u8 *first, u8 *rest) +{ + int i; + + for(i = 0; i < count; i++) + crc = crc8((crc ^ first[i]) << 8); + if(rest != NULL) + for(i = 0; i <= rest[0]; i++) + crc = crc8((crc ^ rest[i]) << 8); + return crc; +} + +u8 i2c_smbus_pec(int count, u8 *first, u8 *rest) +{ + return i2c_smbus_partial_pec(0, count, first, rest); +} + +/* Returns new "size" (transaction type) + Note that we convert byte to byte_data and byte_data to word_data + rather than invent new xxx_PEC transactions. */ +int i2c_smbus_add_pec(u16 addr, u8 command, int size, + union i2c_smbus_data *data) +{ + u8 buf[3]; + + buf[0] = addr << 1; + buf[1] = command; + switch(size) { + case I2C_SMBUS_BYTE: + data->byte = i2c_smbus_pec(2, buf, NULL); + size = I2C_SMBUS_BYTE_DATA; + break; + case I2C_SMBUS_BYTE_DATA: + buf[2] = data->byte; + data->word = buf[2] || + (i2c_smbus_pec(3, buf, NULL) << 8); + size = I2C_SMBUS_WORD_DATA; + break; + case I2C_SMBUS_WORD_DATA: + /* unsupported */ + break; + case I2C_SMBUS_BLOCK_DATA: + data->block[data->block[0] + 1] = + i2c_smbus_pec(2, buf, data->block); + size = I2C_SMBUS_BLOCK_DATA_PEC; + break; + } + return size; +} + +int i2c_smbus_check_pec(u16 addr, u8 command, int size, u8 partial, + union i2c_smbus_data *data) +{ + u8 buf[3], rpec, cpec; + + buf[1] = command; + switch(size) { + case I2C_SMBUS_BYTE_DATA: + buf[0] = (addr << 1) | 1; + cpec = i2c_smbus_pec(2, buf, NULL); + rpec = data->byte; + break; + case I2C_SMBUS_WORD_DATA: + buf[0] = (addr << 1) | 1; + buf[2] = data->word & 0xff; + cpec = i2c_smbus_pec(3, buf, NULL); + rpec = data->word >> 8; + break; + case I2C_SMBUS_WORD_DATA_PEC: + /* unsupported */ + cpec = rpec = 0; + break; + case I2C_SMBUS_PROC_CALL_PEC: + /* unsupported */ + cpec = rpec = 0; + break; + case I2C_SMBUS_BLOCK_DATA_PEC: + buf[0] = (addr << 1); + buf[2] = (addr << 1) | 1; + cpec = i2c_smbus_pec(3, buf, data->block); + rpec = data->block[data->block[0] + 1]; + break; + case I2C_SMBUS_BLOCK_PROC_CALL_PEC: + buf[0] = (addr << 1) | 1; + rpec = i2c_smbus_partial_pec(partial, 1, + buf, data->block); + cpec = data->block[data->block[0] + 1]; + break; + default: + cpec = rpec = 0; + break; + } + if(rpec != cpec) { + DEB(printk(KERN_DEBUG "i2c-core.o: Bad PEC 0x%02x vs. 0x%02x\n", + rpec, cpec)); + return -1; + } + return 0; +} + extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value) { @@ -1023,6 +1139,7 @@ extern s32 i2c_smbus_write_byte(struct i2c_client * client, u8 value) { + union i2c_smbus_data data; /* only for PEC */ return i2c_smbus_xfer(client->adapter,client->addr,client->flags, - I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,NULL); + I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,&data); } @@ -1102,6 +1219,6 @@ union i2c_smbus_data data; int i; - if (length > 32) - length = 32; + if (length > I2C_SMBUS_BLOCK_MAX) + length = I2C_SMBUS_BLOCK_MAX; for (i = 1; i <= length; i++) data.block[i] = values[i-1]; @@ -1112,4 +1229,41 @@ } +/* Returns the number of read bytes */ +extern s32 i2c_smbus_block_process_call(struct i2c_client * client, + u8 command, u8 length, u8 *values) +{ + union i2c_smbus_data data; + int i; + if (length > I2C_SMBUS_BLOCK_MAX - 1) + return -1; + data.block[0] = length; + for (i = 1; i <= length; i++) + data.block[i] = values[i-1]; + if(i2c_smbus_xfer(client->adapter,client->addr,client->flags, + I2C_SMBUS_WRITE, command, + I2C_SMBUS_BLOCK_PROC_CALL, &data)) + return -1; + for (i = 1; i <= data.block[0]; i++) + values[i-1] = data.block[i]; + return data.block[0]; +} + +/* Returns the number of read bytes */ +extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client, + u8 command, u8 *values) +{ + union i2c_smbus_data data; + int i; + if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, + I2C_SMBUS_READ,command, + I2C_SMBUS_I2C_BLOCK_DATA,&data)) + return -1; + else { + for (i = 1; i <= data.block[0]; i++) + values[i-1] = data.block[i]; + return data.block[0]; + } +} + extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client * client, u8 command, u8 length, u8 *values) @@ -1117,6 +1271,6 @@ union i2c_smbus_data data; int i; - if (length > 32) - length = 32; + if (length > I2C_SMBUS_I2C_BLOCK_MAX) + length = I2C_SMBUS_I2C_BLOCK_MAX; for (i = 1; i <= length; i++) data.block[i] = values[i-1]; @@ -1180,4 +1334,5 @@ case I2C_SMBUS_PROC_CALL: num = 2; /* Special case */ + read_write = I2C_SMBUS_READ; msg[0].len = 3; msg[1].len = 2; @@ -1186,22 +1341,45 @@ break; case I2C_SMBUS_BLOCK_DATA: + case I2C_SMBUS_BLOCK_DATA_PEC: if (read_write == I2C_SMBUS_READ) { - printk("i2c-core.o: Block read not supported under " - "I2C emulation!\n"); - return -1; + printk(KERN_ERR "i2c-core.o: Block read not supported " + "under I2C emulation!\n"); + return -1; } else { msg[0].len = data->block[0] + 2; - if (msg[0].len > 34) { - printk("i2c-core.o: smbus_access called with " + if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) { + printk(KERN_ERR "i2c-core.o: smbus_access called with " "invalid block write size (%d)\n", - msg[0].len); + data->block[0]); return -1; } + if(size == I2C_SMBUS_BLOCK_DATA_PEC) + (msg[0].len)++; for (i = 1; i <= msg[0].len; i++) msgbuf0[i] = data->block[i-1]; } break; + case I2C_SMBUS_BLOCK_PROC_CALL: + case I2C_SMBUS_BLOCK_PROC_CALL_PEC: + printk(KERN_ERR "i2c-core.o: Block process call not supported " + "under I2C emulation!\n"); + return -1; + case I2C_SMBUS_I2C_BLOCK_DATA: + if (read_write == I2C_SMBUS_READ) { + msg[1].len = I2C_SMBUS_I2C_BLOCK_MAX; + } else { + msg[0].len = data->block[0] + 1; + if (msg[0].len > I2C_SMBUS_I2C_BLOCK_MAX + 1) { + printk("i2c-core.o: i2c_smbus_xfer_emulated called with " + "invalid block write size (%d)\n", + data->block[0]); + return -1; + } + for (i = 1; i <= data->block[0]; i++) + msgbuf0[i] = data->block[i]; + } + break; default: - printk("i2c-core.o: smbus_access called with invalid size (%d)\n", + printk(KERN_ERR "i2c-core.o: smbus_access called with invalid size (%d)\n", size); return -1; @@ -1223,4 +1401,10 @@ data->word = msgbuf1[0] | (msgbuf1[1] << 8); break; + case I2C_SMBUS_I2C_BLOCK_DATA: + /* fixed at 32 for now */ + data->block[0] = I2C_SMBUS_I2C_BLOCK_MAX; + for (i = 0; i < I2C_SMBUS_I2C_BLOCK_MAX; i++) + data->block[i+1] = msgbuf1[i]; + break; } return 0; @@ -1233,5 +1417,27 @@ { s32 res; - flags = flags & I2C_M_TEN; + int swpec = 0; + u8 partial = 0; + + flags &= I2C_M_TEN | I2C_CLIENT_PEC; + if((flags & I2C_CLIENT_PEC) && + !(i2c_check_functionality(adapter, I2C_FUNC_SMBUS_HWPEC_CALC))) { + swpec = 1; + if(read_write == I2C_SMBUS_READ && + size == I2C_SMBUS_BLOCK_DATA) + size = I2C_SMBUS_BLOCK_DATA_PEC; + else if(size == I2C_SMBUS_PROC_CALL) + size = I2C_SMBUS_PROC_CALL_PEC; + else if(size == I2C_SMBUS_BLOCK_PROC_CALL) { + i2c_smbus_add_pec(addr, command, + I2C_SMBUS_BLOCK_DATA, data); + partial = data->block[data->block[0] + 1]; + size = I2C_SMBUS_BLOCK_PROC_CALL_PEC; + } else if(read_write == I2C_SMBUS_WRITE && + size != I2C_SMBUS_QUICK && + size != I2C_SMBUS_I2C_BLOCK_DATA) + size = i2c_smbus_add_pec(addr, command, size, data); + } + if (adapter->algo->smbus_xfer) { I2C_LOCK(adapter); @@ -1242,4 +1448,12 @@ res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, command,size,data); + + if(res >= 0 && swpec && + size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA && + (read_write == I2C_SMBUS_READ || size == I2C_SMBUS_PROC_CALL_PEC || + size == I2C_SMBUS_BLOCK_PROC_CALL_PEC)) { + if(i2c_smbus_check_pec(addr, command, size, partial, data)) + return -1; + } return res; } @@ -1265,5 +1479,5 @@ static int __init i2c_init(void) { - printk("i2c-core.o: i2c core module\n"); + printk(KERN_INFO "i2c-core.o: i2c core module version %s (%s)\n", I2C_VERSION, I2C_DATE); memset(adapters,0,sizeof(adapters)); memset(drivers,0,sizeof(drivers)); @@ -1279,4 +1493,9 @@ } +static void __exit i2c_exit(void) +{ + i2cproc_cleanup(); +} + #ifndef MODULE #ifdef CONFIG_I2C_CHARDEV @@ -1295,4 +1514,10 @@ extern int i2c_bitvelle_init(void); #endif +#ifdef CONFIG_I2C_PPORT + extern int i2c_bitpport_init(void); +#endif +#ifdef CONFIG_I2C_FRODO + extern int i2c_frodo_init(void); +#endif #ifdef CONFIG_I2C_BITVIA extern int i2c_bitvia_init(void); @@ -1305,4 +1530,7 @@ extern int i2c_pcfisa_init(void); #endif +#ifdef CONFIG_I2C_PCFEPP + extern int i2c_pcfepp_init(void); +#endif #ifdef CONFIG_I2C_ALGO8XX @@ -1312,4 +1540,10 @@ extern int i2c_rpx_init(void); #endif +#ifdef CONFIG_I2C_IBM_OCP_ALGO + extern int i2c_algo_iic_init(void); +#endif +#ifdef CONFIG_I2C_IBM_OCP_ADAP + extern int iic_ibmocp_init(void); +#endif #ifdef CONFIG_I2C_PROC extern int sensors_init(void); @@ -1340,4 +1574,13 @@ i2c_bitvelle_init(); #endif +#ifdef CONFIG_I2C_PPORT + i2c_bitpport_init(); +#endif +#ifdef CONFIG_I2C_FRODO + i2c_frodo_init(); +#endif +#ifdef CONFIG_I2C_BITVIA + i2c_bitvia_init(); +#endif /* --------------------- pcf -------- */ @@ -1348,4 +1591,7 @@ i2c_pcfisa_init(); #endif +#ifdef CONFIG_I2C_PCFEPP + i2c_pcfepp_init(); +#endif /* --------------------- 8xx -------- */ @@ -1356,4 +1602,10 @@ i2c_rpx_init(); #endif +#ifdef CONFIG_I2C_IBM_OCP_ALGO + i2c_algo_iic_init(); +#endif +#ifdef CONFIG_I2C_IBM_OCP_ADAP + iic_ibmocp_init(); +#endif /* -------------- proc interface ---- */ @@ -1403,23 +1655,18 @@ EXPORT_SYMBOL(i2c_smbus_read_block_data); EXPORT_SYMBOL(i2c_smbus_write_block_data); +EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data); +EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data); EXPORT_SYMBOL(i2c_get_functionality); EXPORT_SYMBOL(i2c_check_functionality); -#ifdef MODULE MODULE_AUTHOR("Simon G. Vogl "); MODULE_DESCRIPTION("I2C-Bus main module"); MODULE_PARM(i2c_debug, "i"); MODULE_PARM_DESC(i2c_debug,"debug level"); +#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); - -int init_module(void) -{ - return i2c_init(); -} - -void cleanup_module(void) -{ - i2cproc_cleanup(); -} #endif + +module_init(i2c_init); +module_exit(i2c_exit); --- linux-old/drivers/i2c/i2c-dev.c Thu Dec 19 16:26:40 CET 2002 +++ linux/drivers/i2c/i2c-dev.c Thu Dec 19 16:26:40 CET 2002 @@ -29,5 +29,5 @@ */ -/* $Id: i2c-dev.c,v 1.40 2001/08/25 01:28:01 mds Exp $ */ +/* $Id: i2c-dev.c,v 1.49 2002/11/23 20:58:13 mds Exp $ */ #include @@ -50,13 +50,7 @@ #include #include - #include #include -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* def MODULE */ - /* struct file_operations changed too often in the 2.1 series for nice code */ @@ -80,26 +74,18 @@ void *arg); -#ifdef MODULE -static -#else -extern -#endif - int __init i2c_dev_init(void); -static int i2cdev_cleanup(void); - static struct file_operations i2cdev_fops = { #if LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,4,0) - owner: THIS_MODULE, + .owner = THIS_MODULE, #endif /* LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,4,0) */ #if LINUX_KERNEL_VERSION < KERNEL_VERSION(2,4,9) - llseek: i2cdev_lseek, + .llseek = i2cdev_lseek, #else - llseek: no_llseek, + .llseek = no_llseek, #endif - read: i2cdev_read, - write: i2cdev_write, - ioctl: i2cdev_ioctl, - open: i2cdev_open, - release: i2cdev_release, + .read = i2cdev_read, + .write = i2cdev_write, + .ioctl = i2cdev_ioctl, + .open = i2cdev_open, + .release = i2cdev_release, }; @@ -112,22 +98,17 @@ static struct i2c_driver i2cdev_driver = { - name: "i2c-dev dummy driver", - id: I2C_DRIVERID_I2CDEV, - flags: I2C_DF_DUMMY, - attach_adapter: i2cdev_attach_adapter, - detach_client: i2cdev_detach_client, - command: i2cdev_command, -/* inc_use: NULL, - dec_use: NULL, */ + .name = "i2c-dev dummy driver", + .id = I2C_DRIVERID_I2CDEV, + .flags = I2C_DF_DUMMY, + .attach_adapter = i2cdev_attach_adapter, + .detach_client = i2cdev_detach_client, + .command = i2cdev_command, }; static struct i2c_client i2cdev_client_template = { - name: "I2C /dev entry", - id: 1, - flags: 0, - addr: -1, -/* adapter: NULL, */ - driver: &i2cdev_driver, -/* data: NULL */ + .name = "I2C /dev entry", + .id = 1, + .addr = -1, + .driver = &i2cdev_driver, }; @@ -141,5 +122,5 @@ #ifdef DEBUG struct inode *inode = file->f_dentry->d_inode; - printk("i2c-dev.o: i2c-%d lseek to %ld bytes relative to %d.\n", + printk(KERN_DEBUG "i2c-dev.o: i2c-%d lseek to %ld bytes relative to %d.\n", MINOR(inode->i_rdev),(long) offset,origin); #endif /* DEBUG */ @@ -160,7 +141,7 @@ struct i2c_client *client = (struct i2c_client *)file->private_data; - if(count > 8192) + if (count > 8192) count = 8192; - + /* copy user space data to kernel space. */ tmp = kmalloc(count,GFP_KERNEL); @@ -169,5 +150,5 @@ #ifdef DEBUG - printk("i2c-dev.o: i2c-%d reading %d bytes.\n",MINOR(inode->i_rdev), + printk(KERN_DEBUG "i2c-dev.o: i2c-%d reading %d bytes.\n",MINOR(inode->i_rdev), count); #endif @@ -191,7 +172,7 @@ #endif /* DEBUG */ - if(count > 8192) + if (count > 8192) count = 8192; - + /* copy user space data to kernel space. */ tmp = kmalloc(count,GFP_KERNEL); @@ -204,5 +185,5 @@ #ifdef DEBUG - printk("i2c-dev.o: i2c-%d writing %d bytes.\n",MINOR(inode->i_rdev), + printk(KERN_DEBUG "i2c-dev.o: i2c-%d writing %d bytes.\n",MINOR(inode->i_rdev), count); #endif @@ -224,5 +205,5 @@ #ifdef DEBUG - printk("i2c-dev.o: i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n", + printk(KERN_DEBUG "i2c-dev.o: i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n", MINOR(inode->i_rdev),cmd, arg); #endif /* DEBUG */ @@ -244,4 +225,10 @@ client->flags &= ~I2C_M_TEN; return 0; + case I2C_PEC: + if (arg) + client->flags |= I2C_CLIENT_PEC; + else + client->flags &= ~I2C_CLIENT_PEC; + return 0; case I2C_FUNCS: funcs = i2c_get_functionality(client->adapter); @@ -320,7 +307,8 @@ (data_arg.size != I2C_SMBUS_PROC_CALL) && (data_arg.size != I2C_SMBUS_BLOCK_DATA) && - (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA)) { + (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) && + (data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) { #ifdef DEBUG - printk("i2c-dev.o: size out of range (%x) in ioctl I2C_SMBUS.\n", + printk(KERN_DEBUG "i2c-dev.o: size out of range (%x) in ioctl I2C_SMBUS.\n", data_arg.size); #endif @@ -332,5 +320,5 @@ (data_arg.read_write != I2C_SMBUS_WRITE)) { #ifdef DEBUG - printk("i2c-dev.o: read_write out of range (%x) in ioctl I2C_SMBUS.\n", + printk(KERN_DEBUG "i2c-dev.o: read_write out of range (%x) in ioctl I2C_SMBUS.\n", data_arg.read_write); #endif @@ -352,5 +340,5 @@ if (data_arg.data == NULL) { #ifdef DEBUG - printk("i2c-dev.o: data is NULL pointer in ioctl I2C_SMBUS.\n"); + printk(KERN_DEBUG "i2c-dev.o: data is NULL pointer in ioctl I2C_SMBUS.\n"); #endif return -EINVAL; @@ -363,8 +351,9 @@ (data_arg.size == I2C_SMBUS_PROC_CALL)) datasize = sizeof(data_arg.data->word); - else /* size == I2C_SMBUS_BLOCK_DATA */ + else /* size == smbus block, i2c block, or block proc. call */ datasize = sizeof(data_arg.data->block); if ((data_arg.size == I2C_SMBUS_PROC_CALL) || + (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || (data_arg.read_write == I2C_SMBUS_WRITE)) { if (copy_from_user(&temp, data_arg.data, datasize)) @@ -375,4 +364,5 @@ data_arg.command,data_arg.size,&temp); if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) || + (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || (data_arg.read_write == I2C_SMBUS_READ))) { if (copy_to_user(data_arg.data, &temp, datasize)) @@ -394,5 +384,5 @@ if ((minor >= I2CDEV_ADAPS_MAX) || ! (i2cdev_adaps[minor])) { #ifdef DEBUG - printk("i2c-dev.o: Trying to open unattached adapter i2c-%d\n", + printk(KERN_DEBUG "i2c-dev.o: Trying to open unattached adapter i2c-%d\n", minor); #endif @@ -415,5 +405,5 @@ #ifdef DEBUG - printk("i2c-dev.o: opened i2c-%d\n",minor); + printk(KERN_DEBUG "i2c-dev.o: opened i2c-%d\n",minor); #endif return 0; @@ -426,5 +416,5 @@ file->private_data=NULL; #ifdef DEBUG - printk("i2c-dev.o: Closed: i2c-%d\n", minor); + printk(KERN_DEBUG "i2c-dev.o: Closed: i2c-%d\n", minor); #endif #if LINUX_KERNEL_VERSION < KERNEL_VERSION(2,4,0) @@ -447,9 +437,9 @@ if ((i = i2c_adapter_id(adap)) < 0) { - printk("i2c-dev.o: Unknown adapter ?!?\n"); + printk(KERN_DEBUG "i2c-dev.o: Unknown adapter ?!?\n"); return -ENODEV; } if (i >= I2CDEV_ADAPS_MAX) { - printk("i2c-dev.o: Adapter number too large?!? (%d)\n",i); + printk(KERN_DEBUG "i2c-dev.o: Adapter number too large?!? (%d)\n",i); return -ENODEV; } @@ -464,5 +454,5 @@ &i2cdev_fops, NULL); #endif - printk("i2c-dev.o: Registered '%s' as minor %d\n",adap->name,i); + printk(KERN_DEBUG "i2c-dev.o: Registered '%s' as minor %d\n",adap->name,i); } else { /* This is actually a detach_adapter call! */ @@ -472,5 +462,5 @@ i2cdev_adaps[i] = NULL; #ifdef DEBUG - printk("i2c-dev.o: Adapter unregistered: %s\n",adap->name); + printk(KERN_DEBUG "i2c-dev.o: Adapter unregistered: %s\n",adap->name); #endif } @@ -490,9 +480,33 @@ } +static void i2cdev_cleanup(void) +{ + int res; + + if (i2cdev_initialized >= 2) { + if ((res = i2c_del_driver(&i2cdev_driver))) { + printk(KERN_ERR "i2c-dev.o: Driver deregistration failed, " + "module not removed.\n"); + } + i2cdev_initialized --; + } + + if (i2cdev_initialized >= 1) { +#ifdef CONFIG_DEVFS_FS + devfs_unregister(devfs_handle); +#endif + if ((res = unregister_chrdev(I2C_MAJOR,"i2c"))) { + printk(KERN_ERR "i2c-dev.o: unable to release major %d for i2c bus\n", + I2C_MAJOR); + } + i2cdev_initialized --; + } +} + int __init i2c_dev_init(void) { int res; - printk("i2c-dev.o: i2c /dev entries driver module\n"); + printk(KERN_INFO "i2c-dev.o: i2c /dev entries driver module version %s (%s)\n", I2C_VERSION, I2C_DATE); i2cdev_initialized = 0; @@ -502,5 +516,5 @@ if (register_chrdev(I2C_MAJOR,"i2c",&i2cdev_fops)) { #endif - printk("i2c-dev.o: unable to get major %d for i2c bus\n", + printk(KERN_ERR "i2c-dev.o: unable to get major %d for i2c bus\n", I2C_MAJOR); return -EIO; @@ -512,5 +526,5 @@ if ((res = i2c_add_driver(&i2cdev_driver))) { - printk("i2c-dev.o: Driver registration failed, module not inserted.\n"); + printk(KERN_ERR "i2c-dev.o: Driver registration failed, module not inserted.\n"); i2cdev_cleanup(); return res; @@ -520,51 +534,12 @@ } -int i2cdev_cleanup(void) -{ - int res; - - if (i2cdev_initialized >= 2) { - if ((res = i2c_del_driver(&i2cdev_driver))) { - printk("i2c-dev.o: Driver deregistration failed, " - "module not removed.\n"); - return res; - } - i2cdev_initialized --; - } - - if (i2cdev_initialized >= 1) { -#ifdef CONFIG_DEVFS_FS - devfs_unregister(devfs_handle); - if ((res = devfs_unregister_chrdev(I2C_MAJOR, "i2c"))) { -#else - if ((res = unregister_chrdev(I2C_MAJOR,"i2c"))) { -#endif - printk("i2c-dev.o: unable to release major %d for i2c bus\n", - I2C_MAJOR); - return res; - } - i2cdev_initialized --; - } - return 0; -} - EXPORT_NO_SYMBOLS; -#ifdef MODULE - MODULE_AUTHOR("Frodo Looijaard and Simon G. Vogl "); MODULE_DESCRIPTION("I2C /dev entries driver"); +#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); +#endif -int init_module(void) -{ - return i2c_dev_init(); -} - -int cleanup_module(void) -{ - return i2cdev_cleanup(); -} - -#endif /* def MODULE */ - +module_init(i2c_dev_init); +module_exit(i2cdev_cleanup); --- linux-old/include/linux/i2c-dev.h Thu Dec 19 16:26:40 CET 2002 +++ linux/include/linux/i2c-dev.h Thu Dec 19 16:26:40 CET 2002 @@ -20,5 +20,5 @@ */ -/* $Id: i2c-dev.h,v 1.9 2001/08/15 03:04:58 mds Exp $ */ +/* $Id: i2c-dev.h,v 1.11 2002/07/07 15:42:47 mds Exp $ */ #ifndef I2C_DEV_H @@ -145,5 +145,5 @@ for (i = 1; i <= data.block[0]; i++) values[i-1] = data.block[i]; - return data.block[0]; + return data.block[0]; } } @@ -163,4 +163,20 @@ } +/* Returns the number of read bytes */ +static inline __s32 i2c_smbus_read_i2c_block_data(int file, __u8 command, + __u8 *values) +{ + union i2c_smbus_data data; + int i; + if (i2c_smbus_access(file,I2C_SMBUS_READ,command, + I2C_SMBUS_I2C_BLOCK_DATA,&data)) + return -1; + else { + for (i = 1; i <= data.block[0]; i++) + values[i-1] = data.block[i]; + return data.block[0]; + } +} + static inline __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command, __u8 length, __u8 *values) @@ -175,4 +191,25 @@ return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, I2C_SMBUS_I2C_BLOCK_DATA, &data); +} + +/* Returns the number of read bytes */ +static inline __s32 i2c_smbus_block_process_call(int file, __u8 command, + __u8 length, __u8 *values) +{ + union i2c_smbus_data data; + int i; + if (length > 32) + length = 32; + for (i = 1; i <= length; i++) + data.block[i] = values[i-1]; + data.block[0] = length; + if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command, + I2C_SMBUS_BLOCK_PROC_CALL,&data)) + return -1; + else { + for (i = 1; i <= data.block[0]; i++) + values[i-1] = data.block[i]; + return data.block[0]; + } } --- linux-old/drivers/i2c/i2c-elektor.c Thu Dec 19 16:26:40 CET 2002 +++ linux/drivers/i2c/i2c-elektor.c Thu Dec 19 16:26:40 CET 2002 @@ -33,21 +33,24 @@ #include #include +#include #include -#include -#include - +#include #include #include #include + +#include +#include + #include "i2c-pcf8584.h" #define DEFAULT_BASE 0x330 -static int base = 0; -static int irq = 0; +static int base; +static int irq; static int clock = 0x1c; static int own = 0x55; -static int mmapped = 0; -static int i2c_debug = 0; +static int mmapped; +static int i2c_debug; /* vdovikin: removed static struct i2c_pcf_isa gpi; code - @@ -62,4 +65,5 @@ #endif static int pcf_pending; +spinlock_t irq_driver_lock = SPIN_LOCK_UNLOCKED; /* ----- global defines ----------------------------------------------- */ @@ -75,9 +79,10 @@ int address = ctl ? (base + 1) : base; - if (ctl && irq) { + /* enable irq if any specified for serial operation */ + if (ctl && irq && (val & I2C_PCF_ESO)) { val |= I2C_PCF_ENI; } - DEB3(printk("i2c-elektor.o: Write 0x%X 0x%02X\n", address, val & 255)); + DEB3(printk(KERN_DEBUG "i2c-elektor.o: Write 0x%X 0x%02X\n", address, val & 255)); switch (mmapped) { @@ -100,5 +105,5 @@ int val = mmapped ? readb(address) : inb(address); - DEB3(printk("i2c-elektor.o: Read 0x%X 0x%02X\n", address, val)); + DEB3(printk(KERN_DEBUG "i2c-elektor.o: Read 0x%X 0x%02X\n", address, val)); return (val); @@ -121,10 +126,10 @@ if (irq > 0) { - cli(); + spin_lock_irq(&irq_driver_lock); if (pcf_pending == 0) { interruptible_sleep_on_timeout(&pcf_wait, timeout*HZ ); } else pcf_pending = 0; - sti(); + spin_unlock_irq(&irq_driver_lock); } else { udelay(100); @@ -143,5 +148,5 @@ if (!mmapped) { if (check_region(base, 2) < 0 ) { - printk("i2c-elektor.o: requested I/O region (0x%X:2) is in use.\n", base); + printk(KERN_ERR "i2c-elektor.o: requested I/O region (0x%X:2) is in use.\n", base); return -ENODEV; } else { @@ -151,5 +156,5 @@ if (irq > 0) { if (request_irq(irq, pcf_isa_handler, 0, "PCF8584", 0) < 0) { - printk("i2c-elektor.o: Request irq%d failed\n", irq); + printk(KERN_ERR "i2c-elektor.o: Request irq%d failed\n", irq); irq = 0; } else @@ -160,5 +165,5 @@ -static void __exit pcf_isa_exit(void) +static void pcf_isa_exit(void) { if (irq > 0) { @@ -203,22 +208,22 @@ */ static struct i2c_algo_pcf_data pcf_isa_data = { - NULL, - pcf_isa_setbyte, - pcf_isa_getbyte, - pcf_isa_getown, - pcf_isa_getclock, - pcf_isa_waitforpin, - 10, 10, 100, /* waits, timeout */ + .setpcf = pcf_isa_setbyte, + .getpcf = pcf_isa_getbyte, + .getown = pcf_isa_getown, + .getclock = pcf_isa_getclock, + .waitforpin = pcf_isa_waitforpin, + .udelay = 10, + .mdelay = 10, + .timeout = 100, }; static struct i2c_adapter pcf_isa_ops = { - "PCF8584 ISA adapter", - I2C_HW_P_ELEK, - NULL, - &pcf_isa_data, - pcf_isa_inc_use, - pcf_isa_dec_use, - pcf_isa_reg, - pcf_isa_unreg, + .name = "PCF8584 ISA adapter", + .id = I2C_HW_P_ELEK, + .algo_data = &pcf_isa_data, + .inc_use = pcf_isa_inc_use, + .dec_use = pcf_isa_dec_use, + .client_register = pcf_isa_reg, + .client_unregister = pcf_isa_unreg, }; @@ -239,5 +244,5 @@ if (!pci_read_config_byte(cy693_dev, 0x47, &config)) { - DEB3(printk("i2c-elektor.o: found cy82c693, config register 0x47 = 0x%02x.\n", config)); + DEB3(printk(KERN_DEBUG "i2c-elektor.o: found cy82c693, config register 0x47 = 0x%02x.\n", config)); /* UP2000 board has this register set to 0xe1, @@ -261,5 +266,5 @@ (this can be read from cypress) */ clock = I2C_PCF_CLK | I2C_PCF_TRNS90; - printk("i2c-elektor.o: found API UP2000 like board, will probe PCF8584 later.\n"); + printk(KERN_INFO "i2c-elektor.o: found API UP2000 like board, will probe PCF8584 later.\n"); } } @@ -270,9 +275,9 @@ /* sanity checks for mmapped I/O */ if (mmapped && base < 0xc8000) { - printk("i2c-elektor.o: incorrect base address (0x%0X) specified for mmapped I/O.\n", base); + printk(KERN_ERR "i2c-elektor.o: incorrect base address (0x%0X) specified for mmapped I/O.\n", base); return -ENODEV; } - printk("i2c-elektor.o: i2c pcf8584-isa adapter module\n"); + printk(KERN_INFO "i2c-elektor.o: i2c pcf8584-isa adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE); if (base == 0) { @@ -284,11 +289,13 @@ #endif if (pcf_isa_init() == 0) { - if (i2c_pcf_add_bus(&pcf_isa_ops) < 0) + if (i2c_pcf_add_bus(&pcf_isa_ops) < 0) { + pcf_isa_exit(); return -ENODEV; + } } else { return -ENODEV; } - printk("i2c-elektor.o: found device at %#x.\n", base); + printk(KERN_ERR "i2c-elektor.o: found device at %#x.\n", base); return 0; @@ -301,5 +308,7 @@ MODULE_AUTHOR("Hans Berglund "); MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter"); +#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); +#endif MODULE_PARM(base, "i"); --- linux-old/include/linux/i2c-elektor.h Thu Dec 19 16:26:40 CET 2002 +++ linux/include/linux/i2c-elektor.h Thu Dec 19 16:26:40 CET 2002 --- linux-old/drivers/i2c/i2c-elv.c Thu Dec 19 16:26:40 CET 2002 +++ linux/drivers/i2c/i2c-elv.c Thu Dec 19 16:26:40 CET 2002 @@ -22,5 +22,5 @@ Frodo Looijaard */ -/* $Id: i2c-elv.c,v 1.17 2001/07/29 02:44:25 mds Exp $ */ +/* $Id: i2c-elv.c,v 1.23 2002/11/24 05:44:15 mds Exp $ */ #include @@ -30,7 +30,5 @@ #include #include - #include - #include #include @@ -96,5 +94,5 @@ /* test for ELV adap. */ if (inb(base+1) & 0x80) { /* BUSY should be high */ - DEBINIT(printk("i2c-elv.o: Busy was low.\n")); + DEBINIT(printk(KERN_DEBUG "i2c-elv.o: Busy was low.\n")); return -ENODEV; } else { @@ -103,5 +101,5 @@ if ( !(inb(base+1) && 0x10) ) { outb(0x04,base+2); - DEBINIT(printk("i2c-elv.o: Select was high.\n")); + DEBINIT(printk(KERN_DEBUG "i2c-elv.o: Select was high.\n")); return -ENODEV; } @@ -155,5 +153,5 @@ bit_elv_getsda, bit_elv_getscl, - 80, 80, 100, /* waits, timeout */ + 80, 80, HZ, /* waits, timeout */ }; @@ -171,5 +169,5 @@ int __init i2c_bitelv_init(void) { - printk("i2c-elv.o: i2c ELV parallel port adapter module\n"); + printk(KERN_INFO "i2c-elv.o: i2c ELV parallel port adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE); if (base==0) { /* probe some values */ @@ -191,5 +189,5 @@ } } - printk("i2c-elv.o: found device at %#x.\n",base); + printk(KERN_DEBUG "i2c-elv.o: found device at %#x.\n",base); return 0; } @@ -201,5 +199,7 @@ MODULE_AUTHOR("Simon G. Vogl "); MODULE_DESCRIPTION("I2C-Bus adapter routines for ELV parallel port adapter"); +#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); +#endif --- linux-old/drivers/i2c/i2c-frodo.c Thu Dec 19 16:26:40 CET 2002 +++ linux/drivers/i2c/i2c-frodo.c Thu Dec 19 16:26:40 CET 2002 @@ -0,0 +1,117 @@ + +/* + * linux/drivers/i2c/i2c-frodo.c + * + * Author: Abraham van der Merwe + * + * An I2C adapter driver for the 2d3D, Inc. StrongARM SA-1110 + * Development board (Frodo). + * + * This source code is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +static void frodo_setsda (void *data,int state) +{ + if (state) + FRODO_CPLD_I2C |= FRODO_I2C_SDA_OUT; + else + FRODO_CPLD_I2C &= ~FRODO_I2C_SDA_OUT; +} + +static void frodo_setscl (void *data,int state) +{ + if (state) + FRODO_CPLD_I2C |= FRODO_I2C_SCL_OUT; + else + FRODO_CPLD_I2C &= ~FRODO_I2C_SCL_OUT; +} + +static int frodo_getsda (void *data) +{ + return ((FRODO_CPLD_I2C & FRODO_I2C_SDA_IN) != 0); +} + +static int frodo_getscl (void *data) +{ + return ((FRODO_CPLD_I2C & FRODO_I2C_SCL_IN) != 0); +} + +static struct i2c_algo_bit_data bit_frodo_data = { + .setsda = frodo_setsda, + .setscl = frodo_setscl, + .getsda = frodo_getsda, + .getscl = frodo_getscl, + .udelay = 80, + .mdelay = 80, + .timeout = HZ +}; + +static int frodo_client_register (struct i2c_client *client) +{ + return (0); +} + +static int frodo_client_unregister (struct i2c_client *client) +{ + return (0); +} + +static void frodo_inc_use (struct i2c_adapter *adapter) +{ + MOD_INC_USE_COUNT; +} + +static void frodo_dec_use (struct i2c_adapter *adapter) +{ + MOD_DEC_USE_COUNT; +} + +static struct i2c_adapter frodo_ops = { + .name = "Frodo adapter driver", + .id = I2C_HW_B_FRODO, + .algo_data = &bit_frodo_data, + .inc_use = frodo_inc_use, + .dec_use = frodo_dec_use, + .client_register = frodo_client_register, + .client_unregister = frodo_client_unregister +}; + +int __init i2c_frodo_init (void) +{ + return (i2c_bit_add_bus (&frodo_ops)); +} + +EXPORT_NO_SYMBOLS; + +static void __exit i2c_frodo_exit (void) +{ + i2c_bit_del_bus (&frodo_ops); +} + +MODULE_AUTHOR ("Abraham van der Merwe "); +MODULE_DESCRIPTION ("I2C-Bus adapter routines for Frodo"); + +#ifdef MODULE_LICENSE +MODULE_LICENSE ("GPL"); +#endif /* #ifdef MODULE_LICENSE */ + +EXPORT_NO_SYMBOLS; + +module_init (i2c_frodo_init); +module_exit (i2c_frodo_exit); + --- linux-old/include/linux/i2c-id.h Thu Dec 19 16:26:40 CET 2002 +++ linux/include/linux/i2c-id.h Thu Dec 19 16:26:40 CET 2002 @@ -21,5 +21,5 @@ /* ------------------------------------------------------------------------- */ -/* $Id: i2c-id.h,v 1.35 2001/08/12 17:22:20 mds Exp $ */ +/* $Id: i2c-id.h,v 1.59 2002/11/22 22:04:51 mds Exp $ */ #ifndef I2C_ID_H @@ -91,4 +91,12 @@ #define I2C_DRIVERID_SP5055 44 /* Satellite tuner */ #define I2C_DRIVERID_STV0030 45 /* Multipurpose switch */ +#define I2C_DRIVERID_SAA7108 46 /* video decoder, image scaler */ +#define I2C_DRIVERID_DS1307 47 /* DS1307 real time clock */ +#define I2C_DRIVERID_ADV717x 48 /* ADV 7175/7176 video encoder */ +#define I2C_DRIVERID_ZR36067 49 /* Zoran 36067 video encoder */ +#define I2C_DRIVERID_ZR36120 50 /* Zoran 36120 video encoder */ +#define I2C_DRIVERID_24LC32A 51 /* Microchip 24LC32A 32k EEPROM */ + + #define I2C_DRIVERID_EXP0 0xF0 /* experimental use id's */ @@ -99,4 +107,6 @@ #define I2C_DRIVERID_I2CDEV 900 #define I2C_DRIVERID_I2CPROC 901 +#define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */ +#define I2C_DRIVERID_ALERT 903 /* SMBus Alert Responder Client */ /* IDs -- Use DRIVERIDs 1000-1999 for sensors. @@ -128,4 +138,14 @@ #define I2C_DRIVERID_IT87 1026 #define I2C_DRIVERID_CH700X 1027 /* single driver for CH7003-7009 digital pc to tv encoders */ +#define I2C_DRIVERID_FSCPOS 1028 +#define I2C_DRIVERID_FSCSCY 1029 +#define I2C_DRIVERID_PCF8591 1030 +#define I2C_DRIVERID_SMSC47M1 1031 +#define I2C_DRIVERID_VT1211 1032 +#define I2C_DRIVERID_LM92 1033 +#define I2C_DRIVERID_VT8231 1034 +#define I2C_DRIVERID_SMARTBATT 1035 +#define I2C_DRIVERID_BMCSENSORS 1036 +#define I2C_DRIVERID_FS451 1037 /* @@ -144,8 +164,13 @@ #define I2C_ALGO_SAA7146 0x060000 /* SAA 7146 video decoder bus */ #define I2C_ALGO_ACB 0x070000 /* ACCESS.bus algorithm */ - +#define I2C_ALGO_IIC 0x080000 /* ITE IIC bus */ +#define I2C_ALGO_SAA7134 0x090000 +#define I2C_ALGO_MPC824X 0x0a0000 /* Motorola 8240 / 8245 */ +#define I2C_ALGO_IPMI 0x0b0000 /* IPMI dummy adapter */ +#define I2C_ALGO_IPMB 0x0c0000 /* IPMB adapter */ #define I2C_ALGO_EC 0x100000 /* ACPI embedded controller */ #define I2C_ALGO_MPC8XX 0x110000 /* MPC8xx PowerPC I2C algorithm */ +#define I2C_ALGO_OCP 0x120000 /* IBM or otherwise On-chip I2C algorithm */ #define I2C_ALGO_EXP 0x800000 /* experimental */ @@ -175,7 +200,10 @@ #define I2C_HW_B_VOO 0x0b /* 3dfx Voodoo 3 / Banshee */ #define I2C_HW_B_PPORT 0x0c /* Primitive parallel port adapter */ +#define I2C_HW_B_SAVG 0x0d /* Savage 4 */ +#define I2C_HW_B_SCX200 0x0e /* Nat'l Semi SCx200 I2C */ #define I2C_HW_B_RIVA 0x10 /* Riva based graphics cards */ #define I2C_HW_B_IOC 0x11 /* IOC bit-wiggling */ #define I2C_HW_B_TSUNA 0x12 /* DEC Tsunami chipset */ +#define I2C_HW_B_FRODO 0x13 /* 2d3D, Inc. SA-1110 Development Board */ /* --- PCF 8584 based algorithms */ @@ -187,7 +215,17 @@ #define I2C_HW_ACPI_EC 0x00 +/* --- MPC824x PowerPC adapters */ +#define I2C_HW_MPC824X 0x00 /* Motorola 8240 / 8245 */ + /* --- MPC8xx PowerPC adapters */ #define I2C_HW_MPC8XX_EPON 0x00 /* Eponymous MPC8xx I2C adapter */ +/* --- ITE based algorithms */ +#define I2C_HW_I_IIC 0x00 /* controller on the ITE */ + +/* --- PowerPC on-chip adapters */ +#define I2C_HW_OCP 0x00 /* IBM on-chip I2C adapter */ + + /* --- SMBus only adapters */ #define I2C_HW_SMBUS_PIIX4 0x00 @@ -199,7 +237,17 @@ #define I2C_HW_SMBUS_SIS5595 0x06 #define I2C_HW_SMBUS_ALI1535 0x07 +#define I2C_HW_SMBUS_SIS630 0x08 +#define I2C_HW_SMBUS_SIS645 0x09 +#define I2C_HW_SMBUS_AMD8111 0x0a +#define I2C_HW_SMBUS_SCX200 0x0b /* --- ISA pseudo-adapter */ #define I2C_HW_ISA 0x00 + +/* --- IPMI pseudo-adapter */ +#define I2C_HW_IPMI 0x00 + +/* --- IPMB adapter */ +#define I2C_HW_IPMB 0x00 #endif /* I2C_ID_H */ --- linux-old/drivers/i2c/i2c-pcf-epp.c Thu Dec 19 16:26:40 CET 2002 +++ linux/drivers/i2c/i2c-pcf-epp.c Thu Dec 19 16:26:40 CET 2002 @@ -0,0 +1,316 @@ +/* ------------------------------------------------------------------------- */ +/* i2c-pcf-epp.c i2c-hw access for PCF8584 style EPP parallel port adapters */ +/* ------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "i2c-pcf8584.h" + +struct i2c_pcf_epp { + int pe_base; + int pe_irq; + int pe_clock; + int pe_own; +} ; + +#define DEFAULT_BASE 0x378 +#define DEFAULT_IRQ 7 +#define DEFAULT_CLOCK 0x1c +#define DEFAULT_OWN 0x55 + +static int base = 0; +static int irq = 0; +static int clock = 0; +static int own = 0; +static int i2c_debug=0; +static struct i2c_pcf_epp gpe; +#if (LINUX_VERSION_CODE < 0x020301) +static struct wait_queue *pcf_wait = NULL; +#else +static wait_queue_head_t pcf_wait; +#endif +static int pcf_pending; +spinlock_t irq_driver_lock = SPIN_LOCK_UNLOCKED; + +/* ----- global defines ----------------------------------------------- */ +#define DEB(x) if (i2c_debug>=1) x +#define DEB2(x) if (i2c_debug>=2) x +#define DEB3(x) if (i2c_debug>=3) x +#define DEBE(x) x /* error messages */ + +/* --- Convenience defines for the EPP/SPP port: */ +#define BASE ((struct i2c_pcf_epp *)(data))->pe_base +// #define DATA BASE /* SPP data port */ +#define STAT (BASE+1) /* SPP status port */ +#define CTRL (BASE+2) /* SPP control port */ +#define EADD (BASE+3) /* EPP address port */ +#define EDAT (BASE+4) /* EPP data port */ + +/* ----- local functions ---------------------------------------------- */ + +static void pcf_epp_setbyte(void *data, int ctl, int val) +{ + if (ctl) { + if (gpe.pe_irq > 0) { + DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: Write control 0x%x\n", + val|I2C_PCF_ENI)); + // set A0 pin HIGH + outb(inb(CTRL) | PARPORT_CONTROL_INIT, CTRL); + // DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: CTRL port = 0x%x\n", inb(CTRL))); + // DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: STAT port = 0x%x\n", inb(STAT))); + + // EPP write data cycle + outb(val | I2C_PCF_ENI, EDAT); + } else { + DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: Write control 0x%x\n", val)); + // set A0 pin HIGH + outb(inb(CTRL) | PARPORT_CONTROL_INIT, CTRL); + outb(val, CTRL); + } + } else { + DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: Write data 0x%x\n", val)); + // set A0 pin LO + outb(inb(CTRL) & ~PARPORT_CONTROL_INIT, CTRL); + // DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: CTRL port = 0x%x\n", inb(CTRL))); + // DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: STAT port = 0x%x\n", inb(STAT))); + outb(val, EDAT); + } +} + +static int pcf_epp_getbyte(void *data, int ctl) +{ + int val; + + if (ctl) { + // set A0 pin HIGH + outb(inb(CTRL) | PARPORT_CONTROL_INIT, CTRL); + val = inb(EDAT); + DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: Read control 0x%x\n", val)); + } else { + // set A0 pin LOW + outb(inb(CTRL) & ~PARPORT_CONTROL_INIT, CTRL); + val = inb(EDAT); + DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: Read data 0x%x\n", val)); + } + return (val); +} + +static int pcf_epp_getown(void *data) +{ + return (gpe.pe_own); +} + + +static int pcf_epp_getclock(void *data) +{ + return (gpe.pe_clock); +} + +#if 0 +static void pcf_epp_sleep(unsigned long timeout) +{ + schedule_timeout( timeout * HZ); +} +#endif + +static void pcf_epp_waitforpin(void) { + int timeout = 10; + + if (gpe.pe_irq > 0) { + spin_lock_irq(&irq_driver_lock); + if (pcf_pending == 0) { + interruptible_sleep_on_timeout(&pcf_wait, timeout*HZ); + //udelay(100); + } else { + pcf_pending = 0; + } + spin_unlock_irq(&irq_driver_lock); + } else { + udelay(100); + } +} + +static void pcf_epp_handler(int this_irq, void *dev_id, struct pt_regs *regs) { + pcf_pending = 1; + wake_up_interruptible(&pcf_wait); + DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: in interrupt handler.\n")); +} + + +static int pcf_epp_init(void *data) +{ + if (check_region(gpe.pe_base, 5) < 0 ) { + + printk(KERN_WARNING "Could not request port region with base 0x%x\n", gpe.pe_base); + return -ENODEV; + } else { + request_region(gpe.pe_base, 5, "i2c (EPP parallel port adapter)"); + } + + DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: init status port = 0x%x\n", inb(0x379))); + + if (gpe.pe_irq > 0) { + if (request_irq(gpe.pe_irq, pcf_epp_handler, 0, "PCF8584", 0) < 0) { + printk(KERN_NOTICE "i2c-pcf-epp.o: Request irq%d failed\n", gpe.pe_irq); + gpe.pe_irq = 0; + } else + disable_irq(gpe.pe_irq); + enable_irq(gpe.pe_irq); + } + // EPP mode initialize + // enable interrupt from nINTR pin + outb(inb(CTRL)|0x14, CTRL); + // clear ERROR bit of STAT + outb(inb(STAT)|0x01, STAT); + outb(inb(STAT)&~0x01,STAT); + + return 0; +} + + +static void __exit pcf_epp_exit(void) +{ + if (gpe.pe_irq > 0) { + disable_irq(gpe.pe_irq); + free_irq(gpe.pe_irq, 0); + } + release_region(gpe.pe_base , 5); +} + + +static int pcf_epp_reg(struct i2c_client *client) +{ + return 0; +} + + +static int pcf_epp_unreg(struct i2c_client *client) +{ + return 0; +} + +static void pcf_epp_inc_use(struct i2c_adapter *adap) +{ +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif +} + +static void pcf_epp_dec_use(struct i2c_adapter *adap) +{ +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif +} + + +/* ------------------------------------------------------------------------ + * Encapsulate the above functions in the correct operations structure. + * This is only done when more than one hardware adapter is supported. + */ +static struct i2c_algo_pcf_data pcf_epp_data = { + NULL, + pcf_epp_setbyte, + pcf_epp_getbyte, + pcf_epp_getown, + pcf_epp_getclock, + pcf_epp_waitforpin, + 80, 80, 100, /* waits, timeout */ +}; + +static struct i2c_adapter pcf_epp_ops = { + "PCF8584 EPP adapter", + I2C_HW_P_LP, + NULL, + &pcf_epp_data, + pcf_epp_inc_use, + pcf_epp_dec_use, + pcf_epp_reg, + pcf_epp_unreg, +}; + +int __init i2c_pcfepp_init(void) +{ + struct i2c_pcf_epp *pepp = &gpe; + + printk(KERN_DEBUG "i2c-pcf-epp.o: i2c pcf8584-epp adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE); + if (base == 0) + pepp->pe_base = DEFAULT_BASE; + else + pepp->pe_base = base; + + if (irq == 0) + pepp->pe_irq = DEFAULT_IRQ; + else if (irq<0) { + // switch off irq + pepp->pe_irq=0; + } else { + pepp->pe_irq = irq; + } + if (clock == 0) + pepp->pe_clock = DEFAULT_CLOCK; + else + pepp->pe_clock = clock; + + if (own == 0) + pepp->pe_own = DEFAULT_OWN; + else + pepp->pe_own = own; + + pcf_epp_data.data = (void *)pepp; +#if (LINUX_VERSION_CODE >= 0x020301) + init_waitqueue_head(&pcf_wait); +#endif + if (pcf_epp_init(pepp) == 0) { + int ret; + if ( (ret = i2c_pcf_add_bus(&pcf_epp_ops)) < 0) { + printk(KERN_WARNING "i2c_pcf_add_bus caused an error: %d\n",ret); + release_region(pepp->pe_base , 5); + return ret; + } + } else { + + return -ENODEV; + } + printk(KERN_DEBUG "i2c-pcf-epp.o: found device at %#x.\n", pepp->pe_base); + return 0; +} + + +EXPORT_NO_SYMBOLS; + +#ifdef MODULE +MODULE_AUTHOR("Hans Berglund \n modified by Ryosuke Tajima "); +MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 EPP parallel port adapter"); + +MODULE_PARM(base, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(clock, "i"); +MODULE_PARM(own, "i"); +MODULE_PARM(i2c_debug, "i"); + +int init_module(void) +{ + return i2c_pcfepp_init(); +} + +void cleanup_module(void) +{ + i2c_pcf_del_bus(&pcf_epp_ops); + pcf_epp_exit(); +} + +#endif + + --- linux-old/drivers/i2c/i2c-pcf8584.h Thu Dec 19 16:26:41 CET 2002 +++ linux/drivers/i2c/i2c-pcf8584.h Thu Dec 19 16:26:41 CET 2002 @@ -22,5 +22,5 @@ /* With some changes from Frodo Looijaard */ -/* $Id: i2c-pcf8584.h,v 1.3 2000/01/18 23:54:07 frodo Exp $ */ +/* $Id: i2c-pcf8584.h,v 1.4 2001/10/02 00:07:37 mds Exp $ */ #ifndef I2C_PCF8584_H --- linux-old/drivers/i2c/i2c-philips-par.c Thu Dec 19 16:26:41 CET 2002 +++ linux/drivers/i2c/i2c-philips-par.c Thu Dec 19 16:26:41 CET 2002 @@ -22,5 +22,5 @@ Frodo Looijaard */ -/* $Id: i2c-philips-par.c,v 1.18 2000/07/06 19:21:49 frodo Exp $ */ +/* $Id: i2c-philips-par.c,v 1.25 2002/11/24 05:44:15 mds Exp $ */ #include @@ -30,5 +30,4 @@ #include #include - #include #include @@ -162,5 +161,5 @@ bit_lp_getsda, bit_lp_getscl, - 80, 80, 100, /* waits, timeout */ + 80, 80, HZ, /* waits, timeout */ }; @@ -171,5 +170,5 @@ bit_lp_getsda2, NULL, - 80, 80, 100, /* waits, timeout */ + 80, 80, HZ, /* waits, timeout */ }; @@ -191,9 +190,9 @@ GFP_KERNEL); if (!adapter) { - printk("i2c-philips-par: Unable to malloc.\n"); + printk(KERN_ERR "i2c-philips-par: Unable to malloc.\n"); return; } - printk("i2c-philips-par.o: attaching to %s\n", port->name); + printk(KERN_DEBUG "i2c-philips-par.o: attaching to %s\n", port->name); adapter->pdev = parport_register_device(port, "i2c-philips-par", @@ -202,5 +201,6 @@ NULL); if (!adapter->pdev) { - printk("i2c-philips-par: Unable to register with parport.\n"); + printk(KERN_ERR "i2c-philips-par: Unable to register with parport.\n"); + kfree(adapter); return; } @@ -211,6 +211,10 @@ adapter->bit_lp_data.data = port; + if (parport_claim_or_block(adapter->pdev) < 0 ) { + printk(KERN_ERR "i2c-philips-par: Could not claim parallel port.\n"); + kfree(adapter); + return; + } /* reset hardware to sane state */ - parport_claim_or_block(adapter->pdev); bit_lp_setsda(port, 1); bit_lp_setscl(port, 1); @@ -219,5 +223,5 @@ if (i2c_bit_add_bus(&adapter->adapter) < 0) { - printk("i2c-philips-par: Unable to register with I2C.\n"); + printk(KERN_ERR "i2c-philips-par: Unable to register with I2C.\n"); parport_unregister_device(adapter->pdev); kfree(adapter); @@ -265,5 +269,5 @@ struct parport *port; #endif - printk("i2c-philips-par.o: i2c Philips parallel port adapter module\n"); + printk(KERN_INFO "i2c-philips-par.o: i2c Philips parallel port adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,4) @@ -292,5 +296,7 @@ MODULE_AUTHOR("Simon G. Vogl "); MODULE_DESCRIPTION("I2C-Bus adapter routines for Philips parallel port adapter"); +#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); +#endif MODULE_PARM(type, "i"); --- linux-old/drivers/i2c/i2c-pport.c Thu Dec 19 16:26:41 CET 2002 +++ linux/drivers/i2c/i2c-pport.c Thu Dec 19 16:26:41 CET 2002 @@ -0,0 +1,245 @@ +/* ------------------------------------------------------------------------- */ +/* i2c-pport.c i2c-hw access for primitive i2c par. port adapter */ +/* ------------------------------------------------------------------------- */ +/* Copyright (C) 2001 Daniel Smolik + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* ------------------------------------------------------------------------- */ + +/* + See doc/i2c-pport for instructions on wiring to the + parallel port connector. + + Cut & paste :-) based on Velleman K9000 driver by Simon G. Vogl +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif + +#define DEFAULT_BASE 0x378 +static int base=0; +static unsigned char PortData = 0; + +/* ----- global defines ----------------------------------------------- */ +#define DEB(x) /* should be reasonable open, close &c. */ +#define DEB2(x) /* low level debugging - very slow */ +#define DEBE(x) x /* error messages */ +#define DEBINIT(x) x /* detection status messages */ + +/* --- Convenience defines for the parallel port: */ +#define BASE (unsigned int)(data) +#define DATA BASE /* Centronics data port */ +#define STAT (BASE+1) /* Centronics status port */ +#define CTRL (BASE+2) /* Centronics control port */ + +/* we will use SDA - Auto Linefeed(14) bit 1 POUT */ +/* we will use SCL - Initialize printer(16) BUSY bit 2*/ + +#define SET_SCL | 0x04 +#define CLR_SCL & 0xFB + + + + +#define SET_SDA & 0x04 +#define CLR_SDA | 0x02 + + +/* ----- local functions ---------------------------------------------- */ + + +static void bit_pport_setscl(void *data, int state) +{ + if (state) { + //high + PortData = PortData SET_SCL; + } else { + //low + PortData = PortData CLR_SCL; + } + outb(PortData, CTRL); +} + +static void bit_pport_setsda(void *data, int state) +{ + if (state) { + + PortData = PortData SET_SDA; + } else { + + PortData = PortData CLR_SDA; + } + outb(PortData, CTRL); +} + +static int bit_pport_getscl(void *data) +{ + + return ( 4 == ( (inb_p(CTRL)) & 0x04 ) ); +} + +static int bit_pport_getsda(void *data) +{ + return ( 0 == ( (inb_p(CTRL)) & 0x02 ) ); +} + +static int bit_pport_init(void) +{ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,14) + if (!request_region((base+2),1, "i2c (PPORT adapter)")) { + return -ENODEV; + } else { +#else + if (check_region((base+2),1) < 0) { + return -ENODEV; + } + request_region((base+2),1, "i2c (PPORT adapter)"); + { +#endif + /* test for PPORT adap. */ + + + PortData=inb(base+2); + PortData= (PortData SET_SDA) SET_SCL; + outb(PortData,base+2); + + if (!(inb(base+2) | 0x06)) { /* SDA and SCL will be high */ + DEBINIT(printk("i2c-pport.o: SDA and SCL was low.\n")); + return -ENODEV; + } else { + + /*SCL high and SDA low*/ + PortData = PortData SET_SCL CLR_SDA; + outb(PortData,base+2); + schedule_timeout(400); + if ( !(inb(base+2) | 0x4) ) { + //outb(0x04,base+2); + DEBINIT(printk("i2c-port.o: SDA was high.\n")); + return -ENODEV; + } + } + bit_pport_setsda((void*)base,1); + bit_pport_setscl((void*)base,1); + } + return 0; +} + +static int bit_pport_reg(struct i2c_client *client) +{ + return 0; +} + +static int bit_pport_unreg(struct i2c_client *client) +{ + release_region((base+2),1); + return 0; +} + +static void bit_pport_inc_use(struct i2c_adapter *adap) +{ +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif +} + +static void bit_pport_dec_use(struct i2c_adapter *adap) +{ +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif +} + +/* ------------------------------------------------------------------------ + * Encapsulate the above functions in the correct operations structure. + * This is only done when more than one hardware adapter is supported. + */ +static struct i2c_algo_bit_data bit_pport_data = { + NULL, + bit_pport_setsda, + bit_pport_setscl, + bit_pport_getsda, + bit_pport_getscl, + //NULL, + 40, 80, HZ, /* waits, timeout */ +}; + +static struct i2c_adapter bit_pport_ops = { + "Primitive Parallel port adaptor", + I2C_HW_B_PPORT, + NULL, + &bit_pport_data, + bit_pport_inc_use, + bit_pport_dec_use, + bit_pport_reg, + bit_pport_unreg, +}; + +int __init i2c_bitpport_init(void) +{ + printk("i2c-pport.o: i2c Primitive parallel port adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE); + + if (base==0) { + /* probe some values */ + base=DEFAULT_BASE; + bit_pport_data.data=(void*)DEFAULT_BASE; + if (bit_pport_init()==0) { + if(i2c_bit_add_bus(&bit_pport_ops) < 0) + return -ENODEV; + } else { + return -ENODEV; + } + } else { + bit_pport_data.data=(void*)base; + if (bit_pport_init()==0) { + if(i2c_bit_add_bus(&bit_pport_ops) < 0) + return -ENODEV; + } else { + return -ENODEV; + } + } + printk("i2c-pport.o: found device at %#x.\n",base); + return 0; +} + +static void __exit i2c_bitpport_exit(void) +{ + i2c_bit_del_bus(&bit_pport_ops); + release_region((base+2),1); +} + +EXPORT_NO_SYMBOLS; + +MODULE_AUTHOR("Daniel Smolik "); +MODULE_DESCRIPTION("I2C-Bus adapter routines for Primitive parallel port adapter") +; +MODULE_PARM(base, "i"); + +module_init(i2c_bitpport_init); +module_exit(i2c_bitpport_exit); --- linux-old/drivers/i2c/i2c-proc.c Thu Dec 19 16:26:41 CET 2002 +++ linux/drivers/i2c/i2c-proc.c Thu Dec 19 16:26:41 CET 2002 @@ -33,14 +33,8 @@ #include #include - #include #include - #include -/* FIXME need i2c versioning */ -#define LM_DATE "20010825" -#define LM_VERSION "2.6.1" - #ifndef THIS_MODULE #define THIS_MODULE NULL @@ -56,10 +50,16 @@ struct file *filp, void *buffer, size_t * lenp); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,19)) && \ + (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) +static int i2c_sysctl_chips(ctl_table * table, int *name, unsigned nlen, + void *oldval, size_t * oldlenp, + void *newval, size_t newlen, + void **context); +#else static int i2c_sysctl_chips(ctl_table * table, int *name, int nlen, void *oldval, size_t * oldlenp, void *newval, size_t newlen, void **context); - -int __init sensors_init(void); +#endif /* 2.2.19+ */ #define SENSORS_ENTRY_MAX 20 @@ -111,8 +111,19 @@ { char name_buffer[50]; - int id; + int id, i, end; if (i2c_is_isa_adapter(adapter)) sprintf(name_buffer, "%s-isa-%04x", prefix, addr); - else { + else if (!adapter->algo->smbus_xfer && !adapter->algo->master_xfer) { + /* dummy adapter, generate prefix */ + sprintf(name_buffer, "%s-", prefix); + end = strlen(name_buffer); + for(i = 0; i < 32; i++) { + if(adapter->algo->name[i] == ' ') + break; + name_buffer[end++] = tolower(adapter->algo->name[i]); + } + name_buffer[end] = 0; + sprintf(name_buffer + end, "-%04x", addr); + } else { if ((id = i2c_adapter_id(adapter)) < 0) return -ENOENT; @@ -181,7 +192,8 @@ if (!(new_header = register_sysctl_table(new_table, 0))) { + printk(KERN_ERR "i2c-proc.o: error: sysctl interface not supported by kernel!\n"); kfree(new_table); kfree(name); - return -ENOMEM; + return -EPERM; } @@ -195,5 +207,5 @@ !new_header->ctl_table->child->child->de) { printk - ("i2c-proc.o: NULL pointer when trying to install fill_inode fix!\n"); + (KERN_ERR "i2c-proc.o: NULL pointer when trying to install fill_inode fix!\n"); return id; } @@ -248,5 +260,5 @@ #ifdef DEBUG if (!inode) { - printk("i2c-proc.o: Warning: inode NULL in fill_inode()\n"); + printk(KERN_ERR "i2c-proc.o: Warning: inode NULL in fill_inode()\n"); return; } @@ -259,5 +271,5 @@ if (i == SENSORS_ENTRY_MAX) { printk - ("i2c-proc.o: Warning: inode (%ld) not found in fill_inode()\n", + (KERN_ERR "i2c-proc.o: Warning: inode (%ld) not found in fill_inode()\n", inode->i_ino); return; @@ -309,7 +321,14 @@ } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,19)) && \ + (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) +int i2c_sysctl_chips(ctl_table * table, int *name, unsigned nlen, + void *oldval, size_t * oldlenp, void *newval, + size_t newlen, void **context) +#else int i2c_sysctl_chips(ctl_table * table, int *name, int nlen, void *oldval, size_t * oldlenp, void *newval, size_t newlen, void **context) +#endif /* 2.2.19+ */ { struct i2c_chips_data data; @@ -416,7 +435,14 @@ /* This function is equivalent to i2c_proc_real, only it interacts with the sysctl(2) syscall, and returns no reals, but integers */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,19)) && \ + (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) +int i2c_sysctl_real(ctl_table * table, int *name, unsigned nlen, + void *oldval, size_t * oldlenp, void *newval, + size_t newlen, void **context) +#else int i2c_sysctl_real(ctl_table * table, int *name, int nlen, void *oldval, size_t * oldlenp, void *newval, size_t newlen, void **context) +#endif /* 2.2.19+ */ { long results[MAX_RESULTS]; @@ -685,5 +711,5 @@ #ifdef DEBUG printk - ("i2c-proc.o: found force parameter for adapter %d, addr %04x\n", + (KERN_DEBUG "i2c-proc.o: found force parameter for adapter %d, addr %04x\n", adapter_id, addr); #endif @@ -715,5 +741,5 @@ #ifdef DEBUG printk - ("i2c-proc.o: found ignore parameter for adapter %d, " + (KERN_DEBUG "i2c-proc.o: found ignore parameter for adapter %d, " "addr %04x\n", adapter_id, addr); #endif @@ -735,5 +761,5 @@ #ifdef DEBUG printk - ("i2c-proc.o: found ignore_range parameter for adapter %d, " + (KERN_DEBUG "i2c-proc.o: found ignore_range parameter for adapter %d, " "addr %04x\n", adapter_id, addr); #endif @@ -754,5 +780,5 @@ #ifdef DEBUG printk - ("i2c-proc.o: found normal isa entry for adapter %d, " + (KERN_DEBUG "i2c-proc.o: found normal isa entry for adapter %d, " "addr %04x\n", adapter_id, addr); @@ -776,5 +802,5 @@ #ifdef DEBUG printk - ("i2c-proc.o: found normal isa_range entry for adapter %d, " + (KERN_DEBUG "i2c-proc.o: found normal isa_range entry for adapter %d, " "addr %04x", adapter_id, addr); #endif @@ -790,5 +816,5 @@ #ifdef DEBUG printk - ("i2c-proc.o: found normal i2c entry for adapter %d, " + (KERN_DEBUG "i2c-proc.o: found normal i2c entry for adapter %d, " "addr %02x", adapter_id, addr); #endif @@ -806,5 +832,5 @@ #ifdef DEBUG printk - ("i2c-proc.o: found normal i2c_range entry for adapter %d, " + (KERN_DEBUG "i2c-proc.o: found normal i2c_range entry for adapter %d, " "addr %04x\n", adapter_id, addr); #endif @@ -823,5 +849,5 @@ #ifdef DEBUG printk - ("i2c-proc.o: found probe parameter for adapter %d, " + (KERN_DEBUG "i2c-proc.o: found probe parameter for adapter %d, " "addr %04x\n", adapter_id, addr); #endif @@ -842,5 +868,5 @@ #ifdef DEBUG printk - ("i2c-proc.o: found probe_range parameter for adapter %d, " + (KERN_DEBUG "i2c-proc.o: found probe_range parameter for adapter %d, " "addr %04x\n", adapter_id, addr); #endif @@ -863,9 +889,12 @@ int __init sensors_init(void) { - printk("i2c-proc.o version %s (%s)\n", LM_VERSION, LM_DATE); + printk(KERN_INFO "i2c-proc.o version %s (%s)\n", I2C_VERSION, I2C_DATE); i2c_initialized = 0; if (! (i2c_proc_header = - register_sysctl_table(i2c_proc, 0))) return -ENOMEM; + register_sysctl_table(i2c_proc, 0))) { + printk(KERN_ERR "i2c-proc.o: error: sysctl interface not supported by kernel!\n"); + return -EPERM; + } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,1)) i2c_proc_header->ctl_table->child->de->owner = THIS_MODULE; @@ -878,4 +907,12 @@ } +static void __exit i2c_cleanup(void) +{ + if (i2c_initialized >= 1) { + unregister_sysctl_table(i2c_proc_header); + i2c_initialized--; + } +} + EXPORT_SYMBOL(i2c_deregister_entry); EXPORT_SYMBOL(i2c_detect); @@ -884,27 +921,10 @@ EXPORT_SYMBOL(i2c_sysctl_real); -#ifdef MODULE - MODULE_AUTHOR("Frodo Looijaard "); MODULE_DESCRIPTION("i2c-proc driver"); +#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); +#endif -int i2c_cleanup(void) -{ - if (i2c_initialized >= 1) { - unregister_sysctl_table(i2c_proc_header); - i2c_initialized--; - } - return 0; -} - -int init_module(void) -{ - return sensors_init(); -} - -int cleanup_module(void) -{ - return i2c_cleanup(); -} -#endif /* MODULE */ +module_init(sensors_init); +module_exit(i2c_cleanup); --- linux-old/include/linux/i2c-proc.h Thu Dec 19 16:26:41 CET 2002 +++ linux/include/linux/i2c-proc.h Thu Dec 19 16:26:41 CET 2002 @@ -1,5 +1,6 @@ /* - sensors.h - Part of lm_sensors, Linux kernel modules for hardware - monitoring + i2c-proc.h - Part of the i2c package + was originally sensors.h - Part of lm_sensors, Linux kernel modules + for hardware monitoring Copyright (c) 1998, 1999 Frodo Looijaard @@ -56,8 +57,16 @@ In all cases, client points to the client we wish to interact with, and ctl_name is the SYSCTL id of the file we are accessing. */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,19)) && \ + (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) +extern int i2c_sysctl_real(ctl_table * table, int *name, unsigned nlen, + void *oldval, size_t * oldlenp, + void *newval, size_t newlen, + void **context); +#else extern int i2c_sysctl_real(ctl_table * table, int *name, int nlen, void *oldval, size_t * oldlenp, void *newval, size_t newlen, void **context); +#endif /* 2.2.19+ */ extern int i2c_proc_real(ctl_table * ctl, int write, struct file *filp, void *buffer, size_t * lenp); @@ -345,4 +354,29 @@ {force_ ## chip6,chip6}, \ {force_ ## chip7,chip7}, \ + {NULL}}; \ + SENSORS_INSMOD + +#define SENSORS_INSMOD_8(chip1,chip2,chip3,chip4,chip5,chip6,chip7,chip8) \ + enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6, chip7, chip8 }; \ + SENSORS_MODULE_PARM(force, \ + "List of adapter,address pairs to boldly assume " \ + "to be present"); \ + SENSORS_MODULE_PARM_FORCE(chip1); \ + SENSORS_MODULE_PARM_FORCE(chip2); \ + SENSORS_MODULE_PARM_FORCE(chip3); \ + SENSORS_MODULE_PARM_FORCE(chip4); \ + SENSORS_MODULE_PARM_FORCE(chip5); \ + SENSORS_MODULE_PARM_FORCE(chip6); \ + SENSORS_MODULE_PARM_FORCE(chip7); \ + SENSORS_MODULE_PARM_FORCE(chip8); \ + static struct i2c_force_data forces[] = {{force,any_chip}, \ + {force_ ## chip1,chip1}, \ + {force_ ## chip2,chip2}, \ + {force_ ## chip3,chip3}, \ + {force_ ## chip4,chip4}, \ + {force_ ## chip5,chip5}, \ + {force_ ## chip6,chip6}, \ + {force_ ## chip7,chip7}, \ + {force_ ## chip8,chip8}, \ {NULL}}; \ SENSORS_INSMOD --- linux-old/drivers/i2c/i2c-rpx.c Thu Dec 19 16:26:42 CET 2002 +++ linux/drivers/i2c/i2c-rpx.c Thu Dec 19 16:26:42 CET 2002 @@ -0,0 +1,136 @@ +/* + * Embedded Planet RPX Lite MPC8xx CPM I2C interface. + * Copyright (c) 1999 Dan Malek (dmalek@jlc.net). + * + * moved into proper i2c interface; + * Brad Parker (brad@heeltoe.com) + * + * RPX lite specific parts of the i2c interface + * Update: There actually isn't anything RPXLite-specific about this module. + * This should work for most any 8xx board. The console messages have been + * changed to eliminate RPXLite references. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +static void +rpx_iic_init(struct i2c_algo_8xx_data *data) +{ + volatile cpm8xx_t *cp; + volatile immap_t *immap; + + cp = cpmp; /* Get pointer to Communication Processor */ + immap = (immap_t *)IMAP_ADDR; /* and to internal registers */ + + data->iip = (iic_t *)&cp->cp_dparam[PROFF_IIC]; + + /* Check for and use a microcode relocation patch. + */ + if ((data->reloc = data->iip->iic_rpbase)) + data->iip = (iic_t *)&cp->cp_dpmem[data->iip->iic_rpbase]; + + data->i2c = (i2c8xx_t *)&(immap->im_i2c); + data->cp = cp; + + /* Initialize Port B IIC pins. + */ + cp->cp_pbpar |= 0x00000030; + cp->cp_pbdir |= 0x00000030; + cp->cp_pbodr |= 0x00000030; + + /* Allocate space for two transmit and two receive buffer + * descriptors in the DP ram. + */ + data->dp_addr = m8xx_cpm_dpalloc(sizeof(cbd_t) * 4); + + /* ptr to i2c area */ + data->i2c = (i2c8xx_t *)&(((immap_t *)IMAP_ADDR)->im_i2c); +} + +static int rpx_install_isr(int irq, void (*func)(void *, void *), void *data) +{ + /* install interrupt handler */ + cpm_install_handler(irq, (void (*)(void *, struct pt_regs *)) func, data); + + return 0; +} + +static int rpx_reg(struct i2c_client *client) +{ + return 0; +} + +static int rpx_unreg(struct i2c_client *client) +{ + return 0; +} + +static void rpx_inc_use(struct i2c_adapter *adap) +{ +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif +} + +static void rpx_dec_use(struct i2c_adapter *adap) +{ +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif +} + +static struct i2c_algo_8xx_data rpx_data = { + .setisr = rpx_install_isr +}; + + +static struct i2c_adapter rpx_ops = { + "m8xx", + I2C_HW_MPC8XX_EPON, + NULL, + &rpx_data, + rpx_inc_use, + rpx_dec_use, + rpx_reg, + rpx_unreg, +}; + +int __init i2c_rpx_init(void) +{ + printk("i2c-rpx.o: i2c MPC8xx module version %s (%s)\n", I2C_VERSION, I2C_DATE); + + /* reset hardware to sane state */ + rpx_iic_init(&rpx_data); + + if (i2c_8xx_add_bus(&rpx_ops) < 0) { + printk("i2c-rpx: Unable to register with I2C\n"); + return -ENODEV; + } + + return 0; +} + +void __exit i2c_rpx_exit(void) +{ + i2c_8xx_del_bus(&rpx_ops); +} + +#ifdef MODULE +MODULE_AUTHOR("Dan Malek "); +MODULE_DESCRIPTION("I2C-Bus adapter routines for MPC8xx boards"); + +module_init(i2c_rpx_init); +module_exit(i2c_rpx_exit); +#endif + --- linux-old/drivers/i2c/i2c-velleman.c Thu Dec 19 16:26:42 CET 2002 +++ linux/drivers/i2c/i2c-velleman.c Thu Dec 19 16:26:42 CET 2002 @@ -19,5 +19,5 @@ /* ------------------------------------------------------------------------- */ -/* $Id: i2c-velleman.c,v 1.19 2000/01/24 02:06:33 mds Exp $ */ +/* $Id: i2c-velleman.c,v 1.25 2002/11/24 05:44:15 mds Exp $ */ #include @@ -25,8 +25,8 @@ #include #include +#include #include /* for 2.0 kernels to get NULL */ #include /* for 2.0 kernels to get ENODEV */ #include - #include #include @@ -92,5 +92,5 @@ { if (check_region(base,(base == 0x3bc)? 3 : 8) < 0 ) { - DEBE(printk("i2c-velleman.o: Port %#x already in use.\n", + DEBE(printk(KERN_DEBUG "i2c-velleman.o: Port %#x already in use.\n", base)); return -ENODEV; @@ -145,5 +145,5 @@ bit_velle_getsda, bit_velle_getscl, - 10, 10, 100, /* waits, timeout */ + 10, 10, HZ, /* waits, timeout */ }; @@ -161,5 +161,5 @@ int __init i2c_bitvelle_init(void) { - printk("i2c-velleman.o: i2c Velleman K8000 adapter module\n"); + printk(KERN_INFO "i2c-velleman.o: i2c Velleman K8000 adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE); if (base==0) { /* probe some values */ @@ -181,5 +181,5 @@ } } - printk("i2c-velleman.o: found device at %#x.\n",base); + printk(KERN_DEBUG "i2c-velleman.o: found device at %#x.\n",base); return 0; } @@ -190,5 +190,7 @@ MODULE_AUTHOR("Simon G. Vogl "); MODULE_DESCRIPTION("I2C-Bus adapter routines for Velleman K8000 adapter"); +#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); +#endif MODULE_PARM(base, "i"); --- linux-old/include/linux/i2c.h Thu Dec 19 16:26:42 CET 2002 +++ linux/include/linux/i2c.h Thu Dec 19 16:26:42 CET 2002 @@ -24,11 +24,11 @@ Frodo Looijaard */ -/* $Id: i2c.h,v 1.46 2001/08/31 00:04:07 phil Exp $ */ +/* $Id: i2c.h,v 1.64 2002/12/08 22:17:32 phil Exp $ */ #ifndef I2C_H #define I2C_H -#define I2C_DATE "20010830" -#define I2C_VERSION "2.6.1" +#define I2C_DATE "20021208" +#define I2C_VERSION "2.7.0" #include /* id values of adapters et. al. */ @@ -71,4 +71,9 @@ union i2c_smbus_data; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,1) +#ifndef __exit +#define __exit +#endif +#endif /* @@ -124,4 +129,6 @@ u8 command, u8 length, u8 *values); +extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client, + u8 command, u8 *values); extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client * client, u8 command, u8 length, @@ -282,4 +289,7 @@ #define I2C_CLIENT_ALLOW_MULTIPLE_USE 0x02 /* Allow multiple access-locks */ /* on an i2c_client */ +#define I2C_CLIENT_PEC 0x04 /* Use Packet Error Checking */ +#define I2C_CLIENT_TEN 0x10 /* we have a ten bit chip address */ + /* Must equal I2C_M_TEN below */ /* i2c_client_address_data is the struct for holding default client @@ -388,4 +398,6 @@ #define I2C_M_NOSTART 0x4000 #define I2C_M_REV_DIR_ADDR 0x2000 +#define I2C_M_IGNORE_NAK 0x1000 +#define I2C_M_NO_RD_ACK 0x0800 short len; /* msg length */ char *buf; /* pointer to msg data */ @@ -396,5 +408,11 @@ #define I2C_FUNC_I2C 0x00000001 #define I2C_FUNC_10BIT_ADDR 0x00000002 -#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART} */ +#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART,..} */ +#define I2C_FUNC_SMBUS_HWPEC_CALC 0x00000008 /* SMBus 2.0 */ +#define I2C_FUNC_SMBUS_READ_WORD_DATA_PEC 0x00000800 /* SMBus 2.0 */ +#define I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC 0x00001000 /* SMBus 2.0 */ +#define I2C_FUNC_SMBUS_PROC_CALL_PEC 0x00002000 /* SMBus 2.0 */ +#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL_PEC 0x00004000 /* SMBus 2.0 */ +#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */ #define I2C_FUNC_SMBUS_QUICK 0x00010000 #define I2C_FUNC_SMBUS_READ_BYTE 0x00020000 @@ -407,6 +425,10 @@ #define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000 #define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000 -#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* New I2C-like block */ -#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* transfer */ +#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */ +#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */ +#define I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 0x10000000 /* I2C-like block xfer */ +#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2 0x20000000 /* w/ 2-byte reg. addr. */ +#define I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC 0x40000000 /* SMBus 2.0 */ +#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC 0x80000000 /* SMBus 2.0 */ #define I2C_FUNC_SMBUS_BYTE I2C_FUNC_SMBUS_READ_BYTE | \ @@ -420,4 +442,17 @@ #define I2C_FUNC_SMBUS_I2C_BLOCK I2C_FUNC_SMBUS_READ_I2C_BLOCK | \ I2C_FUNC_SMBUS_WRITE_I2C_BLOCK +#define I2C_FUNC_SMBUS_I2C_BLOCK_2 I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 | \ + I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2 +#define I2C_FUNC_SMBUS_BLOCK_DATA_PEC I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC | \ + I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC +#define I2C_FUNC_SMBUS_WORD_DATA_PEC I2C_FUNC_SMBUS_READ_WORD_DATA_PEC | \ + I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC + +#define I2C_FUNC_SMBUS_READ_BYTE_PEC I2C_FUNC_SMBUS_READ_BYTE_DATA +#define I2C_FUNC_SMBUS_WRITE_BYTE_PEC I2C_FUNC_SMBUS_WRITE_BYTE_DATA +#define I2C_FUNC_SMBUS_READ_BYTE_DATA_PEC I2C_FUNC_SMBUS_READ_WORD_DATA +#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA_PEC I2C_FUNC_SMBUS_WRITE_WORD_DATA +#define I2C_FUNC_SMBUS_BYTE_PEC I2C_FUNC_SMBUS_BYTE_DATA +#define I2C_FUNC_SMBUS_BYTE_DATA_PEC I2C_FUNC_SMBUS_WORD_DATA #define I2C_FUNC_SMBUS_EMUL I2C_FUNC_SMBUS_QUICK | \ @@ -426,13 +461,19 @@ I2C_FUNC_SMBUS_WORD_DATA | \ I2C_FUNC_SMBUS_PROC_CALL | \ - I2C_FUNC_SMBUS_WRITE_BLOCK_DATA + I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \ + I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC | \ + I2C_FUNC_SMBUS_I2C_BLOCK /* * Data for SMBus Messages */ +#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */ +#define I2C_SMBUS_I2C_BLOCK_MAX 32 /* Not specified but we use same structure */ union i2c_smbus_data { __u8 byte; __u16 word; - __u8 block[33]; /* block[0] is used for length */ + __u8 block[I2C_SMBUS_BLOCK_MAX + 3]; /* block[0] is used for length */ + /* one more for read length in block process call */ + /* and one more for PEC */ }; @@ -450,4 +491,9 @@ #define I2C_SMBUS_BLOCK_DATA 5 #define I2C_SMBUS_I2C_BLOCK_DATA 6 +#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */ +#define I2C_SMBUS_BLOCK_DATA_PEC 8 /* SMBus 2.0 */ +#define I2C_SMBUS_PROC_CALL_PEC 9 /* SMBus 2.0 */ +#define I2C_SMBUS_BLOCK_PROC_CALL_PEC 10 /* SMBus 2.0 */ +#define I2C_SMBUS_WORD_DATA_PEC 11 /* SMBus 2.0 */ @@ -475,4 +521,5 @@ #define I2C_FUNCS 0x0705 /* Get the adapter functionality */ #define I2C_RDWR 0x0707 /* Combined R/W transfer (one stop only)*/ +#define I2C_PEC 0x0708 /* != 0 for SMBus PEC */ #if 0 #define I2C_ACK_TEST 0x0710 /* See if a slave is at a specific address */ --- linux-old/drivers/i2c/Config.in Thu Dec 19 16:26:42 CET 2002 +++ linux/drivers/i2c/Config.in Thu Dec 19 16:26:42 CET 2002 @@ -14,10 +14,8 @@ dep_tristate ' ELV adapter' CONFIG_I2C_ELV $CONFIG_I2C_ALGOBIT dep_tristate ' Velleman K9000 adapter' CONFIG_I2C_VELLEMAN $CONFIG_I2C_ALGOBIT - dep_tristate ' NatSemi SCx200 I2C using GPIO pins' CONFIG_SCx200_I2C $CONFIG_SCx200 $CONFIG_I2C_ALGOBIT - if [ "$CONFIG_SCx200_I2C" != "n" ]; then - int ' GPIO pin used for SCL' CONFIG_SCx200_I2C_SCL 12 - int ' GPIO pin used for SDA' CONFIG_SCx200_I2C_SDA 13 + dep_tristate ' Basic I2C on Parallel Port' CONFIG_I2C_PPORT $CONFIG_I2C_ALGOBIT + if [ "$CONFIG_ARCH_SA1100" = "y" ]; then + dep_tristate 'SA1100 I2C Adapter' CONFIG_I2C_FRODO $CONFIG_I2C_ALGOBIT fi - dep_tristate ' NatSemi SCx200 ACCESS.bus' CONFIG_SCx200_ACB $CONFIG_I2C fi @@ -25,4 +23,5 @@ if [ "$CONFIG_I2C_ALGOPCF" != "n" ]; then dep_tristate ' Elektor ISA card' CONFIG_I2C_ELEKTOR $CONFIG_I2C_ALGOPCF + dep_tristate ' PCF on EPP port' CONFIG_I2C_PCFEPP $CONFIG_I2C_ALGOPCF fi @@ -39,20 +38,16 @@ fi fi - if [ "$CONFIG_405" = "y" ]; then - dep_tristate 'PPC 405 I2C Algorithm' CONFIG_I2C_PPC405_ALGO $CONFIG_I2C - if [ "$CONFIG_I2C_PPC405_ALGO" != "n" ]; then - dep_tristate ' PPC 405 I2C Adapter' CONFIG_I2C_PPC405_ADAP $CONFIG_I2C_PPC405_ALGO + if [ "$CONFIG_IBM_OCP" = "y" ]; then + dep_tristate 'IBM on-chip I2C Algorithm' CONFIG_I2C_IBM_OCP_ALGO $CONFIG_I2C + if [ "$CONFIG_I2C_IBM_OCP_ALGO" != "n" ]; then + dep_tristate ' IBM on-chip I2C Adapter' CONFIG_I2C_IBM_OCP_ADAP $CONFIG_I2C_IBM_OCP_ALGO fi fi - if [ "$CONFIG_ALL_PPC" = "y" ] ; then - dep_tristate 'Keywest I2C interface in Apple Core99 machines' CONFIG_I2C_KEYWEST $CONFIG_I2C - fi - # This is needed for automatic patch generation: sensors code starts here # This is needed for automatic patch generation: sensors code ends here dep_tristate 'I2C device interface' CONFIG_I2C_CHARDEV $CONFIG_I2C - dep_tristate 'I2C /proc interface (required for hardware sensors)' CONFIG_I2C_PROC $CONFIG_I2C + dep_tristate 'I2C /proc interface (required for hardware sensors)' CONFIG_I2C_PROC $CONFIG_I2C $CONFIG_SYSCTL fi --- linux-old/Makefile Thu Dec 19 16:26:42 CET 2002 +++ linux/Makefile Thu Dec 19 16:26:42 CET 2002 --- linux-old/drivers/Makefile Thu Dec 19 16:26:42 CET 2002 +++ linux/drivers/Makefile Thu Dec 19 16:26:42 CET 2002 --- linux-old/drivers/i2c/Makefile Thu Dec 19 16:26:42 CET 2002 +++ linux/drivers/i2c/Makefile Thu Dec 19 16:26:42 CET 2002 @@ -6,5 +6,5 @@ export-objs := i2c-core.o i2c-algo-bit.o i2c-algo-pcf.o \ - i2c-algo-ite.o i2c-proc.o + i2c-algo-8xx.o i2c-proc.o i2c-algo-ibm_ocp.o obj-$(CONFIG_I2C) += i2c-core.o @@ -14,12 +14,14 @@ obj-$(CONFIG_I2C_ELV) += i2c-elv.o obj-$(CONFIG_I2C_VELLEMAN) += i2c-velleman.o +obj-$(CONFIG_I2C_PPORT) += i2c-pport.o obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o -obj-$(CONFIG_ITE_I2C_ALGO) += i2c-algo-ite.o -obj-$(CONFIG_ITE_I2C_ADAP) += i2c-adap-ite.o +obj-$(CONFIG_I2C_PCFEPP) += i2c-pcf-epp.o obj-$(CONFIG_I2C_PROC) += i2c-proc.o -obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o -obj-$(CONFIG_SCx200_ACB) += scx200_acb.o -obj-$(CONFIG_I2C_KEYWEST) += i2c-keywest.o +obj-$(CONFIG_I2C_ALGO8XX) += i2c-algo-8xx.o +obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o +obj-$(CONFIG_I2C_IBM_OCP_ALGO) += i2c-algo-ibm_ocp.o +obj-$(CONFIG_I2C_IBM_OCP_ADAP) += i2c-adap-ibm_ocp.o +obj-$(CONFIG_I2C_FRODO) += i2c-frodo.o # This is needed for automatic patch generation: sensors code starts here --- linux-old/drivers/char/Config.in Thu Dec 19 16:26:42 CET 2002 +++ linux/drivers/char/Config.in Thu Dec 19 16:26:42 CET 2002 --- linux-old/drivers/char/mem.c Thu Dec 19 16:26:42 CET 2002 +++ linux/drivers/char/mem.c Thu Dec 19 16:26:42 CET 2002 --- linux-old/Documentation/Configure.help Thu Dec 19 16:26:42 CET 2002 +++ linux/Documentation/Configure.help Thu Dec 19 16:26:42 CET 2002 @@ -17656,4 +17656,35 @@ board at . +UltraSPARC-III bootbus i2c controller driver +CONFIG_BBC_I2C + The BBC devices on the UltraSPARC III have two I2C controllers. The + first I2C controller connects mainly to configuration PROMs (NVRAM, + CPU configuration, DIMM types, etc.). The second I2C controller + connects to environmental control devices such as fans and + temperature sensors. The second controller also connects to the + smartcard reader, if present. Say Y to enable support for these. + +ITE I2C Algorithm +CONFIG_ITE_I2C_ALGO + This supports the use the ITE8172 I2C interface found on some MIPS + systems. Say Y if you have one of these. You should also say Y for + the ITE I2C peripheral driver support below. + + This support is also available as a module. If you want to compile + it as a modules, say M here and read + . + The module will be called i2c-algo-ite.o. + +ITE I2C Adapter +CONFIG_ITE_I2C_ADAP + This supports the ITE8172 I2C peripheral found on some MIPS + systems. Say Y if you have one of these. You should also say Y for + the ITE I2C driver algorithm support above. + + This support is also available as a module. If you want to compile + it as a module, say M here and read + . + The module will be called i2c-adap-ite.o. + I2C support CONFIG_I2C @@ -17680,13 +17711,4 @@ The module will be called i2c-core.o. -UltraSPARC-III bootbus i2c controller driver -CONFIG_BBC_I2C - The BBC devices on the UltraSPARC III have two I2C controllers. The - first I2C controller connects mainly to configuration PROMs (NVRAM, - CPU configuration, DIMM types, etc.). The second I2C controller - connects to environmental control devices such as fans and - temperature sensors. The second controller also connects to the - smartcard reader, if present. Say Y to enable support for these. - I2C bit-banging interfaces CONFIG_I2C_ALGOBIT @@ -17733,4 +17755,14 @@ The module will be called i2c-velleman.o. +Basic I2C on Parallel Port adapter +CONFIG_I2C_PPORT + This supports directly connecting I2C devices to the parallel port. + See for more information. + + This driver is also available as a module. If you want to compile + it as a module, say M here and read + . + The module will be called i2c-pport.o. + I2C PCF 8584 interfaces CONFIG_I2C_ALGOPCF @@ -17754,25 +17786,57 @@ The module will be called i2c-elektor.o. -ITE I2C Algorithm -CONFIG_ITE_I2C_ALGO - This supports the use the ITE8172 I2C interface found on some MIPS - systems. Say Y if you have one of these. You should also say Y for - the ITE I2C peripheral driver support below. +PCF on the EPP Parallel Port +CONFIG_I2C_PCFEPP + This supports the PCF8584 connected to the parallel port. - This support is also available as a module. If you want to compile - it as a modules, say M here and read + This driver is also available as a module. If you want to compile + it as a module, say M here and read . - The module will be called i2c-algo-ite.o. + The module will be called i2c-pcf-epp.o. -ITE I2C Adapter -CONFIG_ITE_I2C_ADAP - This supports the ITE8172 I2C peripheral found on some MIPS - systems. Say Y if you have one of these. You should also say Y for - the ITE I2C driver algorithm support above. +Motorola 8xx I2C algorithm +CONFIG_I2C_ALGO8XX + This is the algorithm that allows you to use Motorola 8xx I2C adapters. - This support is also available as a module. If you want to compile + This driver is also available as a module. If you want to compile it as a module, say M here and read . - The module will be called i2c-adap-ite.o. + The module will be called i2c-algo-8xx.o. + +Motorola 8xx I2C interface +CONFIG_I2C_RPXLITE + This supports the Motorola 8xx I2C device. + + This driver is also available as a module. If you want to compile + it as a module, say M here and read + . + The module will be called i2c-rpx.o. + +IBM 405 I2C algorithm +CONFIG_I2C_IBM_OCP_ALGO + This is the algorithm that allows you to use IBM 405 I2C adapters. + + This driver is also available as a module. If you want to compile + it as a module, say M here and read + . + The module will be called i2c-algo-ibm_ocp.o. + +IBM 405 I2C interface +CONFIG_I2C_IBM_OCP_ADAP + This supports the IBM 405 I2C device. + + This driver is also available as a module. If you want to compile + it as a module, say M here and read + . + The module will be called i2c-adap-ibm_ocp.o. + +StrongARM SA-1110 interface +CONFIG_I2C_FRODO + This supports the StrongARM SA-1110 Development Board. + + This driver is also available as a module. If you want to compile + it as a module, say M here and read + . + The module will be called i2c-frodo.o. I2C device interface --- linux-old/MAINTAINERS Thu Dec 19 16:26:42 CET 2002 +++ linux/MAINTAINERS Thu Dec 19 16:26:42 CET 2002