static int i801_transaction(struct i801_priv *priv, int xact) { int status; int result; const struct i2c_adapter *adap = &priv->adapter; result = i801_check_pre(priv); if (result < 0) return result; if (priv->features & FEATURE_IRQ) { outb_p(xact | SMBHSTCNT_INTREN | SMBHSTCNT_START, SMBHSTCNT(priv)); result = wait_event_timeout(priv->waitq, (status = priv->status), adap->timeout); if (!result) { status = -ETIMEDOUT; dev_warn(&priv->pci_dev->dev, "Timeout waiting for interrupt!\n"); } priv->status = 0; return i801_check_post(priv, status); } /* the current contents of SMBHSTCNT can be overwritten, since PEC, * SMBSCMD are passed in xact */ outb_p(xact | SMBHSTCNT_START, SMBHSTCNT(priv)); status = i801_wait_intr(priv); return i801_check_post(priv, status); }
static int i801_transaction(struct i801_priv *priv, int xact) { int status; int result; int timeout = 0; result = i801_check_pre(priv); if (result < 0) return result; /* the current contents of SMBHSTCNT can be overwritten, since PEC, * INTREN, SMBSCMD are passed in xact */ outb_p(xact | I801_START, SMBHSTCNT(priv)); /* We will always wait for a fraction of a second! */ do { msleep(1); status = inb_p(SMBHSTSTS(priv)); } while ((status & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_TIMEOUT)); result = i801_check_post(priv, status, timeout > MAX_TIMEOUT); if (result < 0) return result; outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv)); return 0; }
static int i801_transaction(struct i801_priv *priv, int xact) { int status; int result; result = i801_check_pre(priv); if (result < 0) return result; if (priv->features & FEATURE_IRQ) { outb_p(xact | SMBHSTCNT_INTREN | SMBHSTCNT_START, SMBHSTCNT(priv)); wait_event(priv->waitq, (status = priv->status)); priv->status = 0; return i801_check_post(priv, status); } /* the current contents of SMBHSTCNT can be overwritten, since PEC, * SMBSCMD are passed in xact */ outb_p(xact | SMBHSTCNT_START, SMBHSTCNT(priv)); status = i801_wait_intr(priv); return i801_check_post(priv, status); }
/* * For "byte-by-byte" block transactions: * I2C write uses cmd=I801_BLOCK_DATA, I2C_EN=1 * I2C read uses cmd=I801_I2C_BLOCK_DATA */ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, union i2c_smbus_data *data, char read_write, int command, int hwpec) { int i, len; int smbcmd; int status; int result; const struct i2c_adapter *adap = &priv->adapter; result = i801_check_pre(priv); if (result < 0) return result; len = data->block[0]; if (read_write == I2C_SMBUS_WRITE) { outb_p(len, SMBHSTDAT0(priv)); outb_p(data->block[1], SMBBLKDAT(priv)); } if (command == I2C_SMBUS_I2C_BLOCK_DATA && read_write == I2C_SMBUS_READ) smbcmd = I801_I2C_BLOCK_DATA; else smbcmd = I801_BLOCK_DATA; if (priv->features & FEATURE_IRQ) { priv->is_read = (read_write == I2C_SMBUS_READ); if (len == 1 && priv->is_read) smbcmd |= SMBHSTCNT_LAST_BYTE; priv->cmd = smbcmd | SMBHSTCNT_INTREN; priv->len = len; priv->count = 0; priv->data = &data->block[1]; outb_p(priv->cmd | SMBHSTCNT_START, SMBHSTCNT(priv)); result = wait_event_timeout(priv->waitq, (status = priv->status), adap->timeout); if (!result) { status = -ETIMEDOUT; dev_warn(&priv->pci_dev->dev, "Timeout waiting for interrupt!\n"); } priv->status = 0; return i801_check_post(priv, status); } for (i = 1; i <= len; i++) { if (i == len && read_write == I2C_SMBUS_READ) smbcmd |= SMBHSTCNT_LAST_BYTE; outb_p(smbcmd, SMBHSTCNT(priv)); if (i == 1) outb_p(inb(SMBHSTCNT(priv)) | SMBHSTCNT_START, SMBHSTCNT(priv)); status = i801_wait_byte_done(priv); if (status) goto exit; if (i == 1 && read_write == I2C_SMBUS_READ && command != I2C_SMBUS_I2C_BLOCK_DATA) { len = inb_p(SMBHSTDAT0(priv)); if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) { dev_err(&priv->pci_dev->dev, "Illegal SMBus block read size %d\n", len); /* Recover */ while (inb_p(SMBHSTSTS(priv)) & SMBHSTSTS_HOST_BUSY) outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv)); outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv)); return -EPROTO; } data->block[0] = len; } /* Retrieve/store value in SMBBLKDAT */ if (read_write == I2C_SMBUS_READ) data->block[i] = inb_p(SMBBLKDAT(priv)); if (read_write == I2C_SMBUS_WRITE && i+1 <= len) outb_p(data->block[i+1], SMBBLKDAT(priv)); /* signals SMBBLKDAT ready */ outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv)); } status = i801_wait_intr(priv); exit: return i801_check_post(priv, status); }
static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, union i2c_smbus_data *data, char read_write, int command, int hwpec) { int i, len; int smbcmd; int status; int result; int timeout; result = i801_check_pre(priv); if (result < 0) return result; len = data->block[0]; if (read_write == I2C_SMBUS_WRITE) { outb_p(len, SMBHSTDAT0(priv)); outb_p(data->block[1], SMBBLKDAT(priv)); } for (i = 1; i <= len; i++) { if (i == len && read_write == I2C_SMBUS_READ) { if (command == I2C_SMBUS_I2C_BLOCK_DATA) smbcmd = I801_I2C_BLOCK_LAST; else smbcmd = I801_BLOCK_LAST; } else { if (command == I2C_SMBUS_I2C_BLOCK_DATA && read_write == I2C_SMBUS_READ) smbcmd = I801_I2C_BLOCK_DATA; else smbcmd = I801_BLOCK_DATA; } outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT(priv)); if (i == 1) outb_p(inb(SMBHSTCNT(priv)) | I801_START, SMBHSTCNT(priv)); /* We will always wait for a fraction of a second! */ timeout = 0; do { msleep(1); status = inb_p(SMBHSTSTS(priv)); } while ((!(status & SMBHSTSTS_BYTE_DONE)) && (timeout++ < MAX_TIMEOUT)); result = i801_check_post(priv, status, timeout > MAX_TIMEOUT); if (result < 0) return result; if (i == 1 && read_write == I2C_SMBUS_READ && command != I2C_SMBUS_I2C_BLOCK_DATA) { len = inb_p(SMBHSTDAT0(priv)); if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) { dev_err(&priv->pci_dev->dev, "Illegal SMBus block read size %d\n", len); /* Recover */ while (inb_p(SMBHSTSTS(priv)) & SMBHSTSTS_HOST_BUSY) outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv)); outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv)); return -EPROTO; } data->block[0] = len; } /* Retrieve/store value in SMBBLKDAT */ if (read_write == I2C_SMBUS_READ) data->block[i] = inb_p(SMBBLKDAT(priv)); if (read_write == I2C_SMBUS_WRITE && i+1 <= len) outb_p(data->block[i+1], SMBBLKDAT(priv)); /* signals SMBBLKDAT ready */ outb_p(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR, SMBHSTSTS(priv)); } return 0; }