[PATCH] Updates for the i801 driver to support the I2C non-blocking interface

From: Corey Minyard (minyard_at_acm.org)
Date: 01/28/05

  • Next message: Andi Kleen: "Re: [PATCH] Add CONFIG_X86_APIC_OFF for i386/UP"
    Date:	Fri, 28 Jan 2005 09:11:47 -0600
    To: Bukie Mabayoje <bukiemab@gte.net>
    
    
    

    Here's the changes required for the i801 driver. See the previous post
    for the patch to add a non-blocking interface to the I2C driver.

    Like the core I2C changes, this is mostly breaking the functions into
    smaller pieces and calling them from the appropriate places.

    -Corey

    
    

    Index: linux-2.6.11-rc2/drivers/i2c/busses/i2c-i801.c
    ===================================================================
    --- linux-2.6.11-rc2.orig/drivers/i2c/busses/i2c-i801.c 2005-01-27 13:09:12.000000000 -0600
    +++ linux-2.6.11-rc2/drivers/i2c/busses/i2c-i801.c 2005-01-27 13:46:23.000000000 -0600
    @@ -79,7 +79,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 +106,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 +147,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 +191,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 +285,347 @@
     
             /* 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.command == 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.command == 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 after a timeout. 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;
    + 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 (command == I2C_SMBUS_I2C_BLOCK_DATA) {
    - if (read_write == I2C_SMBUS_WRITE) {
    + i801_check_hststs(adap, entry, d);
    + if (entry->result)
    + return;
    +
    + 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));
    +
    + 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.command == 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, &hostc);
    + pci_read_config_byte(I801_dev, SMBHSTCFG, &d->hostc);
                             pci_write_config_byte(I801_dev, SMBHSTCFG,
    - hostc | SMBHSTCFG_I2C_EN);
    + d->hostc | SMBHSTCFG_I2C_EN);
                     } else {
                             dev_err(&I801_dev->dev,
                                     "I2C_SMBUS_I2C_BLOCK_READ not DB!\n");
    - return -1;
    + entry->result = -EINVAL;
    + 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);
    + 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.command != 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");
    - }
    + /* Decrement timeout */
    + entry->time_left -= us_since_last_poll;
     
    - 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;
    - }
    + /* Wait a jiffie normally. */
    + entry->call_again_us = RETRY_TIME_US;
     
    - /* 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);
    + if (d->block) {
    + if (d->wait_intr) {
    + i801_block_poll_wait_intr(adap, entry, d);
    + } else {
    + i801_block_poll(adap, entry, d);
                     }
    - 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));
    -
    - if (result < 0)
    - goto END;
    + 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));
    -
    - if (timeout >= MAX_TIMEOUT) {
    - dev_dbg(&I801_dev->dev, "PEC Timeout!\n");
    - }
    - 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;
    + if (d->finished)
    + i2c_op_done(adap, entry);
     }
     
    -/* 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)
    +/* 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)
     {
    - int hwpec = 0;
    - int block = 0;
    - int ret, xact = 0;
    + struct i801_i2c_data *d = adap->algo_data;
    +
    + 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();
    - }
    -
    -#ifdef HAVE_PEC
    - if(isich4 && hwpec) {
    - if(size != I2C_SMBUS_QUICK &&
    - size != I2C_SMBUS_I2C_BLOCK_DATA)
    - outb_p(0, SMBAUXCTL);
    + 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);
             }
    -#endif
     
    - if(block)
    - return ret;
    - if(ret)
    - return -1;
    - if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK))
    - return 0;
    + entry->call_again_us = RETRY_TIME_US;
    + entry->time_left = MAX_TIMEOUT_US;
     
    - 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 +645,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 +654,7 @@
             .owner = THIS_MODULE,
             .class = I2C_CLASS_HWMON,
             .algo = &smbus_algorithm,
    + .algo_data = &i801_data,
             .name = "unset",
     };
     
    @@ -563,7 +673,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)) {

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/


  • Next message: Andi Kleen: "Re: [PATCH] Add CONFIG_X86_APIC_OFF for i386/UP"

    Relevant Pages