18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <media/drv-intf/saa7146_vv.h>
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_cistatic u32 saa7146_i2c_func(struct i2c_adapter *adapter)
78c2ecf20Sopenharmony_ci{
88c2ecf20Sopenharmony_ci	/* DEB_I2C("'%s'\n", adapter->name); */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci	return	  I2C_FUNC_I2C
118c2ecf20Sopenharmony_ci		| I2C_FUNC_SMBUS_QUICK
128c2ecf20Sopenharmony_ci		| I2C_FUNC_SMBUS_READ_BYTE	| I2C_FUNC_SMBUS_WRITE_BYTE
138c2ecf20Sopenharmony_ci		| I2C_FUNC_SMBUS_READ_BYTE_DATA | I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
148c2ecf20Sopenharmony_ci}
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci/* this function returns the status-register of our i2c-device */
178c2ecf20Sopenharmony_cistatic inline u32 saa7146_i2c_status(struct saa7146_dev *dev)
188c2ecf20Sopenharmony_ci{
198c2ecf20Sopenharmony_ci	u32 iicsta = saa7146_read(dev, I2C_STATUS);
208c2ecf20Sopenharmony_ci	/* DEB_I2C("status: 0x%08x\n", iicsta); */
218c2ecf20Sopenharmony_ci	return iicsta;
228c2ecf20Sopenharmony_ci}
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci/* this function runs through the i2c-messages and prepares the data to be
258c2ecf20Sopenharmony_ci   sent through the saa7146. have a look at the specifications p. 122 ff
268c2ecf20Sopenharmony_ci   to understand this. it returns the number of u32s to send, or -1
278c2ecf20Sopenharmony_ci   in case of an error. */
288c2ecf20Sopenharmony_cistatic int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, __le32 *op)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	int h1, h2;
318c2ecf20Sopenharmony_ci	int i, j, addr;
328c2ecf20Sopenharmony_ci	int mem = 0, op_count = 0;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	/* first determine size of needed memory */
358c2ecf20Sopenharmony_ci	for(i = 0; i < num; i++) {
368c2ecf20Sopenharmony_ci		mem += m[i].len + 1;
378c2ecf20Sopenharmony_ci	}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	/* worst case: we need one u32 for three bytes to be send
408c2ecf20Sopenharmony_ci	   plus one extra byte to address the device */
418c2ecf20Sopenharmony_ci	mem = 1 + ((mem-1) / 3);
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	/* we assume that op points to a memory of at least
448c2ecf20Sopenharmony_ci	 * SAA7146_I2C_MEM bytes size. if we exceed this limit...
458c2ecf20Sopenharmony_ci	 */
468c2ecf20Sopenharmony_ci	if ((4 * mem) > SAA7146_I2C_MEM) {
478c2ecf20Sopenharmony_ci		/* DEB_I2C("cannot prepare i2c-message\n"); */
488c2ecf20Sopenharmony_ci		return -ENOMEM;
498c2ecf20Sopenharmony_ci	}
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	/* be careful: clear out the i2c-mem first */
528c2ecf20Sopenharmony_ci	memset(op,0,sizeof(__le32)*mem);
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	/* loop through all messages */
558c2ecf20Sopenharmony_ci	for(i = 0; i < num; i++) {
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci		addr = i2c_8bit_addr_from_msg(&m[i]);
588c2ecf20Sopenharmony_ci		h1 = op_count/3; h2 = op_count%3;
598c2ecf20Sopenharmony_ci		op[h1] |= cpu_to_le32(	    (u8)addr << ((3-h2)*8));
608c2ecf20Sopenharmony_ci		op[h1] |= cpu_to_le32(SAA7146_I2C_START << ((3-h2)*2));
618c2ecf20Sopenharmony_ci		op_count++;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci		/* loop through all bytes of message i */
648c2ecf20Sopenharmony_ci		for(j = 0; j < m[i].len; j++) {
658c2ecf20Sopenharmony_ci			/* insert the data bytes */
668c2ecf20Sopenharmony_ci			h1 = op_count/3; h2 = op_count%3;
678c2ecf20Sopenharmony_ci			op[h1] |= cpu_to_le32( (u32)((u8)m[i].buf[j]) << ((3-h2)*8));
688c2ecf20Sopenharmony_ci			op[h1] |= cpu_to_le32(       SAA7146_I2C_CONT << ((3-h2)*2));
698c2ecf20Sopenharmony_ci			op_count++;
708c2ecf20Sopenharmony_ci		}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	/* have a look at the last byte inserted:
758c2ecf20Sopenharmony_ci	  if it was: ...CONT change it to ...STOP */
768c2ecf20Sopenharmony_ci	h1 = (op_count-1)/3; h2 = (op_count-1)%3;
778c2ecf20Sopenharmony_ci	if ( SAA7146_I2C_CONT == (0x3 & (le32_to_cpu(op[h1]) >> ((3-h2)*2))) ) {
788c2ecf20Sopenharmony_ci		op[h1] &= ~cpu_to_le32(0x2 << ((3-h2)*2));
798c2ecf20Sopenharmony_ci		op[h1] |= cpu_to_le32(SAA7146_I2C_STOP << ((3-h2)*2));
808c2ecf20Sopenharmony_ci	}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	/* return the number of u32s to send */
838c2ecf20Sopenharmony_ci	return mem;
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci/* this functions loops through all i2c-messages. normally, it should determine
878c2ecf20Sopenharmony_ci   which bytes were read through the adapter and write them back to the corresponding
888c2ecf20Sopenharmony_ci   i2c-message. but instead, we simply write back all bytes.
898c2ecf20Sopenharmony_ci   fixme: this could be improved. */
908c2ecf20Sopenharmony_cistatic int saa7146_i2c_msg_cleanup(const struct i2c_msg *m, int num, __le32 *op)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	int i, j;
938c2ecf20Sopenharmony_ci	int op_count = 0;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	/* loop through all messages */
968c2ecf20Sopenharmony_ci	for(i = 0; i < num; i++) {
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci		op_count++;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci		/* loop through all bytes of message i */
1018c2ecf20Sopenharmony_ci		for(j = 0; j < m[i].len; j++) {
1028c2ecf20Sopenharmony_ci			/* write back all bytes that could have been read */
1038c2ecf20Sopenharmony_ci			m[i].buf[j] = (le32_to_cpu(op[op_count/3]) >> ((3-(op_count%3))*8));
1048c2ecf20Sopenharmony_ci			op_count++;
1058c2ecf20Sopenharmony_ci		}
1068c2ecf20Sopenharmony_ci	}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	return 0;
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci/* this functions resets the i2c-device and returns 0 if everything was fine, otherwise -1 */
1128c2ecf20Sopenharmony_cistatic int saa7146_i2c_reset(struct saa7146_dev *dev)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	/* get current status */
1158c2ecf20Sopenharmony_ci	u32 status = saa7146_i2c_status(dev);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	/* clear registers for sure */
1188c2ecf20Sopenharmony_ci	saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
1198c2ecf20Sopenharmony_ci	saa7146_write(dev, I2C_TRANSFER, 0);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	/* check if any operation is still in progress */
1228c2ecf20Sopenharmony_ci	if ( 0 != ( status & SAA7146_I2C_BUSY) ) {
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci		/* yes, kill ongoing operation */
1258c2ecf20Sopenharmony_ci		DEB_I2C("busy_state detected\n");
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci		/* set "ABORT-OPERATION"-bit (bit 7)*/
1288c2ecf20Sopenharmony_ci		saa7146_write(dev, I2C_STATUS, (dev->i2c_bitrate | MASK_07));
1298c2ecf20Sopenharmony_ci		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
1308c2ecf20Sopenharmony_ci		msleep(SAA7146_I2C_DELAY);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci		/* clear all error-bits pending; this is needed because p.123, note 1 */
1338c2ecf20Sopenharmony_ci		saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
1348c2ecf20Sopenharmony_ci		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
1358c2ecf20Sopenharmony_ci		msleep(SAA7146_I2C_DELAY);
1368c2ecf20Sopenharmony_ci	}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	/* check if any error is (still) present. (this can be necessary because p.123, note 1) */
1398c2ecf20Sopenharmony_ci	status = saa7146_i2c_status(dev);
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	if ( dev->i2c_bitrate != status ) {
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci		DEB_I2C("error_state detected. status:0x%08x\n", status);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci		/* Repeat the abort operation. This seems to be necessary
1468c2ecf20Sopenharmony_ci		   after serious protocol errors caused by e.g. the SAA7740 */
1478c2ecf20Sopenharmony_ci		saa7146_write(dev, I2C_STATUS, (dev->i2c_bitrate | MASK_07));
1488c2ecf20Sopenharmony_ci		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
1498c2ecf20Sopenharmony_ci		msleep(SAA7146_I2C_DELAY);
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci		/* clear all error-bits pending */
1528c2ecf20Sopenharmony_ci		saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
1538c2ecf20Sopenharmony_ci		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
1548c2ecf20Sopenharmony_ci		msleep(SAA7146_I2C_DELAY);
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci		/* the data sheet says it might be necessary to clear the status
1578c2ecf20Sopenharmony_ci		   twice after an abort */
1588c2ecf20Sopenharmony_ci		saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
1598c2ecf20Sopenharmony_ci		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
1608c2ecf20Sopenharmony_ci		msleep(SAA7146_I2C_DELAY);
1618c2ecf20Sopenharmony_ci	}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	/* if any error is still present, a fatal error has occurred ... */
1648c2ecf20Sopenharmony_ci	status = saa7146_i2c_status(dev);
1658c2ecf20Sopenharmony_ci	if ( dev->i2c_bitrate != status ) {
1668c2ecf20Sopenharmony_ci		DEB_I2C("fatal error. status:0x%08x\n", status);
1678c2ecf20Sopenharmony_ci		return -1;
1688c2ecf20Sopenharmony_ci	}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	return 0;
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci/* this functions writes out the data-byte 'dword' to the i2c-device.
1748c2ecf20Sopenharmony_ci   it returns 0 if ok, -1 if the transfer failed, -2 if the transfer
1758c2ecf20Sopenharmony_ci   failed badly (e.g. address error) */
1768c2ecf20Sopenharmony_cistatic int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int short_delay)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	u32 status = 0, mc2 = 0;
1798c2ecf20Sopenharmony_ci	int trial = 0;
1808c2ecf20Sopenharmony_ci	unsigned long timeout;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	/* write out i2c-command */
1838c2ecf20Sopenharmony_ci	DEB_I2C("before: 0x%08x (status: 0x%08x), %d\n",
1848c2ecf20Sopenharmony_ci		*dword, saa7146_read(dev, I2C_STATUS), dev->i2c_op);
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	if( 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags)) {
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci		saa7146_write(dev, I2C_STATUS,	 dev->i2c_bitrate);
1898c2ecf20Sopenharmony_ci		saa7146_write(dev, I2C_TRANSFER, le32_to_cpu(*dword));
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci		dev->i2c_op = 1;
1928c2ecf20Sopenharmony_ci		SAA7146_ISR_CLEAR(dev, MASK_16|MASK_17);
1938c2ecf20Sopenharmony_ci		SAA7146_IER_ENABLE(dev, MASK_16|MASK_17);
1948c2ecf20Sopenharmony_ci		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci		timeout = HZ/100 + 1; /* 10ms */
1978c2ecf20Sopenharmony_ci		timeout = wait_event_interruptible_timeout(dev->i2c_wq, dev->i2c_op == 0, timeout);
1988c2ecf20Sopenharmony_ci		if (timeout == -ERESTARTSYS || dev->i2c_op) {
1998c2ecf20Sopenharmony_ci			SAA7146_IER_DISABLE(dev, MASK_16|MASK_17);
2008c2ecf20Sopenharmony_ci			SAA7146_ISR_CLEAR(dev, MASK_16|MASK_17);
2018c2ecf20Sopenharmony_ci			if (timeout == -ERESTARTSYS)
2028c2ecf20Sopenharmony_ci				/* a signal arrived */
2038c2ecf20Sopenharmony_ci				return -ERESTARTSYS;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci			pr_warn("%s %s [irq]: timed out waiting for end of xfer\n",
2068c2ecf20Sopenharmony_ci				dev->name, __func__);
2078c2ecf20Sopenharmony_ci			return -EIO;
2088c2ecf20Sopenharmony_ci		}
2098c2ecf20Sopenharmony_ci		status = saa7146_read(dev, I2C_STATUS);
2108c2ecf20Sopenharmony_ci	} else {
2118c2ecf20Sopenharmony_ci		saa7146_write(dev, I2C_STATUS,	 dev->i2c_bitrate);
2128c2ecf20Sopenharmony_ci		saa7146_write(dev, I2C_TRANSFER, le32_to_cpu(*dword));
2138c2ecf20Sopenharmony_ci		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci		/* do not poll for i2c-status before upload is complete */
2168c2ecf20Sopenharmony_ci		timeout = jiffies + HZ/100 + 1; /* 10ms */
2178c2ecf20Sopenharmony_ci		while(1) {
2188c2ecf20Sopenharmony_ci			mc2 = (saa7146_read(dev, MC2) & 0x1);
2198c2ecf20Sopenharmony_ci			if( 0 != mc2 ) {
2208c2ecf20Sopenharmony_ci				break;
2218c2ecf20Sopenharmony_ci			}
2228c2ecf20Sopenharmony_ci			if (time_after(jiffies,timeout)) {
2238c2ecf20Sopenharmony_ci				pr_warn("%s %s: timed out waiting for MC2\n",
2248c2ecf20Sopenharmony_ci					dev->name, __func__);
2258c2ecf20Sopenharmony_ci				return -EIO;
2268c2ecf20Sopenharmony_ci			}
2278c2ecf20Sopenharmony_ci		}
2288c2ecf20Sopenharmony_ci		/* wait until we get a transfer done or error */
2298c2ecf20Sopenharmony_ci		timeout = jiffies + HZ/100 + 1; /* 10ms */
2308c2ecf20Sopenharmony_ci		/* first read usually delivers bogus results... */
2318c2ecf20Sopenharmony_ci		saa7146_i2c_status(dev);
2328c2ecf20Sopenharmony_ci		while(1) {
2338c2ecf20Sopenharmony_ci			status = saa7146_i2c_status(dev);
2348c2ecf20Sopenharmony_ci			if ((status & 0x3) != 1)
2358c2ecf20Sopenharmony_ci				break;
2368c2ecf20Sopenharmony_ci			if (time_after(jiffies,timeout)) {
2378c2ecf20Sopenharmony_ci				/* this is normal when probing the bus
2388c2ecf20Sopenharmony_ci				 * (no answer from nonexisistant device...)
2398c2ecf20Sopenharmony_ci				 */
2408c2ecf20Sopenharmony_ci				pr_warn("%s %s [poll]: timed out waiting for end of xfer\n",
2418c2ecf20Sopenharmony_ci					dev->name, __func__);
2428c2ecf20Sopenharmony_ci				return -EIO;
2438c2ecf20Sopenharmony_ci			}
2448c2ecf20Sopenharmony_ci			if (++trial < 50 && short_delay)
2458c2ecf20Sopenharmony_ci				udelay(10);
2468c2ecf20Sopenharmony_ci			else
2478c2ecf20Sopenharmony_ci				msleep(1);
2488c2ecf20Sopenharmony_ci		}
2498c2ecf20Sopenharmony_ci	}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	/* give a detailed status report */
2528c2ecf20Sopenharmony_ci	if ( 0 != (status & (SAA7146_I2C_SPERR | SAA7146_I2C_APERR |
2538c2ecf20Sopenharmony_ci			     SAA7146_I2C_DTERR | SAA7146_I2C_DRERR |
2548c2ecf20Sopenharmony_ci			     SAA7146_I2C_AL    | SAA7146_I2C_ERR   |
2558c2ecf20Sopenharmony_ci			     SAA7146_I2C_BUSY)) ) {
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci		if ( 0 == (status & SAA7146_I2C_ERR) ||
2588c2ecf20Sopenharmony_ci		     0 == (status & SAA7146_I2C_BUSY) ) {
2598c2ecf20Sopenharmony_ci			/* it may take some time until ERR goes high - ignore */
2608c2ecf20Sopenharmony_ci			DEB_I2C("unexpected i2c status %04x\n", status);
2618c2ecf20Sopenharmony_ci		}
2628c2ecf20Sopenharmony_ci		if( 0 != (status & SAA7146_I2C_SPERR) ) {
2638c2ecf20Sopenharmony_ci			DEB_I2C("error due to invalid start/stop condition\n");
2648c2ecf20Sopenharmony_ci		}
2658c2ecf20Sopenharmony_ci		if( 0 != (status & SAA7146_I2C_DTERR) ) {
2668c2ecf20Sopenharmony_ci			DEB_I2C("error in data transmission\n");
2678c2ecf20Sopenharmony_ci		}
2688c2ecf20Sopenharmony_ci		if( 0 != (status & SAA7146_I2C_DRERR) ) {
2698c2ecf20Sopenharmony_ci			DEB_I2C("error when receiving data\n");
2708c2ecf20Sopenharmony_ci		}
2718c2ecf20Sopenharmony_ci		if( 0 != (status & SAA7146_I2C_AL) ) {
2728c2ecf20Sopenharmony_ci			DEB_I2C("error because arbitration lost\n");
2738c2ecf20Sopenharmony_ci		}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci		/* we handle address-errors here */
2768c2ecf20Sopenharmony_ci		if( 0 != (status & SAA7146_I2C_APERR) ) {
2778c2ecf20Sopenharmony_ci			DEB_I2C("error in address phase\n");
2788c2ecf20Sopenharmony_ci			return -EREMOTEIO;
2798c2ecf20Sopenharmony_ci		}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci		return -EIO;
2828c2ecf20Sopenharmony_ci	}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	/* read back data, just in case we were reading ... */
2858c2ecf20Sopenharmony_ci	*dword = cpu_to_le32(saa7146_read(dev, I2C_TRANSFER));
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	DEB_I2C("after: 0x%08x\n", *dword);
2888c2ecf20Sopenharmony_ci	return 0;
2898c2ecf20Sopenharmony_ci}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_cistatic int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	int i = 0, count = 0;
2948c2ecf20Sopenharmony_ci	__le32 *buffer = dev->d_i2c.cpu_addr;
2958c2ecf20Sopenharmony_ci	int err = 0;
2968c2ecf20Sopenharmony_ci	int short_delay = 0;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	if (mutex_lock_interruptible(&dev->i2c_lock))
2998c2ecf20Sopenharmony_ci		return -ERESTARTSYS;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	for(i=0;i<num;i++) {
3028c2ecf20Sopenharmony_ci		DEB_I2C("msg:%d/%d\n", i+1, num);
3038c2ecf20Sopenharmony_ci	}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	/* prepare the message(s), get number of u32s to transfer */
3068c2ecf20Sopenharmony_ci	count = saa7146_i2c_msg_prepare(msgs, num, buffer);
3078c2ecf20Sopenharmony_ci	if ( 0 > count ) {
3088c2ecf20Sopenharmony_ci		err = -EIO;
3098c2ecf20Sopenharmony_ci		goto out;
3108c2ecf20Sopenharmony_ci	}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	if ( count > 3 || 0 != (SAA7146_I2C_SHORT_DELAY & dev->ext->flags) )
3138c2ecf20Sopenharmony_ci		short_delay = 1;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	do {
3168c2ecf20Sopenharmony_ci		/* reset the i2c-device if necessary */
3178c2ecf20Sopenharmony_ci		err = saa7146_i2c_reset(dev);
3188c2ecf20Sopenharmony_ci		if ( 0 > err ) {
3198c2ecf20Sopenharmony_ci			DEB_I2C("could not reset i2c-device\n");
3208c2ecf20Sopenharmony_ci			goto out;
3218c2ecf20Sopenharmony_ci		}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci		/* write out the u32s one after another */
3248c2ecf20Sopenharmony_ci		for(i = 0; i < count; i++) {
3258c2ecf20Sopenharmony_ci			err = saa7146_i2c_writeout(dev, &buffer[i], short_delay);
3268c2ecf20Sopenharmony_ci			if ( 0 != err) {
3278c2ecf20Sopenharmony_ci				/* this one is unsatisfying: some i2c slaves on some
3288c2ecf20Sopenharmony_ci				   dvb cards don't acknowledge correctly, so the saa7146
3298c2ecf20Sopenharmony_ci				   thinks that an address error occurred. in that case, the
3308c2ecf20Sopenharmony_ci				   transaction should be retrying, even if an address error
3318c2ecf20Sopenharmony_ci				   occurred. analog saa7146 based cards extensively rely on
3328c2ecf20Sopenharmony_ci				   i2c address probing, however, and address errors indicate that a
3338c2ecf20Sopenharmony_ci				   device is really *not* there. retrying in that case
3348c2ecf20Sopenharmony_ci				   increases the time the device needs to probe greatly, so
3358c2ecf20Sopenharmony_ci				   it should be avoided. So we bail out in irq mode after an
3368c2ecf20Sopenharmony_ci				   address error and trust the saa7146 address error detection. */
3378c2ecf20Sopenharmony_ci				if (-EREMOTEIO == err && 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags))
3388c2ecf20Sopenharmony_ci					goto out;
3398c2ecf20Sopenharmony_ci				DEB_I2C("error while sending message(s). starting again\n");
3408c2ecf20Sopenharmony_ci				break;
3418c2ecf20Sopenharmony_ci			}
3428c2ecf20Sopenharmony_ci		}
3438c2ecf20Sopenharmony_ci		if( 0 == err ) {
3448c2ecf20Sopenharmony_ci			err = num;
3458c2ecf20Sopenharmony_ci			break;
3468c2ecf20Sopenharmony_ci		}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci		/* delay a bit before retrying */
3498c2ecf20Sopenharmony_ci		msleep(10);
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	} while (err != num && retries--);
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	/* quit if any error occurred */
3548c2ecf20Sopenharmony_ci	if (err != num)
3558c2ecf20Sopenharmony_ci		goto out;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	/* if any things had to be read, get the results */
3588c2ecf20Sopenharmony_ci	if ( 0 != saa7146_i2c_msg_cleanup(msgs, num, buffer)) {
3598c2ecf20Sopenharmony_ci		DEB_I2C("could not cleanup i2c-message\n");
3608c2ecf20Sopenharmony_ci		err = -EIO;
3618c2ecf20Sopenharmony_ci		goto out;
3628c2ecf20Sopenharmony_ci	}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	/* return the number of delivered messages */
3658c2ecf20Sopenharmony_ci	DEB_I2C("transmission successful. (msg:%d)\n", err);
3668c2ecf20Sopenharmony_ciout:
3678c2ecf20Sopenharmony_ci	/* another bug in revision 0: the i2c-registers get uploaded randomly by other
3688c2ecf20Sopenharmony_ci	   uploads, so we better clear them out before continuing */
3698c2ecf20Sopenharmony_ci	if( 0 == dev->revision ) {
3708c2ecf20Sopenharmony_ci		__le32 zero = 0;
3718c2ecf20Sopenharmony_ci		saa7146_i2c_reset(dev);
3728c2ecf20Sopenharmony_ci		if( 0 != saa7146_i2c_writeout(dev, &zero, short_delay)) {
3738c2ecf20Sopenharmony_ci			pr_info("revision 0 error. this should never happen\n");
3748c2ecf20Sopenharmony_ci		}
3758c2ecf20Sopenharmony_ci	}
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	mutex_unlock(&dev->i2c_lock);
3788c2ecf20Sopenharmony_ci	return err;
3798c2ecf20Sopenharmony_ci}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci/* utility functions */
3828c2ecf20Sopenharmony_cistatic int saa7146_i2c_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num)
3838c2ecf20Sopenharmony_ci{
3848c2ecf20Sopenharmony_ci	struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter);
3858c2ecf20Sopenharmony_ci	struct saa7146_dev *dev = to_saa7146_dev(v4l2_dev);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	/* use helper function to transfer data */
3888c2ecf20Sopenharmony_ci	return saa7146_i2c_transfer(dev, msg, num, adapter->retries);
3898c2ecf20Sopenharmony_ci}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci/*****************************************************************************/
3938c2ecf20Sopenharmony_ci/* i2c-adapter helper functions                                              */
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci/* exported algorithm data */
3968c2ecf20Sopenharmony_cistatic const struct i2c_algorithm saa7146_algo = {
3978c2ecf20Sopenharmony_ci	.master_xfer	= saa7146_i2c_xfer,
3988c2ecf20Sopenharmony_ci	.functionality	= saa7146_i2c_func,
3998c2ecf20Sopenharmony_ci};
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ciint saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate)
4028c2ecf20Sopenharmony_ci{
4038c2ecf20Sopenharmony_ci	DEB_EE("bitrate: 0x%08x\n", bitrate);
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	/* enable i2c-port pins */
4068c2ecf20Sopenharmony_ci	saa7146_write(dev, MC1, (MASK_08 | MASK_24));
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	dev->i2c_bitrate = bitrate;
4098c2ecf20Sopenharmony_ci	saa7146_i2c_reset(dev);
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	if (i2c_adapter) {
4128c2ecf20Sopenharmony_ci		i2c_set_adapdata(i2c_adapter, &dev->v4l2_dev);
4138c2ecf20Sopenharmony_ci		i2c_adapter->dev.parent    = &dev->pci->dev;
4148c2ecf20Sopenharmony_ci		i2c_adapter->algo	   = &saa7146_algo;
4158c2ecf20Sopenharmony_ci		i2c_adapter->algo_data     = NULL;
4168c2ecf20Sopenharmony_ci		i2c_adapter->timeout = SAA7146_I2C_TIMEOUT;
4178c2ecf20Sopenharmony_ci		i2c_adapter->retries = SAA7146_I2C_RETRIES;
4188c2ecf20Sopenharmony_ci	}
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	return 0;
4218c2ecf20Sopenharmony_ci}
422