Exemplo n.º 1
0
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);
}
Exemplo n.º 4
0
/*
 * 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;
}