static int saa716x_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
{
	struct saa716x_i2c *i2c		= i2c_get_adapdata(adapter);
	struct saa716x_dev *saa716x	= i2c->saa716x;

	u32 DEV = SAA716x_I2C_BUS(i2c->i2c_dev);
	int i, j, err = 0;
	int t;
	u32 data;

	mutex_lock(&i2c->i2c_lock);

	for (t = 0; t < 3; t++) {
		for (i = 0; i < num; i++) {
			/* first write START width I2C address */
			data = (msgs[i].addr << 1) | I2C_START_BIT;
			if (msgs[i].flags & I2C_M_RD)
				data |= 1;
			err = saa716x_i2c_send(i2c, DEV, data);
			if (err < 0) {
				dprintk(SAA716x_ERROR, 1, "Address write failed");
				err = -EIO;
				goto retry;
			}
			/* now read or write the data */
			for (j = 0; j < msgs[i].len; j++) {
				if (msgs[i].flags & I2C_M_RD)
					data = 0x00; /* dummy write for reading */
				else {
					data = msgs[i].buf[j];
				}
				if (i == (num - 1) && j == (msgs[i].len - 1))
					data |= I2C_STOP_BIT;
				err = saa716x_i2c_send(i2c, DEV, data);
				if (err < 0) {
					dprintk(SAA716x_ERROR, 1, "Data send failed");
					err = -EIO;
					goto retry;
				}
				if (msgs[i].flags & I2C_M_RD) {
					err = saa716x_i2c_recv(i2c, DEV, &data);
					if (err < 0) {
						dprintk(SAA716x_ERROR, 1, "Data receive failed");
						err = -EIO;
						goto retry;
					}
					msgs[i].buf[j] = data;
				}
			}
		}
		break;
retry:
		dprintk(SAA716x_INFO, 1, "Error in Transfer, try %d", t);
		err = saa716x_i2c_hwinit(i2c, DEV);
		if (err < 0) {
			dprintk(SAA716x_ERROR, 1, "Error Reinit");
			err = -EIO;
			goto bail_out;
		}
	}

	mutex_unlock(&i2c->i2c_lock);
	if (t == 3)
		return -EIO;
	else
		return num;

bail_out:
	dprintk(SAA716x_ERROR, 1, "ERROR: Bailing out <%d>", err);
	mutex_unlock(&i2c->i2c_lock);
	return err;
}
示例#2
0
static int saa716x_i2c_read_msg(struct saa716x_i2c *i2c, u32 I2C_DEV,
				u16 addr, u8 *buf, u16 len, u8 add_stop)
{
	struct saa716x_dev *saa716x = i2c->saa716x;
	u32 data;
	int err;
	int i;
	int bytes;

	saa716x_i2c_irq_start(i2c, I2C_DEV);

	/* first write START with I2C address */
	data = I2C_START_BIT | (addr << 1) | 1;
	dprintk(SAA716x_DEBUG, 1, "length=%d Addr:0x%02x", len, data);
	err = saa716x_i2c_send(i2c, I2C_DEV, data);
	if (err < 0) {
		dprintk(SAA716x_ERROR, 1, "Address write failed");
		goto exit;
	}

	bytes = i2c->block_size - 1;

	/* now read the data */
	while (len > 0) {
		if (bytes == i2c->block_size) {
			/* this is not the first round, so restart irq */
			saa716x_i2c_irq_start(i2c, I2C_DEV);
		}

		if (bytes > len)
			bytes = len;

		for (i = 0; i < bytes; i++) {
			data = 0x00; /* dummy write for reading */
			if (add_stop && i == (len - 1))
				data |= I2C_STOP_BIT;
			err = saa716x_i2c_send(i2c, I2C_DEV, data);
			if (err < 0) {
				dprintk(SAA716x_ERROR, 1, "Data send failed");
				goto exit;
			}
		}

		err = saa716x_i2c_irq_wait(i2c, I2C_DEV);
		if (err < 0) {
			goto exit;
		}

		for (i = 0; i < bytes; i++) {
			err = saa716x_i2c_recv(i2c, I2C_DEV, &data);
			if (err < 0) {
				dprintk(SAA716x_ERROR, 1, "Data receive failed");
				goto exit;
			}
			dprintk(SAA716x_DEBUG, 0, "    <R %04x> 0x%02x\n\n", i, data);
			buf[i] = data;
		}

		len -= bytes;
		buf += bytes;
		bytes = i2c->block_size;
	}

	return 0;

exit:
	dprintk(SAA716x_ERROR, 1, "Error reading data, err=%d", err);
	return err;
}