Add a non-blocking interface to the I2C code, part 7
PATCH 1/1 Add a non-blocking interface to the I2C code, part 7
See part 1 for details on what this does...
This patch modifies the I801 SMBus driver to use the non-blocking interface.
Signed-off-by Corey Minyard <[email protected]>
drivers/i2c/busses/i2c-i801.c +395 -261
@@ -40,6 +40,14 @@/* Note: we assume there can only be one I801, with one SMBus interface */ +/* Another note: This interface is extremely sensitive to timing and +failure handling. If you don't wait at least one jiffie after +starting the transaction before checking things, you will screw it +up. If you don't wait a jiffie after the final check, you will +screw it up. If you screw it up by these manners or by abandoning +an operation in progress, the I2C bus is likely stuck and won't +work any more. Gotta love this hardware. */ +#include <linux/config.h> #include <linux/module.h> #include <linux/pci.h>
@@ -79,7 +87,8 @@#define SMBHSTCFG_I2C_EN 4/* Other settings */ -#define MAX_TIMEOUT 100 +#define MAX_TIMEOUT_US 100000 +#define RETRY_TIME_US 500/* Retry minimum is 500us */ #define ENABLE_INT9 0/* set to 0x01 to enable - untested */ /* I801 command constants */
@@ -105,21 +114,31 @@"Forcibly enable the I801 at the given address. " "EXTREMELY DANGEROUS!"); -static int i801_transaction (void ); -static int i801_block_transaction (union i2c_smbus_data *data, -char read_write,int command); -static unsigned short i801_smba;static struct pci_dev *I801_dev;static int isich4; +struct i801_i2c_data +{ +int i; +int len; +unsigned char hostc; +int block; +int hwpec; +int xact; +int hststs; +int wait_intr; +int finished; +}; +struct i801_i2c_data i801_data; +static int i801_setup (struct pci_dev *dev) {int error_return =0 ;unsigned char temp;/* Note: we keep on searching until we have found 'function 3' */ -if (PCI_FUNC (dev->devfn) !=3 ) +if (PCI_FUNC (dev->devfn) !=3 )return -ENODEV ; I801_dev = dev;
@@ -136,7 +155,7 @@ }else {pci_read_config_word (I801_dev,SMBBA , &i801_smba); i801_smba &=0xfff0 ; -if (i801_smba ==0 ) { +if (i801_smba ==0 ) {dev_err (&dev->dev,"SMB base address uninitialized" "- upgrade BIOS or use force_addr=0xaddr\n" );return -ENODEV ;
@@ -180,12 +199,93 @@return error_return; } -static int i801_transaction (void ) +static void i801_check_hststs (struct i2c_adapter *adap, +struct i2c_op_q_entry *entry, +struct i801_i2c_data *d) +{ +if (d->hststs &0x10 ) { + entry->result = -EIO ; +dev_dbg (&I801_dev->dev, +"Error: Failed bus transaction\n" ); + }else if (d->hststs &0x08 ) { + entry->result = -EIO ; +dev_err (&I801_dev->dev,"Bus collision!\n" ); +/* Clock stops and slave is stuck in mid-transmission */ + }else if (d->hststs &0x04 ) { + entry->result = -EIO ; +dev_dbg (&I801_dev->dev,"Error: no response!\n" ); + } +} + +static void i801_finish (struct i2c_adapter *adap, +struct i2c_op_q_entry *entry, +struct i801_i2c_data *d) +{ + d->finished =1 ; + +#ifdef HAVE_PEC +if (isich4 && d->hwpec) { +if (entry->smbus.size !=I2C_SMBUS_QUICK && + entry->smbus.size !=I2C_SMBUS_I2C_BLOCK_DATA ) +outb_p (0 ,SMBAUXCTL ); + } +#endif + +if (d->block || (entry->result <0 ) || + ((entry->smbus.read_write ==I2C_SMBUS_WRITE ) + || (d->xact ==I801_QUICK ))) +return ; + +switch (d->xact &0x7f ) { +case I801_BYTE :/* Result put in SMBHSTDAT0 */ +case I801_BYTE_DATA : + entry->smbus.data->byte =inb_p (SMBHSTDAT0 ); +break ; +case I801_WORD_DATA : + entry->smbus.data->word =inb_p (SMBHSTDAT0 ) + + (inb_p (SMBHSTDAT1 ) <<8 ); +break ; + } +} + +static void i801_transaction_final_check (struct i2c_adapter *adap, +struct i2c_op_q_entry *entry, +struct i801_i2c_data *d) +{ +i801_check_hststs (adap, entry, d); + +if ((inb_p (SMBHSTSTS ) &0x1f ) !=0x00 ) +outb_p (inb (SMBHSTSTS ),SMBHSTSTS ); + +if ((d->hststs = (0x1f &inb_p (SMBHSTSTS ))) !=0x00 ) { +dev_dbg (&I801_dev->dev,"Failed reset at end of transaction" +"(%02x)\n" , d->hststs); + } +dev_dbg (&I801_dev->dev,"Transaction (post): CNT=%02x, CMD=%02x, " +"ADD=%02x, DAT0=%02x, DAT1=%02x\n" ,inb_p (SMBHSTCNT ), +inb_p (SMBHSTCMD ),inb_p (SMBHSTADD ),inb_p (SMBHSTDAT0 ), +inb_p (SMBHSTDAT1 )); +} + +static void i801_transaction_poll (struct i2c_adapter *adap, +struct i2c_op_q_entry *entry, +struct i801_i2c_data *d) { -int temp; -int result =0 ; -int timeout =0 ; + d->hststs =inb_p (SMBHSTSTS ); +if (!(d->hststs &0x01 )) { +i801_transaction_final_check (adap, entry, d); +i801_finish (adap, entry, d); + }else if (entry->time_left <=0 ) { +dev_dbg (&I801_dev->dev,"SMBus Timeout!\n" ); + entry->result = -EIO ; +i801_transaction_final_check (adap, entry, d); + } +} +static void i801_transaction_start (struct i2c_adapter *adap, +struct i2c_op_q_entry *entry, +struct i801_i2c_data *d) +{ dev_dbg(&I801_dev->dev, "Transaction (pre): CNT=%02x, CMD=%02x," "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
@@ -193,331 +293,362 @@/* Make sure the SMBus host is ready to start transmitting */ /* 0x1f = Failed, Bus_Err, Dev_Err, Intr, Host_Busy */ -if ((temp = (0x1f &inb_p (SMBHSTSTS ))) !=0x00 ) { +if ((d->hststs = (0x1f &inb_p (SMBHSTSTS ))) !=0x00 ) {dev_dbg (&I801_dev->dev,"SMBus busy (%02x). Resetting... \n" , - temp); -outb_p (temp,SMBHSTSTS ); -if ((temp = (0x1f &inb_p (SMBHSTSTS ))) !=0x00 ) { -dev_dbg (&I801_dev->dev,"Failed! (%02x)\n" , temp); -return -1 ; + d->hststs); +outb_p (d->hststs,SMBHSTSTS ); +if ((d->hststs = (0x1f &inb_p (SMBHSTSTS ))) !=0x00 ) { +dev_dbg (&I801_dev->dev,"Failed! (%02x)\n" , d->hststs); + entry->result = -EIO ; +return ; }else {dev_dbg (&I801_dev->dev,"Successfull!\n" ); } }outb_p (inb (SMBHSTCNT ) |I801_START ,SMBHSTCNT ); +} -/* We will always wait for a fraction of a second! */ -do { -msleep (1 ); - temp =inb_p (SMBHSTSTS ); - }while ((temp &0x01 ) && (timeout++ <MAX_TIMEOUT )); - -/* If the SMBus is still busy, we give up */ -if (timeout >=MAX_TIMEOUT ) { -dev_dbg (&I801_dev->dev,"SMBus Timeout!\n" ); - result =-1 ; +static void i801_block_finish (struct i2c_adapter *adap, +struct i2c_op_q_entry *entry, +struct i801_i2c_data *d) +{ +if (entry->smbus.size ==I2C_SMBUS_I2C_BLOCK_DATA ) { +/* restore saved configuration register value */ +pci_write_config_byte (I801_dev,SMBHSTCFG , d->hostc); } -if (temp &0x10 ) { - result =-1 ; -dev_dbg (&I801_dev->dev,"Error: Failed bus transaction\n" ); - } +i801_finish (adap, entry, d); +} -if (temp &0x08 ) { - result =-1 ; -dev_err (&I801_dev->dev,"Bus collision! SMBus may be locked " -"until next hard reset. (sorry!)\n" ); -/* Clock stops and slave is stuck in mid-transmission */ - } +static void i801_block_poll_wait_intr (struct i2c_adapter *adap, +struct i2c_op_q_entry *entry, +struct i801_i2c_data *d) +{ +#ifdef HAVE_PEC +if (entry->result >=0 && + isich4 && + entry->smbus.size ==I2C_SMBUS_BLOCK_DATA_PEC ) + { +/* wait for INTR bit as advised by Intel */ + d->hststs =inb_p (SMBHSTSTS ); +if (d->hststs &0x02 ) { +outb_p (d->hststs,SMBHSTSTS ); +i801_block_finish (adap, entry, d); + }else if (entry->time_left <=0 ) { +/* Timed out */ +outb_p (d->hststs,SMBHSTSTS ); + entry->result = -EIO ; +dev_dbg (&I801_dev->dev,"PEC Timeout!\n" ); + } + } else +#endif +i801_block_finish (adap, entry, d); +} -if (temp &0x04 ) { - result =-1 ; -dev_dbg (&I801_dev->dev,"Error: no response!\n" ); +static void i801_block_next_byte (struct i2c_adapter *adap, +struct i2c_op_q_entry *entry, +struct i801_i2c_data *d) +{ +int smbcmd; +unsigned char errmask; + +if (d->i > d->len) { + d->wait_intr =1 ; + entry->time_left =MAX_TIMEOUT_US ; +i801_block_poll_wait_intr (adap, entry, d); +return ; } -if ((inb_p (SMBHSTSTS ) &0x1f ) !=0x00 ) -outb_p (inb (SMBHSTSTS ),SMBHSTSTS ); +if (d->i == d->len && entry->smbus.read_write ==I2C_SMBUS_READ ) + smbcmd =I801_BLOCK_LAST ; +else + smbcmd =I801_BLOCK_DATA ; +outb_p (smbcmd |ENABLE_INT9 ,SMBHSTCNT ); -if ((temp = (0x1f &inb_p (SMBHSTSTS ))) !=0x00 ) { -dev_dbg (&I801_dev->dev,"Failed reset at end of transaction" -"(%02x)\n" , temp); +dev_dbg (&I801_dev->dev,"Block (pre %d): CNT=%02x, CMD=%02x, " +"ADD=%02x, DAT0=%02x, BLKDAT=%02x\n" , d->i, +inb_p (SMBHSTCNT ),inb_p (SMBHSTCMD ),inb_p (SMBHSTADD ), +inb_p (SMBHSTDAT0 ),inb_p (SMBBLKDAT )); + +/* Make sure the SMBus host is ready to start transmitting */ + d->hststs =inb_p (SMBHSTSTS ); +if (d->i ==1 ) { +/* Erronenous conditions before transaction: +* Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */ + errmask=0x9f ; + }else { +/* Erronenous conditions during transaction: +* Failed, Bus_Err, Dev_Err, Intr */ + errmask=0x1e ; + } +if (d->hststs & errmask) { +dev_dbg (&I801_dev->dev,"SMBus busy (%02x). " +"Resetting... \n" , d->hststs); +outb_p (d->hststs,SMBHSTSTS ); +if (((d->hststs =inb_p (SMBHSTSTS )) & errmask) !=0x00 ) { +dev_err (&I801_dev->dev, +"Reset failed! (%02x)\n" , d->hststs); + entry->result = -EIO ; +return ; + } +if (d->i !=1 ) { +/* if die in middle of block transaction, fail */ + entry->result = -EIO ; +return ; + } } -dev_dbg (&I801_dev->dev,"Transaction (post): CNT=%02x, CMD=%02x, " -"ADD=%02x, DAT0=%02x, DAT1=%02x\n" ,inb_p (SMBHSTCNT ), -inb_p (SMBHSTCMD ),inb_p (SMBHSTADD ),inb_p (SMBHSTDAT0 ), -inb_p (SMBHSTDAT1 )); -return result; + +if (d->i ==1 ) +outb_p (inb (SMBHSTCNT ) |I801_START ,SMBHSTCNT ); } -/* All-inclusive block transaction function */ -static int i801_block_transaction (union i2c_smbus_data *data,char read_write, -int command) +/* Called on timer ticks. This checks the result of the +transaction. */ +static void i801_block_poll (struct i2c_adapter *adap, +struct i2c_op_q_entry *entry, +struct i801_i2c_data *d) { -int i, len; -int smbcmd; -int temp; -int result =0 ; -int timeout; -unsigned char hostc, errmask; - -if (command ==I2C_SMBUS_I2C_BLOCK_DATA ) { -if (read_write ==I2C_SMBUS_WRITE ) { -/* set I2C_EN bit in configuration register */ -pci_read_config_byte (I801_dev,SMBHSTCFG , &hostc); -pci_write_config_byte (I801_dev,SMBHSTCFG , - hostc |SMBHSTCFG_I2C_EN ); - }else { -dev_err (&I801_dev->dev, -"I2C_SMBUS_I2C_BLOCK_READ not DB!\n" ); -return -1 ; + d->hststs =inb_p (SMBHSTSTS ); +if (!(d->hststs &0x80 )) { +/* Not ready yet */ +if (entry->time_left <=0 ) { +dev_dbg (&I801_dev->dev,"SMBus Timeout!\n" ); + entry->result = -EIO ; } +return ; } -if (read_write ==I2C_SMBUS_WRITE ) { - len = data->block[0 ]; -if (len <1 ) - len =1 ; -if (len >32 ) - len =32 ; -outb_p (len,SMBHSTDAT0 ); -outb_p (data->block[1 ],SMBBLKDAT ); +i801_check_hststs (adap, entry, d); +if (d->i ==1 && entry->smbus.read_write ==I2C_SMBUS_READ ) { + d->len =inb_p (SMBHSTDAT0 ); +if (d->len <1 ) + d->len =1 ; +if (d->len >32 ) + d->len =32 ; + entry->smbus.data->block[0 ] = d->len; + } + +/* Retrieve/store value in SMBBLKDAT */ +if (entry->smbus.read_write ==I2C_SMBUS_READ ) + entry->smbus.data->block[d->i] =inb_p (SMBBLKDAT ); +if (entry->smbus.read_write ==I2C_SMBUS_WRITE && d->i+1 <= d->len) +outb_p (entry->smbus.data->block[d->i+1 ],SMBBLKDAT ); +if ((d->hststs &0x9e ) !=0x00 ) +outb_p (d->hststs,SMBHSTSTS );/* signals SMBBLKDAT ready */ + +if ((d->hststs = (0x1e &inb_p (SMBHSTSTS ))) !=0x00 ) { +dev_dbg (&I801_dev->dev, +"Bad status (%02x) at end of transaction\n" , + d->hststs); + } +dev_dbg (&I801_dev->dev,"Block (post %d): CNT=%02x, CMD=%02x, " +"ADD=%02x, DAT0=%02x, BLKDAT=%02x\n" , d->i, +inb_p (SMBHSTCNT ),inb_p (SMBHSTCMD ),inb_p (SMBHSTADD ), +inb_p (SMBHSTDAT0 ),inb_p (SMBBLKDAT )); + +if (entry->result) +return ; + + (d->i)++; +i801_block_next_byte (adap, entry, d); +} + +static void i801_block_start (struct i2c_adapter *adap, +struct i2c_op_q_entry *entry, +struct i801_i2c_data *d) +{ +if (entry->smbus.read_write ==I2C_SMBUS_WRITE ) { + d->len = entry->smbus.data->block[0 ]; +if (d->len <1 ) + d->len =1 ; +if (d->len >32 ) + d->len =32 ; +outb_p (d->len,SMBHSTDAT0 ); +outb_p (entry->smbus.data->block[1 ],SMBBLKDAT ); }else { - len =32 ;/* max for reads */ + d->len =32 ;/* max for reads */ } -if (isich4 && command !=I2C_SMBUS_I2C_BLOCK_DATA ) { +if (isich4 && entry->smbus.size !=I2C_SMBUS_I2C_BLOCK_DATA ) {/* set 32 byte buffer */ } -for (i =1 ; i <= len; i++) { -if (i == len && read_write ==I2C_SMBUS_READ ) - smbcmd =I801_BLOCK_LAST ; -else - smbcmd =I801_BLOCK_DATA ; -outb_p (smbcmd |ENABLE_INT9 ,SMBHSTCNT ); - -dev_dbg (&I801_dev->dev,"Block (pre %d): CNT=%02x, CMD=%02x, " -"ADD=%02x, DAT0=%02x, BLKDAT=%02x\n" , i, -inb_p (SMBHSTCNT ),inb_p (SMBHSTCMD ),inb_p (SMBHSTADD ), -inb_p (SMBHSTDAT0 ),inb_p (SMBBLKDAT )); - -/* Make sure the SMBus host is ready to start transmitting */ - temp =inb_p (SMBHSTSTS ); -if (i ==1 ) { -/* Erronenous conditions before transaction: -* Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */ - errmask=0x9f ; - }else { -/* Erronenous conditions during transaction: -* Failed, Bus_Err, Dev_Err, Intr */ - errmask=0x1e ; - } -if (temp & errmask) { -dev_dbg (&I801_dev->dev,"SMBus busy (%02x). " -"Resetting... \n" , temp); -outb_p (temp,SMBHSTSTS ); -if (((temp =inb_p (SMBHSTSTS )) & errmask) !=0x00 ) { -dev_err (&I801_dev->dev, -"Reset failed! (%02x)\n" , temp); - result =-1 ; - goto END; - } -if (i !=1 ) { -/* if die in middle of block transaction, fail */ - result =-1 ; - goto END; - } - } + d->i =1 ; +i801_block_next_byte (adap, entry, d); +} -if (i ==1 ) -outb_p (inb (SMBHSTCNT ) |I801_START ,SMBHSTCNT ); +/* General poll routine. Called periodically by the i2c code. */ +static void i801_poll (struct i2c_adapter *adap, +struct i2c_op_q_entry *entry, +unsigned int us_since_last_poll) +{ +struct i801_i2c_data *d = entry->data; -/* We will always wait for a fraction of a second! */ - timeout =0 ; -do { - temp =inb_p (SMBHSTSTS ); -msleep (1 ); - } -while ((!(temp &0x80 )) - && (timeout++ <MAX_TIMEOUT )); +dev_dbg (&I801_dev->dev,"Poll call for %p %p at %ld\n" , adap, entry, + jiffies); -/* If the SMBus is still busy, we give up */ -if (timeout >=MAX_TIMEOUT ) { - result =-1 ; -dev_dbg (&I801_dev->dev,"SMBus Timeout!\n" ); - } +if (!d) +/* The entry hasn't been started yet. */ +return ; -if (temp &0x10 ) { - result =-1 ; -dev_dbg (&I801_dev->dev, -"Error: Failed bus transaction\n" ); - }else if (temp &0x08 ) { - result =-1 ; -dev_err (&I801_dev->dev,"Bus collision!\n" ); - }else if (temp &0x04 ) { - result =-1 ; -dev_dbg (&I801_dev->dev,"Error: no response!\n" ); - } +if (d->finished) { +/* We delay an extra poll to keep the hardware happy. +Otherwise the hardware is not ready when we start +the next operation. */ +i2c_op_done (adap, entry); +return ; + } -if (i ==1 && read_write ==I2C_SMBUS_READ ) { - len =inb_p (SMBHSTDAT0 ); -if (len <1 ) - len =1 ; -if (len >32 ) - len =32 ; - data->block[0 ] = len; - } +/* Decrement timeout */ + entry->time_left -= us_since_last_poll; -/* Retrieve/store value in SMBBLKDAT */ -if (read_write ==I2C_SMBUS_READ ) - data->block[i] =inb_p (SMBBLKDAT ); -if (read_write ==I2C_SMBUS_WRITE && i+1 <= len) -outb_p (data->block[i+1 ],SMBBLKDAT ); -if ((temp &0x9e ) !=0x00 ) -outb_p (temp,SMBHSTSTS );/* signals SMBBLKDAT ready */ - -if ((temp = (0x1e &inb_p (SMBHSTSTS ))) !=0x00 ) { -dev_dbg (&I801_dev->dev, -"Bad status (%02x) at end of transaction\n" , - temp); - } -dev_dbg (&I801_dev->dev,"Block (post %d): CNT=%02x, CMD=%02x, " -"ADD=%02x, DAT0=%02x, BLKDAT=%02x\n" , i, -inb_p (SMBHSTCNT ),inb_p (SMBHSTCMD ),inb_p (SMBHSTADD ), -inb_p (SMBHSTDAT0 ),inb_p (SMBBLKDAT )); +/* Wait a jiffie normally. */ + entry->call_again_us =RETRY_TIME_US ; -if (result <0 ) - goto END; +if (d->block) { +if (d->wait_intr) { +i801_block_poll_wait_intr (adap, entry, d); + }else { +i801_block_poll (adap, entry, d); + } +if (entry->result <0 ) +/* Error, finish the transaction */ +i801_block_finish (adap, entry, d); + }else { +i801_transaction_poll (adap, entry, d); +if (entry->result <0 ) +/* Error, finish the transaction */ +i801_finish (adap, entry, d); } +} -#ifdef HAVE_PEC -if (isich4 && command ==I2C_SMBUS_BLOCK_DATA_PEC ) { -/* wait for INTR bit as advised by Intel */ - timeout =0 ; -do { - temp =inb_p (SMBHSTSTS ); -msleep (1 ); - }while ((!(temp &0x02 )) - && (timeout++ <MAX_TIMEOUT )); +/* Start a general SMBUS transaction on the i801. Figure out what +kind of transaction it is, set it up, and start it. */ +static void i801_start (struct i2c_adapter *adap, +struct i2c_op_q_entry *entry) +{ +struct i801_i2c_data *d = adap->algo_data; -if (timeout >=MAX_TIMEOUT ) { -dev_dbg (&I801_dev->dev,"PEC Timeout!\n" ); +dev_dbg (&I801_dev->dev,"start call for %p %p at %ld\n" , adap, entry, + jiffies); + +if (entry->smbus.size ==I2C_SMBUS_I2C_BLOCK_DATA ) { +if (entry->smbus.read_write ==I2C_SMBUS_WRITE ) { +/* set I2C_EN bit in configuration register */ +pci_read_config_byte (I801_dev,SMBHSTCFG , &d->hostc); +pci_write_config_byte (I801_dev,SMBHSTCFG , + d->hostc |SMBHSTCFG_I2C_EN ); + }else { +dev_err (&I801_dev->dev, +"I2C_SMBUS_I2C_BLOCK_READ not DB!\n" ); + entry->result = -EINVAL ; +return ; } -outb_p (temp,SMBHSTSTS ); - } -#endif - result =0 ; -END: -if (command ==I2C_SMBUS_I2C_BLOCK_DATA ) { -/* restore saved configuration register value */ -pci_write_config_byte (I801_dev,SMBHSTCFG , hostc); } -return result; -} -/* Return -1 on error. */ -static s32 i801_access (struct i2c_adapter * adap,u16 addr, -unsigned short flags,char read_write,u8 command, -int size,union i2c_smbus_data * data) -{ -int hwpec =0 ; -int block =0 ; -int ret, xact =0 ; + d->block =0 ; + d->hwpec =0 ; + d->xact =0 ; + d->wait_intr =0 ; + d->finished =0 ;#ifdef HAVE_PEC -if (isich4) - hwpec = (flags &I2C_CLIENT_PEC ) !=0 ; +if (isich4) + d->hwpec = (entry->smbus.flags &I2C_CLIENT_PEC ) !=0 ;#endif -switch (size) { +switch (entry->smbus.size) {case I2C_SMBUS_QUICK : -outb_p (((addr &0x7f ) <<1 ) | (read_write &0x01 ), +outb_p (((entry->smbus.addr &0x7f ) <<1 ) + | (entry->smbus.read_write &0x01 ),SMBHSTADD ); - xact =I801_QUICK ; + d->xact =I801_QUICK ;break ;case I2C_SMBUS_BYTE : -outb_p (((addr &0x7f ) <<1 ) | (read_write &0x01 ), +outb_p (((entry->smbus.addr &0x7f ) <<1 ) + | (entry->smbus.read_write &0x01 ),SMBHSTADD ); -if (read_write ==I2C_SMBUS_WRITE ) -outb_p (command,SMBHSTCMD ); - xact =I801_BYTE ; +if (entry->smbus.read_write ==I2C_SMBUS_WRITE ) +outb_p (entry->smbus.command,SMBHSTCMD ); + d->xact =I801_BYTE ;break ;case I2C_SMBUS_BYTE_DATA : -outb_p (((addr &0x7f ) <<1 ) | (read_write &0x01 ), +outb_p (((entry->smbus.addr &0x7f ) <<1 ) + | (entry->smbus.read_write &0x01 ),SMBHSTADD ); -outb_p (command,SMBHSTCMD ); -if (read_write ==I2C_SMBUS_WRITE ) -outb_p (data->byte,SMBHSTDAT0 ); - xact =I801_BYTE_DATA ; +outb_p (entry->smbus.command,SMBHSTCMD ); +if (entry->smbus.read_write ==I2C_SMBUS_WRITE ) +outb_p (entry->smbus.data->byte,SMBHSTDAT0 ); + d->xact =I801_BYTE_DATA ;break ;case I2C_SMBUS_WORD_DATA : -outb_p (((addr &0x7f ) <<1 ) | (read_write &0x01 ), +outb_p (((entry->smbus.addr &0x7f ) <<1 ) + | (entry->smbus.read_write &0x01 ),SMBHSTADD ); -outb_p (command,SMBHSTCMD ); -if (read_write ==I2C_SMBUS_WRITE ) { -outb_p (data->word &0xff ,SMBHSTDAT0 ); -outb_p ((data->word &0xff00 ) >>8 ,SMBHSTDAT1 ); +outb_p (entry->smbus.command,SMBHSTCMD ); +if (entry->smbus.read_write ==I2C_SMBUS_WRITE ) { +outb_p (entry->smbus.data->word &0xff ,SMBHSTDAT0 ); +outb_p ((entry->smbus.data->word &0xff00 ) >>8 , +SMBHSTDAT1 ); } - xact =I801_WORD_DATA ; + d->xact =I801_WORD_DATA ;break ;case I2C_SMBUS_BLOCK_DATA :case I2C_SMBUS_I2C_BLOCK_DATA :#ifdef HAVE_PEC case I2C_SMBUS_BLOCK_DATA_PEC : -if (hwpec && size ==I2C_SMBUS_BLOCK_DATA ) - size =I2C_SMBUS_BLOCK_DATA_PEC ; +if (d->hwpec && entry->smbus.size ==I2C_SMBUS_BLOCK_DATA ) + entry->smbus.size =I2C_SMBUS_BLOCK_DATA_PEC ;#endif -outb_p (((addr &0x7f ) <<1 ) | (read_write &0x01 ), +outb_p (((entry->smbus.addr &0x7f ) <<1 ) + | (entry->smbus.read_write &0x01 ),SMBHSTADD ); -outb_p (command,SMBHSTCMD ); - block =1 ; +outb_p (entry->smbus.command,SMBHSTCMD ); + d->block =1 ;break ;case I2C_SMBUS_PROC_CALL :default : -dev_err (&I801_dev->dev,"Unsupported transaction %d\n" , size); -return -1 ; +dev_err (&I801_dev->dev,"Unsupported transaction %d\n" , + entry->smbus.size); + entry->result = -EINVAL ; +return ; }#ifdef HAVE_PEC -if (isich4 && hwpec) { -if (size !=I2C_SMBUS_QUICK && - size !=I2C_SMBUS_I2C_BLOCK_DATA ) +if (isich4 && d->hwpec) { +if (entry->smbus.size !=I2C_SMBUS_QUICK && + entry->smbus.size !=I2C_SMBUS_I2C_BLOCK_DATA )outb_p (1 ,SMBAUXCTL );/* enable HW PEC */ }#endif -if (block) - ret =i801_block_transaction (data, read_write, size); -else { -outb_p (xact |ENABLE_INT9 ,SMBHSTCNT ); - ret =i801_transaction (); +if (d->block) { +i801_block_start (adap, entry, d); +if (entry->result <0 ) +/* Error, finish the transaction */ +i801_block_finish (adap, entry, d); + }else { +outb_p (d->xact |ENABLE_INT9 ,SMBHSTCNT ); +i801_transaction_start (adap, entry, d); +if (entry->result <0 ) +/* Error, finish the transaction */ +i801_finish (adap, entry, d); } -#ifdef HAVE_PEC -if (isich4 && hwpec) { -if (size !=I2C_SMBUS_QUICK && - size !=I2C_SMBUS_I2C_BLOCK_DATA ) -outb_p (0 ,SMBAUXCTL ); - } +/* Wait extra long here, we want at least 2 ticks to guarantee +we wait >= 1 tick. But we want to wait at least 100us no +matter what. */ +#if (1000000 /HZ ) <100 + entry->call_again_us =200 ; +#else + entry->call_again_us = (1000000 /HZ ) *2 ;#endif + entry->time_left =MAX_TIMEOUT_US ; -if (block) -return ret; -if (ret) -return -1 ; -if ((read_write ==I2C_SMBUS_WRITE ) || (xact ==I801_QUICK )) -return 0 ; - -switch (xact &0x7f ) { -case I801_BYTE :/* Result put in SMBHSTDAT0 */ -case I801_BYTE_DATA : - data->byte =inb_p (SMBHSTDAT0 ); -break ; -case I801_WORD_DATA : - data->word =inb_p (SMBHSTDAT0 ) + (inb_p (SMBHSTDAT1 ) <<8 ); -break ; - } -return 0 ; +if (d->finished) +i2c_op_done (adap, entry); +else + entry->data = d; }
@@ -537,7 +668,8 @@static struct i2c_algorithm smbus_algorithm = { .name ="Non-I2C SMBus adapter" , .id =I2C_ALGO_SMBUS , - .smbus_xfer = i801_access, + .smbus_start = i801_start, + .poll = i801_poll, .functionality = i801_func, };
@@ -545,6 +677,7 @@ .owner = THIS_MODULE, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, + .algo_data = &i801_data, .name = "unset", };
@@ -563,7 +696,8 @@MODULE_DEVICE_TABLE (pci, i801_ids); -static int __devinit i801_probe (struct pci_dev *dev,const struct pci_device_id *id) +static int __devinit i801_probe (struct pci_dev *dev, +const struct pci_device_id *id) {if (i801_setup (dev)) {