Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 316352
b: refs/heads/master
c: 6cad93c
h: refs/heads/master
v: v3
  • Loading branch information
Jean Delvare authored and Jean Delvare committed Jul 24, 2012
1 parent 3a48e5f commit 4c0ca83
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 56 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 37af871112e1dec1e39dfac782f0be5926be1c88
refs/heads/master: 6cad93c4bbd62ecfa2e1b3a95c1ac4f6f27764c7
108 changes: 53 additions & 55 deletions trunk/drivers/i2c/busses/i2c-i801.c
Original file line number Diff line number Diff line change
Expand Up @@ -206,13 +206,17 @@ static int i801_check_pre(struct i801_priv *priv)
return 0;
}

/* Convert the status register to an error code, and clear it. */
static int i801_check_post(struct i801_priv *priv, int status, int timeout)
/*
* Convert the status register to an error code, and clear it.
* Note that status only contains the bits we want to clear, not the
* actual register value.
*/
static int i801_check_post(struct i801_priv *priv, int status)
{
int result = 0;

/* If the SMBus is still busy, we give up */
if (timeout) {
if (unlikely(status < 0)) {
dev_err(&priv->pci_dev->dev, "Transaction timeout\n");
/* try to stop the current command */
dev_dbg(&priv->pci_dev->dev, "Terminating the current operation\n");
Expand Down Expand Up @@ -245,64 +249,68 @@ static int i801_check_post(struct i801_priv *priv, int status, int timeout)
dev_dbg(&priv->pci_dev->dev, "Lost arbitration\n");
}

if (result) {
/* Clear error flags */
outb_p(status & STATUS_FLAGS, SMBHSTSTS(priv));
status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS;
if (status) {
dev_warn(&priv->pci_dev->dev, "Failed clearing status "
"flags at end of transaction (%02x)\n",
status);
}
}
/* Clear status flags except BYTE_DONE, to be cleared by caller */
outb_p(status, SMBHSTSTS(priv));

return result;
}

static int i801_transaction(struct i801_priv *priv, int xact)
/* Wait for BUSY being cleared and either INTR or an error flag being set */
static int i801_wait_intr(struct i801_priv *priv)
{
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,
* SMBSCMD are passed in xact */
outb_p(xact | SMBHSTCNT_START, SMBHSTCNT(priv));
int status;

/* We will always wait for a fraction of a second! */
do {
usleep_range(250, 500);
status = inb_p(SMBHSTSTS(priv));
} while ((status & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_RETRIES));
} while (((status & SMBHSTSTS_HOST_BUSY) ||
!(status & (STATUS_ERROR_FLAGS | SMBHSTSTS_INTR))) &&
(timeout++ < MAX_RETRIES));

result = i801_check_post(priv, status, timeout > MAX_RETRIES);
if (result < 0)
return result;

outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv));
return 0;
if (timeout > MAX_RETRIES) {
dev_dbg(&priv->pci_dev->dev, "INTR Timeout!\n");
return -ETIMEDOUT;
}
return status & (STATUS_ERROR_FLAGS | SMBHSTSTS_INTR);
}

/* wait for INTR bit as advised by Intel */
static void i801_wait_hwpec(struct i801_priv *priv)
/* Wait for either BYTE_DONE or an error flag being set */
static int i801_wait_byte_done(struct i801_priv *priv)
{
int timeout = 0;
int status;

/* We will always wait for a fraction of a second! */
do {
usleep_range(250, 500);
status = inb_p(SMBHSTSTS(priv));
} while ((!(status & SMBHSTSTS_INTR))
&& (timeout++ < MAX_RETRIES));
} while (!(status & (STATUS_ERROR_FLAGS | SMBHSTSTS_BYTE_DONE)) &&
(timeout++ < MAX_RETRIES));

if (timeout > MAX_RETRIES) {
dev_dbg(&priv->pci_dev->dev, "BYTE_DONE Timeout!\n");
return -ETIMEDOUT;
}
return status & STATUS_ERROR_FLAGS;
}

static int i801_transaction(struct i801_priv *priv, int xact)
{
int status;
int result;

if (timeout > MAX_RETRIES)
dev_dbg(&priv->pci_dev->dev, "PEC Timeout!\n");
result = i801_check_pre(priv);
if (result < 0)
return result;

outb_p(status & STATUS_FLAGS, SMBHSTSTS(priv));
/* 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_block_transaction_by_block(struct i801_priv *priv,
Expand Down Expand Up @@ -353,7 +361,6 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
int smbcmd;
int status;
int result;
int timeout;

result = i801_check_pre(priv);
if (result < 0)
Expand Down Expand Up @@ -381,17 +388,9 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
outb_p(inb(SMBHSTCNT(priv)) | SMBHSTCNT_START,
SMBHSTCNT(priv));

/* We will always wait for a fraction of a second! */
timeout = 0;
do {
usleep_range(250, 500);
status = inb_p(SMBHSTSTS(priv));
} while (!(status & (SMBHSTSTS_BYTE_DONE | STATUS_ERROR_FLAGS))
&& (timeout++ < MAX_RETRIES));

result = i801_check_post(priv, status, timeout > MAX_RETRIES);
if (result < 0)
return result;
status = i801_wait_byte_done(priv);
if (status)
goto exit;

if (i == 1 && read_write == I2C_SMBUS_READ
&& command != I2C_SMBUS_I2C_BLOCK_DATA) {
Expand All @@ -418,10 +417,12 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
outb_p(data->block[i+1], SMBBLKDAT(priv));

/* signals SMBBLKDAT ready */
outb_p(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR, SMBHSTSTS(priv));
outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv));
}

return 0;
status = i801_wait_intr(priv);
exit:
return i801_check_post(priv, status);
}

static int i801_set_block_buffer_mode(struct i801_priv *priv)
Expand Down Expand Up @@ -476,9 +477,6 @@ static int i801_block_transaction(struct i801_priv *priv,
read_write,
command, hwpec);

if (result == 0 && hwpec)
i801_wait_hwpec(priv);

if (command == I2C_SMBUS_I2C_BLOCK_DATA
&& read_write == I2C_SMBUS_WRITE) {
/* restore saved configuration register value */
Expand Down

0 comments on commit 4c0ca83

Please sign in to comment.