static int sis96x_transaction(int size)
{
	int temp;
	int result = 0;
	int timeout = 0;

	dev_dbg(&sis96x_adapter.dev, "SMBus transaction %d\n", size);

	
	if (((temp = sis96x_read(SMB_CNT)) & 0x03) != 0x00) {

		dev_dbg(&sis96x_adapter.dev, "SMBus busy (0x%02x). "
			"Resetting...\n", temp);

		
		sis96x_write(SMB_HOST_CNT, 0x20);

		
		if (((temp = sis96x_read(SMB_CNT)) & 0x03) != 0x00) {
			dev_dbg(&sis96x_adapter.dev, "Failed (0x%02x)\n", temp);
			return -EBUSY;
		} else {
			dev_dbg(&sis96x_adapter.dev, "Successful\n");
		}
	}

	
	sis96x_write(SMB_CNT, 0x20);

	
	temp = sis96x_read(SMB_STS);
	sis96x_write(SMB_STS, temp & 0x1e);

	
	sis96x_write(SMB_HOST_CNT, 0x10 | (size & 0x07));

	
	do {
		msleep(1);
		temp = sis96x_read(SMB_STS);
	} while (!(temp & 0x0e) && (timeout++ < MAX_TIMEOUT));

	
	if (timeout > MAX_TIMEOUT) {
		dev_dbg(&sis96x_adapter.dev, "SMBus Timeout! (0x%02x)\n", temp);
		result = -ETIMEDOUT;
	}

	
	if (temp & 0x02) {
		dev_dbg(&sis96x_adapter.dev, "Failed bus transaction!\n");
		result = -ENXIO;
	}

	
	if (temp & 0x04) {
		dev_dbg(&sis96x_adapter.dev, "Bus collision!\n");
		result = -EIO;
	}

	
	sis96x_write(SMB_STS, temp);
	if ((temp = sis96x_read(SMB_STS))) {
		dev_dbg(&sis96x_adapter.dev, "Failed reset at "
			"end of transaction! (0x%02x)\n", temp);
	}

	return result;
}
Example #2
0
/* Execute a SMBus transaction.
   int size is from SIS96x_QUICK to SIS96x_BLOCK_DATA
 */
static int sis96x_transaction(int size)
{
	int temp;
	int result = 0;
	int timeout = 0;

	dev_dbg(&sis96x_adapter.dev, "SMBus transaction %d\n", size);

	/* Make sure the SMBus host is ready to start transmitting */
	if (((temp = sis96x_read(SMB_CNT)) & 0x03) != 0x00) {

		dev_dbg(&sis96x_adapter.dev, "SMBus busy (0x%02x). "
			"Resetting...\n", temp);

		/* kill the transaction */
		sis96x_write(SMB_HOST_CNT, 0x20);

		/* check it again */
		if (((temp = sis96x_read(SMB_CNT)) & 0x03) != 0x00) {
			dev_dbg(&sis96x_adapter.dev, "Failed (0x%02x)\n", temp);
			return -EBUSY;
		} else {
			dev_dbg(&sis96x_adapter.dev, "Successful\n");
		}
	}

	/* Turn off timeout interrupts, set fast host clock */
	sis96x_write(SMB_CNT, 0x20);

	/* clear all (sticky) status flags */
	temp = sis96x_read(SMB_STS);
	sis96x_write(SMB_STS, temp & 0x1e);

	/* start the transaction by setting bit 4 and size bits */
	sis96x_write(SMB_HOST_CNT, 0x10 | (size & 0x07));

	/* We will always wait for a fraction of a second! */
	do {
		msleep(1);
		temp = sis96x_read(SMB_STS);
	} while (!(temp & 0x0e) && (timeout++ < MAX_TIMEOUT));

	/* If the SMBus is still busy, we give up */
	if (timeout > MAX_TIMEOUT) {
		dev_dbg(&sis96x_adapter.dev, "SMBus Timeout! (0x%02x)\n", temp);
		result = -ETIMEDOUT;
	}

	/* device error - probably missing ACK */
	if (temp & 0x02) {
		dev_dbg(&sis96x_adapter.dev, "Failed bus transaction!\n");
		result = -ENXIO;
	}

	/* bus collision */
	if (temp & 0x04) {
		dev_dbg(&sis96x_adapter.dev, "Bus collision!\n");
		result = -EIO;
	}

	/* Finish up by resetting the bus */
	sis96x_write(SMB_STS, temp);
	if ((temp = sis96x_read(SMB_STS))) {
		dev_dbg(&sis96x_adapter.dev, "Failed reset at "
			"end of transaction! (0x%02x)\n", temp);
	}

	return result;
}