Example #1
0
static int i801_block_transaction_by_block(struct i801_priv *priv,
					   union i2c_smbus_data *data,
					   char read_write, int hwpec)
{
	int i, len;
	int status;

	inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */

	/* Use 32-byte buffer to process this transaction */
	if (read_write == I2C_SMBUS_WRITE) {
		len = data->block[0];
		outb_p(len, SMBHSTDAT0(priv));
		for (i = 0; i < len; i++)
			outb_p(data->block[i+1], SMBBLKDAT(priv));
	}

	status = i801_transaction(priv, I801_BLOCK_DATA |
				  (hwpec ? SMBHSTCNT_PEC_EN : 0));
	if (status)
		return status;

	if (read_write == I2C_SMBUS_READ) {
		len = inb_p(SMBHSTDAT0(priv));
		if (len < 1 || len > I2C_SMBUS_BLOCK_MAX)
			return -EPROTO;

		data->block[0] = len;
		for (i = 0; i < len; i++)
			data->block[i + 1] = inb_p(SMBBLKDAT(priv));
	}
	return 0;
}
Example #2
0
static void i801_isr_byte_done(struct i801_priv *priv)
{
	if (priv->is_read) {
		/* For SMBus block reads, length is received with first byte */
		if (((priv->cmd & 0x1c) == I801_BLOCK_DATA) &&
		    (priv->count == 0)) {
			priv->len = inb_p(SMBHSTDAT0(priv));
			if (priv->len < 1 || priv->len > I2C_SMBUS_BLOCK_MAX) {
				dev_err(&priv->pci_dev->dev,
					"Illegal SMBus block read size %d\n",
					priv->len);
				/* FIXME: Recover */
				priv->len = I2C_SMBUS_BLOCK_MAX;
			} else {
				dev_dbg(&priv->pci_dev->dev,
					"SMBus block read size is %d\n",
					priv->len);
			}
			priv->data[-1] = priv->len;
		}

		/* Read next byte */
		if (priv->count < priv->len)
			priv->data[priv->count++] = inb(SMBBLKDAT(priv));
		else
			dev_dbg(&priv->pci_dev->dev,
				"Discarding extra byte on block read\n");

		/* Set LAST_BYTE for last byte of read transaction */
		if (priv->count == priv->len - 1)
			outb_p(priv->cmd | SMBHSTCNT_LAST_BYTE,
			       SMBHSTCNT(priv));
	} else if (priv->count < priv->len - 1) {
		/* Write next byte, except for IRQ after last byte */
		outb_p(priv->data[++priv->count], SMBBLKDAT(priv));
	}

	/* Clear BYTE_DONE to continue with next byte */
	outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv));
}
Example #3
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;
}