xref: /openbmc/linux/drivers/media/usb/em28xx/em28xx-i2c.c (revision cc5c5d20c3cb9066576043b937b35d6b669a52e0)
10c0d06caSMauro Carvalho Chehab /*
20c0d06caSMauro Carvalho Chehab    em28xx-i2c.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
30c0d06caSMauro Carvalho Chehab 
40c0d06caSMauro Carvalho Chehab    Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
50c0d06caSMauro Carvalho Chehab 		      Markus Rechberger <mrechberger@gmail.com>
60c0d06caSMauro Carvalho Chehab 		      Mauro Carvalho Chehab <mchehab@infradead.org>
70c0d06caSMauro Carvalho Chehab 		      Sascha Sommer <saschasommer@freenet.de>
8a3ea4bf9SFrank Schaefer    Copyright (C) 2013 Frank Schäfer <fschaefer.oss@googlemail.com>
90c0d06caSMauro Carvalho Chehab 
100c0d06caSMauro Carvalho Chehab    This program is free software; you can redistribute it and/or modify
110c0d06caSMauro Carvalho Chehab    it under the terms of the GNU General Public License as published by
120c0d06caSMauro Carvalho Chehab    the Free Software Foundation; either version 2 of the License, or
130c0d06caSMauro Carvalho Chehab    (at your option) any later version.
140c0d06caSMauro Carvalho Chehab 
150c0d06caSMauro Carvalho Chehab    This program is distributed in the hope that it will be useful,
160c0d06caSMauro Carvalho Chehab    but WITHOUT ANY WARRANTY; without even the implied warranty of
170c0d06caSMauro Carvalho Chehab    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
180c0d06caSMauro Carvalho Chehab    GNU General Public License for more details.
190c0d06caSMauro Carvalho Chehab 
200c0d06caSMauro Carvalho Chehab    You should have received a copy of the GNU General Public License
210c0d06caSMauro Carvalho Chehab    along with this program; if not, write to the Free Software
220c0d06caSMauro Carvalho Chehab    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
230c0d06caSMauro Carvalho Chehab  */
240c0d06caSMauro Carvalho Chehab 
250c0d06caSMauro Carvalho Chehab #include <linux/module.h>
260c0d06caSMauro Carvalho Chehab #include <linux/kernel.h>
270c0d06caSMauro Carvalho Chehab #include <linux/usb.h>
280c0d06caSMauro Carvalho Chehab #include <linux/i2c.h>
294b83626aSMauro Carvalho Chehab #include <linux/jiffies.h>
300c0d06caSMauro Carvalho Chehab 
310c0d06caSMauro Carvalho Chehab #include "em28xx.h"
320c0d06caSMauro Carvalho Chehab #include "tuner-xc2028.h"
330c0d06caSMauro Carvalho Chehab #include <media/v4l2-common.h>
340c0d06caSMauro Carvalho Chehab #include <media/tuner.h>
350c0d06caSMauro Carvalho Chehab 
360c0d06caSMauro Carvalho Chehab /* ----------------------------------------------------------- */
370c0d06caSMauro Carvalho Chehab 
380c0d06caSMauro Carvalho Chehab static unsigned int i2c_scan;
390c0d06caSMauro Carvalho Chehab module_param(i2c_scan, int, 0444);
400c0d06caSMauro Carvalho Chehab MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
410c0d06caSMauro Carvalho Chehab 
420c0d06caSMauro Carvalho Chehab static unsigned int i2c_debug;
430c0d06caSMauro Carvalho Chehab module_param(i2c_debug, int, 0644);
4450f0a9dfSMauro Carvalho Chehab MODULE_PARM_DESC(i2c_debug, "i2c debug message level (1: normal debug, 2: show I2C transfers)");
450c0d06caSMauro Carvalho Chehab 
460c0d06caSMauro Carvalho Chehab /*
47f5ae371aSFrank Schaefer  * em2800_i2c_send_bytes()
48f5ae371aSFrank Schaefer  * send up to 4 bytes to the em2800 i2c device
490c0d06caSMauro Carvalho Chehab  */
50f5ae371aSFrank Schaefer static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
510c0d06caSMauro Carvalho Chehab {
52d1b7213bSMauro Carvalho Chehab 	unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT);
530c0d06caSMauro Carvalho Chehab 	int ret;
54a6bad040SFrank Schaefer 	u8 b2[6];
55f5ae371aSFrank Schaefer 
56f5ae371aSFrank Schaefer 	if (len < 1 || len > 4)
57f5ae371aSFrank Schaefer 		return -EOPNOTSUPP;
58f5ae371aSFrank Schaefer 
590c0d06caSMauro Carvalho Chehab 	BUG_ON(len < 1 || len > 4);
600c0d06caSMauro Carvalho Chehab 	b2[5] = 0x80 + len - 1;
610c0d06caSMauro Carvalho Chehab 	b2[4] = addr;
620c0d06caSMauro Carvalho Chehab 	b2[3] = buf[0];
630c0d06caSMauro Carvalho Chehab 	if (len > 1)
640c0d06caSMauro Carvalho Chehab 		b2[2] = buf[1];
650c0d06caSMauro Carvalho Chehab 	if (len > 2)
660c0d06caSMauro Carvalho Chehab 		b2[1] = buf[2];
670c0d06caSMauro Carvalho Chehab 	if (len > 3)
680c0d06caSMauro Carvalho Chehab 		b2[0] = buf[3];
690c0d06caSMauro Carvalho Chehab 
702fcc82d8SFrank Schaefer 	/* trigger write */
710c0d06caSMauro Carvalho Chehab 	ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len);
720c0d06caSMauro Carvalho Chehab 	if (ret != 2 + len) {
73d230d5adSFrank Schaefer 		em28xx_warn("failed to trigger write to i2c address 0x%x (error=%i)\n",
74d230d5adSFrank Schaefer 			    addr, ret);
7545f04e82SFrank Schaefer 		return (ret < 0) ? ret : -EIO;
760c0d06caSMauro Carvalho Chehab 	}
772fcc82d8SFrank Schaefer 	/* wait for completion */
784b83626aSMauro Carvalho Chehab 	while (time_is_after_jiffies(timeout)) {
790c0d06caSMauro Carvalho Chehab 		ret = dev->em28xx_read_reg(dev, 0x05);
804b83626aSMauro Carvalho Chehab 		if (ret == 0x80 + len - 1)
810c0d06caSMauro Carvalho Chehab 			return len;
824b83626aSMauro Carvalho Chehab 		if (ret == 0x94 + len - 1) {
83d845fb3aSMauro Carvalho Chehab 			if (i2c_debug == 1)
848ae8cd6cSFrank Schaefer 				em28xx_warn("R05 returned 0x%02x: I2C ACK error\n",
85d845fb3aSMauro Carvalho Chehab 					    ret);
86e63b009dSMauro Carvalho Chehab 			return -ENXIO;
874b83626aSMauro Carvalho Chehab 		}
884b83626aSMauro Carvalho Chehab 		if (ret < 0) {
89d230d5adSFrank Schaefer 			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
90d230d5adSFrank Schaefer 				    ret);
9145f04e82SFrank Schaefer 			return ret;
9245f04e82SFrank Schaefer 		}
930c0d06caSMauro Carvalho Chehab 		msleep(5);
940c0d06caSMauro Carvalho Chehab 	}
9550f0a9dfSMauro Carvalho Chehab 	if (i2c_debug)
9645f04e82SFrank Schaefer 		em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
97e63b009dSMauro Carvalho Chehab 	return -ETIMEDOUT;
980c0d06caSMauro Carvalho Chehab }
990c0d06caSMauro Carvalho Chehab 
1000c0d06caSMauro Carvalho Chehab /*
1010c0d06caSMauro Carvalho Chehab  * em2800_i2c_recv_bytes()
1022fcc82d8SFrank Schaefer  * read up to 4 bytes from the em2800 i2c device
1030c0d06caSMauro Carvalho Chehab  */
104a6bad040SFrank Schaefer static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
1050c0d06caSMauro Carvalho Chehab {
106d1b7213bSMauro Carvalho Chehab 	unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT);
1072fcc82d8SFrank Schaefer 	u8 buf2[4];
1080c0d06caSMauro Carvalho Chehab 	int ret;
1092fcc82d8SFrank Schaefer 	int i;
110f5ae371aSFrank Schaefer 
111f5ae371aSFrank Schaefer 	if (len < 1 || len > 4)
112f5ae371aSFrank Schaefer 		return -EOPNOTSUPP;
113f5ae371aSFrank Schaefer 
1142fcc82d8SFrank Schaefer 	/* trigger read */
1152fcc82d8SFrank Schaefer 	buf2[1] = 0x84 + len - 1;
1162fcc82d8SFrank Schaefer 	buf2[0] = addr;
1172fcc82d8SFrank Schaefer 	ret = dev->em28xx_write_regs(dev, 0x04, buf2, 2);
1182fcc82d8SFrank Schaefer 	if (ret != 2) {
119d230d5adSFrank Schaefer 		em28xx_warn("failed to trigger read from i2c address 0x%x (error=%i)\n",
120d230d5adSFrank Schaefer 			    addr, ret);
1212fcc82d8SFrank Schaefer 		return (ret < 0) ? ret : -EIO;
1222fcc82d8SFrank Schaefer 	}
1232fcc82d8SFrank Schaefer 
1242fcc82d8SFrank Schaefer 	/* wait for completion */
1254b83626aSMauro Carvalho Chehab 	while (time_is_after_jiffies(timeout)) {
1262fcc82d8SFrank Schaefer 		ret = dev->em28xx_read_reg(dev, 0x05);
1274b83626aSMauro Carvalho Chehab 		if (ret == 0x84 + len - 1)
1282fcc82d8SFrank Schaefer 			break;
1294b83626aSMauro Carvalho Chehab 		if (ret == 0x94 + len - 1) {
130d845fb3aSMauro Carvalho Chehab 			if (i2c_debug == 1)
1318ae8cd6cSFrank Schaefer 				em28xx_warn("R05 returned 0x%02x: I2C ACK error\n",
132d845fb3aSMauro Carvalho Chehab 					    ret);
133e63b009dSMauro Carvalho Chehab 			return -ENXIO;
1344b83626aSMauro Carvalho Chehab 		}
1354b83626aSMauro Carvalho Chehab 		if (ret < 0) {
136d230d5adSFrank Schaefer 			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
137d230d5adSFrank Schaefer 				    ret);
1380c0d06caSMauro Carvalho Chehab 			return ret;
1390c0d06caSMauro Carvalho Chehab 		}
1402fcc82d8SFrank Schaefer 		msleep(5);
1412fcc82d8SFrank Schaefer 	}
14250f0a9dfSMauro Carvalho Chehab 	if (ret != 0x84 + len - 1) {
14350f0a9dfSMauro Carvalho Chehab 		if (i2c_debug)
14450f0a9dfSMauro Carvalho Chehab 			em28xx_warn("read from i2c device at 0x%x timed out\n",
14550f0a9dfSMauro Carvalho Chehab 				    addr);
14650f0a9dfSMauro Carvalho Chehab 	}
1472fcc82d8SFrank Schaefer 
1482fcc82d8SFrank Schaefer 	/* get the received message */
1492fcc82d8SFrank Schaefer 	ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len);
1502fcc82d8SFrank Schaefer 	if (ret != len) {
151d230d5adSFrank Schaefer 		em28xx_warn("reading from i2c device at 0x%x failed: couldn't get the received message from the bridge (error=%i)\n",
152d230d5adSFrank Schaefer 			    addr, ret);
1532fcc82d8SFrank Schaefer 		return (ret < 0) ? ret : -EIO;
1542fcc82d8SFrank Schaefer 	}
1552fcc82d8SFrank Schaefer 	for (i = 0; i < len; i++)
1562fcc82d8SFrank Schaefer 		buf[i] = buf2[len - 1 - i];
1572fcc82d8SFrank Schaefer 
1580c0d06caSMauro Carvalho Chehab 	return ret;
1590c0d06caSMauro Carvalho Chehab }
1602fcc82d8SFrank Schaefer 
1612fcc82d8SFrank Schaefer /*
1622fcc82d8SFrank Schaefer  * em2800_i2c_check_for_device()
1632fcc82d8SFrank Schaefer  * check if there is an i2c device at the supplied address
1642fcc82d8SFrank Schaefer  */
1652fcc82d8SFrank Schaefer static int em2800_i2c_check_for_device(struct em28xx *dev, u8 addr)
1662fcc82d8SFrank Schaefer {
1672fcc82d8SFrank Schaefer 	u8 buf;
1682fcc82d8SFrank Schaefer 	int ret;
1692fcc82d8SFrank Schaefer 
1702fcc82d8SFrank Schaefer 	ret = em2800_i2c_recv_bytes(dev, addr, &buf, 1);
1712fcc82d8SFrank Schaefer 	if (ret == 1)
1722fcc82d8SFrank Schaefer 		return 0;
1732fcc82d8SFrank Schaefer 	return (ret < 0) ? ret : -EIO;
1740c0d06caSMauro Carvalho Chehab }
1750c0d06caSMauro Carvalho Chehab 
1760c0d06caSMauro Carvalho Chehab /*
1770c0d06caSMauro Carvalho Chehab  * em28xx_i2c_send_bytes()
1780c0d06caSMauro Carvalho Chehab  */
179a6bad040SFrank Schaefer static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
180a6bad040SFrank Schaefer 				 u16 len, int stop)
1810c0d06caSMauro Carvalho Chehab {
182d1b7213bSMauro Carvalho Chehab 	unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT);
1834b83626aSMauro Carvalho Chehab 	int ret;
1840c0d06caSMauro Carvalho Chehab 
185f5ae371aSFrank Schaefer 	if (len < 1 || len > 64)
186f5ae371aSFrank Schaefer 		return -EOPNOTSUPP;
187fa74aca3SFrank Schaefer 	/*
188fa74aca3SFrank Schaefer 	 * NOTE: limited by the USB ctrl message constraints
189fa74aca3SFrank Schaefer 	 * Zero length reads always succeed, even if no device is connected
190fa74aca3SFrank Schaefer 	 */
191f5ae371aSFrank Schaefer 
19245f04e82SFrank Schaefer 	/* Write to i2c device */
19345f04e82SFrank Schaefer 	ret = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len);
19445f04e82SFrank Schaefer 	if (ret != len) {
19545f04e82SFrank Schaefer 		if (ret < 0) {
196d230d5adSFrank Schaefer 			em28xx_warn("writing to i2c device at 0x%x failed (error=%i)\n",
197d230d5adSFrank Schaefer 				    addr, ret);
19845f04e82SFrank Schaefer 			return ret;
19945f04e82SFrank Schaefer 		} else {
200d230d5adSFrank Schaefer 			em28xx_warn("%i bytes write to i2c device at 0x%x requested, but %i bytes written\n",
20145f04e82SFrank Schaefer 				    len, addr, ret);
20245f04e82SFrank Schaefer 			return -EIO;
20345f04e82SFrank Schaefer 		}
20445f04e82SFrank Schaefer 	}
2050c0d06caSMauro Carvalho Chehab 
2064b83626aSMauro Carvalho Chehab 	/* wait for completion */
2074b83626aSMauro Carvalho Chehab 	while (time_is_after_jiffies(timeout)) {
2080c0d06caSMauro Carvalho Chehab 		ret = dev->em28xx_read_reg(dev, 0x05);
2094b83626aSMauro Carvalho Chehab 		if (ret == 0) /* success */
21045f04e82SFrank Schaefer 			return len;
2114b83626aSMauro Carvalho Chehab 		if (ret == 0x10) {
212d845fb3aSMauro Carvalho Chehab 			if (i2c_debug == 1)
2138ae8cd6cSFrank Schaefer 				em28xx_warn("I2C ACK error on writing to addr 0x%02x\n",
214d845fb3aSMauro Carvalho Chehab 					    addr);
215e63b009dSMauro Carvalho Chehab 			return -ENXIO;
2164b83626aSMauro Carvalho Chehab 		}
2174b83626aSMauro Carvalho Chehab 		if (ret < 0) {
2184b83626aSMauro Carvalho Chehab 			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
219d230d5adSFrank Schaefer 				    ret);
22045f04e82SFrank Schaefer 			return ret;
2210c0d06caSMauro Carvalho Chehab 		}
22245f04e82SFrank Schaefer 		msleep(5);
223fa74aca3SFrank Schaefer 		/*
224fa74aca3SFrank Schaefer 		 * NOTE: do we really have to wait for success ?
225fa74aca3SFrank Schaefer 		 * Never seen anything else than 0x00 or 0x10
226fa74aca3SFrank Schaefer 		 * (even with high payload) ...
227fa74aca3SFrank Schaefer 		 */
22845f04e82SFrank Schaefer 	}
229123a17d1SFrank Schaefer 
230123a17d1SFrank Schaefer 	if (ret == 0x02 || ret == 0x04) {
231123a17d1SFrank Schaefer 		/* NOTE: these errors seem to be related to clock stretching */
23250f0a9dfSMauro Carvalho Chehab 		if (i2c_debug)
23350f0a9dfSMauro Carvalho Chehab 			em28xx_warn("write to i2c device at 0x%x timed out (status=%i)\n",
23450f0a9dfSMauro Carvalho Chehab 				    addr, ret);
235e63b009dSMauro Carvalho Chehab 		return -ETIMEDOUT;
2360c0d06caSMauro Carvalho Chehab 	}
2370c0d06caSMauro Carvalho Chehab 
238123a17d1SFrank Schaefer 	em28xx_warn("write to i2c device at 0x%x failed with unknown error (status=%i)\n",
239123a17d1SFrank Schaefer 		    addr, ret);
240123a17d1SFrank Schaefer 	return -EIO;
241123a17d1SFrank Schaefer }
242123a17d1SFrank Schaefer 
2430c0d06caSMauro Carvalho Chehab /*
2440c0d06caSMauro Carvalho Chehab  * em28xx_i2c_recv_bytes()
2450c0d06caSMauro Carvalho Chehab  * read a byte from the i2c device
2460c0d06caSMauro Carvalho Chehab  */
247a6bad040SFrank Schaefer static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
2480c0d06caSMauro Carvalho Chehab {
2490c0d06caSMauro Carvalho Chehab 	int ret;
250f5ae371aSFrank Schaefer 
251f5ae371aSFrank Schaefer 	if (len < 1 || len > 64)
252f5ae371aSFrank Schaefer 		return -EOPNOTSUPP;
253fa74aca3SFrank Schaefer 	/*
254fa74aca3SFrank Schaefer 	 * NOTE: limited by the USB ctrl message constraints
255fa74aca3SFrank Schaefer 	 * Zero length reads always succeed, even if no device is connected
256fa74aca3SFrank Schaefer 	 */
257f5ae371aSFrank Schaefer 
25845f04e82SFrank Schaefer 	/* Read data from i2c device */
2590c0d06caSMauro Carvalho Chehab 	ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
2600c0d06caSMauro Carvalho Chehab 	if (ret < 0) {
2617f6301d1SFrank Schaefer 		em28xx_warn("reading from i2c device at 0x%x failed (error=%i)\n",
2627f6301d1SFrank Schaefer 			    addr, ret);
26345f04e82SFrank Schaefer 		return ret;
26445f04e82SFrank Schaefer 	}
265fa74aca3SFrank Schaefer 	/*
266fa74aca3SFrank Schaefer 	 * NOTE: some devices with two i2c busses have the bad habit to return 0
2677f6301d1SFrank Schaefer 	 * bytes if we are on bus B AND there was no write attempt to the
2687f6301d1SFrank Schaefer 	 * specified slave address before AND no device is present at the
2697f6301d1SFrank Schaefer 	 * requested slave address.
270e63b009dSMauro Carvalho Chehab 	 * Anyway, the next check will fail with -ENXIO in this case, so avoid
2717f6301d1SFrank Schaefer 	 * spamming the system log on device probing and do nothing here.
2727f6301d1SFrank Schaefer 	 */
27345f04e82SFrank Schaefer 
27445f04e82SFrank Schaefer 	/* Check success of the i2c operation */
27545f04e82SFrank Schaefer 	ret = dev->em28xx_read_reg(dev, 0x05);
2764b83626aSMauro Carvalho Chehab 	if (ret == 0) /* success */
2774b83626aSMauro Carvalho Chehab 		return len;
27845f04e82SFrank Schaefer 	if (ret < 0) {
2794b83626aSMauro Carvalho Chehab 		em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
280d230d5adSFrank Schaefer 			    ret);
2810c0d06caSMauro Carvalho Chehab 		return ret;
2820c0d06caSMauro Carvalho Chehab 	}
283d845fb3aSMauro Carvalho Chehab 	if (ret == 0x10) {
284d845fb3aSMauro Carvalho Chehab 		if (i2c_debug == 1)
2858ae8cd6cSFrank Schaefer 			em28xx_warn("I2C ACK error on writing to addr 0x%02x\n",
286d845fb3aSMauro Carvalho Chehab 				    addr);
287e63b009dSMauro Carvalho Chehab 		return -ENXIO;
288d845fb3aSMauro Carvalho Chehab 	}
2894b83626aSMauro Carvalho Chehab 
290123a17d1SFrank Schaefer 	if (ret == 0x02 || ret == 0x04) {
291123a17d1SFrank Schaefer 		/* NOTE: these errors seem to be related to clock stretching */
292123a17d1SFrank Schaefer 		if (i2c_debug)
293123a17d1SFrank Schaefer 			em28xx_warn("write to i2c device at 0x%x timed out (status=%i)\n",
294123a17d1SFrank Schaefer 				    addr, ret);
295e63b009dSMauro Carvalho Chehab 		return -ETIMEDOUT;
29645f04e82SFrank Schaefer 	}
2970c0d06caSMauro Carvalho Chehab 
298123a17d1SFrank Schaefer 	em28xx_warn("write to i2c device at 0x%x failed with unknown error (status=%i)\n",
299123a17d1SFrank Schaefer 		    addr, ret);
300123a17d1SFrank Schaefer 	return -EIO;
301123a17d1SFrank Schaefer }
302123a17d1SFrank Schaefer 
3030c0d06caSMauro Carvalho Chehab /*
3040c0d06caSMauro Carvalho Chehab  * em28xx_i2c_check_for_device()
3050c0d06caSMauro Carvalho Chehab  * check if there is a i2c_device at the supplied address
3060c0d06caSMauro Carvalho Chehab  */
307a6bad040SFrank Schaefer static int em28xx_i2c_check_for_device(struct em28xx *dev, u16 addr)
3080c0d06caSMauro Carvalho Chehab {
3090c0d06caSMauro Carvalho Chehab 	int ret;
31045f04e82SFrank Schaefer 	u8 buf;
3110c0d06caSMauro Carvalho Chehab 
31245f04e82SFrank Schaefer 	ret = em28xx_i2c_recv_bytes(dev, addr, &buf, 1);
31345f04e82SFrank Schaefer 	if (ret == 1)
3140c0d06caSMauro Carvalho Chehab 		return 0;
31545f04e82SFrank Schaefer 	return (ret < 0) ? ret : -EIO;
3160c0d06caSMauro Carvalho Chehab }
3170c0d06caSMauro Carvalho Chehab 
3180c0d06caSMauro Carvalho Chehab /*
319a3ea4bf9SFrank Schaefer  * em25xx_bus_B_send_bytes
320a3ea4bf9SFrank Schaefer  * write bytes to the i2c device
321a3ea4bf9SFrank Schaefer  */
322a3ea4bf9SFrank Schaefer static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
323a3ea4bf9SFrank Schaefer 				   u16 len)
324a3ea4bf9SFrank Schaefer {
325a3ea4bf9SFrank Schaefer 	int ret;
326a3ea4bf9SFrank Schaefer 
327a3ea4bf9SFrank Schaefer 	if (len < 1 || len > 64)
328a3ea4bf9SFrank Schaefer 		return -EOPNOTSUPP;
329a3ea4bf9SFrank Schaefer 	/*
330a3ea4bf9SFrank Schaefer 	 * NOTE: limited by the USB ctrl message constraints
331a3ea4bf9SFrank Schaefer 	 * Zero length reads always succeed, even if no device is connected
332a3ea4bf9SFrank Schaefer 	 */
333a3ea4bf9SFrank Schaefer 
334a3ea4bf9SFrank Schaefer 	/* Set register and write value */
335a3ea4bf9SFrank Schaefer 	ret = dev->em28xx_write_regs_req(dev, 0x06, addr, buf, len);
336a3ea4bf9SFrank Schaefer 	if (ret != len) {
337a3ea4bf9SFrank Schaefer 		if (ret < 0) {
338a3ea4bf9SFrank Schaefer 			em28xx_warn("writing to i2c device at 0x%x failed (error=%i)\n",
339a3ea4bf9SFrank Schaefer 				    addr, ret);
340a3ea4bf9SFrank Schaefer 			return ret;
341a3ea4bf9SFrank Schaefer 		} else {
342a3ea4bf9SFrank Schaefer 			em28xx_warn("%i bytes write to i2c device at 0x%x requested, but %i bytes written\n",
343a3ea4bf9SFrank Schaefer 				    len, addr, ret);
344a3ea4bf9SFrank Schaefer 			return -EIO;
345a3ea4bf9SFrank Schaefer 		}
346a3ea4bf9SFrank Schaefer 	}
347a3ea4bf9SFrank Schaefer 	/* Check success */
348a3ea4bf9SFrank Schaefer 	ret = dev->em28xx_read_reg_req(dev, 0x08, 0x0000);
349a3ea4bf9SFrank Schaefer 	/*
350a3ea4bf9SFrank Schaefer 	 * NOTE: the only error we've seen so far is
351a3ea4bf9SFrank Schaefer 	 * 0x01 when the slave device is not present
352a3ea4bf9SFrank Schaefer 	 */
353a3ea4bf9SFrank Schaefer 	if (!ret)
354a3ea4bf9SFrank Schaefer 		return len;
355d845fb3aSMauro Carvalho Chehab 	else if (ret > 0) {
356d845fb3aSMauro Carvalho Chehab 		if (i2c_debug == 1)
3578ae8cd6cSFrank Schaefer 			em28xx_warn("Bus B R08 returned 0x%02x: I2C ACK error\n",
358d845fb3aSMauro Carvalho Chehab 				    ret);
359e63b009dSMauro Carvalho Chehab 		return -ENXIO;
360d845fb3aSMauro Carvalho Chehab 	}
361a3ea4bf9SFrank Schaefer 
362a3ea4bf9SFrank Schaefer 	return ret;
363a3ea4bf9SFrank Schaefer 	/*
364a3ea4bf9SFrank Schaefer 	 * NOTE: With chip types (other chip IDs) which actually don't support
365a3ea4bf9SFrank Schaefer 	 * this operation, it seems to succeed ALWAYS ! (even if there is no
366a3ea4bf9SFrank Schaefer 	 * slave device or even no second i2c bus provided)
367a3ea4bf9SFrank Schaefer 	 */
368a3ea4bf9SFrank Schaefer }
369a3ea4bf9SFrank Schaefer 
370a3ea4bf9SFrank Schaefer /*
371a3ea4bf9SFrank Schaefer  * em25xx_bus_B_recv_bytes
372a3ea4bf9SFrank Schaefer  * read bytes from the i2c device
373a3ea4bf9SFrank Schaefer  */
374a3ea4bf9SFrank Schaefer static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf,
375a3ea4bf9SFrank Schaefer 				   u16 len)
376a3ea4bf9SFrank Schaefer {
377a3ea4bf9SFrank Schaefer 	int ret;
378a3ea4bf9SFrank Schaefer 
379a3ea4bf9SFrank Schaefer 	if (len < 1 || len > 64)
380a3ea4bf9SFrank Schaefer 		return -EOPNOTSUPP;
381a3ea4bf9SFrank Schaefer 	/*
382a3ea4bf9SFrank Schaefer 	 * NOTE: limited by the USB ctrl message constraints
383a3ea4bf9SFrank Schaefer 	 * Zero length reads always succeed, even if no device is connected
384a3ea4bf9SFrank Schaefer 	 */
385a3ea4bf9SFrank Schaefer 
386a3ea4bf9SFrank Schaefer 	/* Read value */
387a3ea4bf9SFrank Schaefer 	ret = dev->em28xx_read_reg_req_len(dev, 0x06, addr, buf, len);
388a3ea4bf9SFrank Schaefer 	if (ret < 0) {
389a3ea4bf9SFrank Schaefer 		em28xx_warn("reading from i2c device at 0x%x failed (error=%i)\n",
390a3ea4bf9SFrank Schaefer 			    addr, ret);
391a3ea4bf9SFrank Schaefer 		return ret;
392a3ea4bf9SFrank Schaefer 	}
393a3ea4bf9SFrank Schaefer 	/*
394a3ea4bf9SFrank Schaefer 	 * NOTE: some devices with two i2c busses have the bad habit to return 0
395a3ea4bf9SFrank Schaefer 	 * bytes if we are on bus B AND there was no write attempt to the
396a3ea4bf9SFrank Schaefer 	 * specified slave address before AND no device is present at the
397a3ea4bf9SFrank Schaefer 	 * requested slave address.
398e63b009dSMauro Carvalho Chehab 	 * Anyway, the next check will fail with -ENXIO in this case, so avoid
399a3ea4bf9SFrank Schaefer 	 * spamming the system log on device probing and do nothing here.
400a3ea4bf9SFrank Schaefer 	 */
401a3ea4bf9SFrank Schaefer 
402a3ea4bf9SFrank Schaefer 	/* Check success */
403a3ea4bf9SFrank Schaefer 	ret = dev->em28xx_read_reg_req(dev, 0x08, 0x0000);
404a3ea4bf9SFrank Schaefer 	/*
405a3ea4bf9SFrank Schaefer 	 * NOTE: the only error we've seen so far is
406a3ea4bf9SFrank Schaefer 	 * 0x01 when the slave device is not present
407a3ea4bf9SFrank Schaefer 	 */
408a3ea4bf9SFrank Schaefer 	if (!ret)
409a3ea4bf9SFrank Schaefer 		return len;
410d845fb3aSMauro Carvalho Chehab 	else if (ret > 0) {
411d845fb3aSMauro Carvalho Chehab 		if (i2c_debug == 1)
4128ae8cd6cSFrank Schaefer 			em28xx_warn("Bus B R08 returned 0x%02x: I2C ACK error\n",
413d845fb3aSMauro Carvalho Chehab 				    ret);
414e63b009dSMauro Carvalho Chehab 		return -ENXIO;
415d845fb3aSMauro Carvalho Chehab 	}
416a3ea4bf9SFrank Schaefer 
417a3ea4bf9SFrank Schaefer 	return ret;
418a3ea4bf9SFrank Schaefer 	/*
419a3ea4bf9SFrank Schaefer 	 * NOTE: With chip types (other chip IDs) which actually don't support
420a3ea4bf9SFrank Schaefer 	 * this operation, it seems to succeed ALWAYS ! (even if there is no
421a3ea4bf9SFrank Schaefer 	 * slave device or even no second i2c bus provided)
422a3ea4bf9SFrank Schaefer 	 */
423a3ea4bf9SFrank Schaefer }
424a3ea4bf9SFrank Schaefer 
425a3ea4bf9SFrank Schaefer /*
426a3ea4bf9SFrank Schaefer  * em25xx_bus_B_check_for_device()
427a3ea4bf9SFrank Schaefer  * check if there is a i2c device at the supplied address
428a3ea4bf9SFrank Schaefer  */
429a3ea4bf9SFrank Schaefer static int em25xx_bus_B_check_for_device(struct em28xx *dev, u16 addr)
430a3ea4bf9SFrank Schaefer {
431a3ea4bf9SFrank Schaefer 	u8 buf;
432a3ea4bf9SFrank Schaefer 	int ret;
433a3ea4bf9SFrank Schaefer 
434a3ea4bf9SFrank Schaefer 	ret = em25xx_bus_B_recv_bytes(dev, addr, &buf, 1);
435a3ea4bf9SFrank Schaefer 	if (ret < 0)
436a3ea4bf9SFrank Schaefer 		return ret;
437a3ea4bf9SFrank Schaefer 
438a3ea4bf9SFrank Schaefer 	return 0;
439a3ea4bf9SFrank Schaefer 	/*
440a3ea4bf9SFrank Schaefer 	 * NOTE: With chips which do not support this operation,
441a3ea4bf9SFrank Schaefer 	 * it seems to succeed ALWAYS ! (even if no device connected)
442a3ea4bf9SFrank Schaefer 	 */
443a3ea4bf9SFrank Schaefer }
444a3ea4bf9SFrank Schaefer 
445a3ea4bf9SFrank Schaefer static inline int i2c_check_for_device(struct em28xx_i2c_bus *i2c_bus, u16 addr)
446a3ea4bf9SFrank Schaefer {
447a3ea4bf9SFrank Schaefer 	struct em28xx *dev = i2c_bus->dev;
448a3ea4bf9SFrank Schaefer 	int rc = -EOPNOTSUPP;
449a3ea4bf9SFrank Schaefer 
450a3ea4bf9SFrank Schaefer 	if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX)
451a3ea4bf9SFrank Schaefer 		rc = em28xx_i2c_check_for_device(dev, addr);
452a3ea4bf9SFrank Schaefer 	else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800)
453a3ea4bf9SFrank Schaefer 		rc = em2800_i2c_check_for_device(dev, addr);
454a3ea4bf9SFrank Schaefer 	else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)
455a3ea4bf9SFrank Schaefer 		rc = em25xx_bus_B_check_for_device(dev, addr);
456a3ea4bf9SFrank Schaefer 	return rc;
457a3ea4bf9SFrank Schaefer }
458a3ea4bf9SFrank Schaefer 
459a3ea4bf9SFrank Schaefer static inline int i2c_recv_bytes(struct em28xx_i2c_bus *i2c_bus,
460a3ea4bf9SFrank Schaefer 				 struct i2c_msg msg)
461a3ea4bf9SFrank Schaefer {
462a3ea4bf9SFrank Schaefer 	struct em28xx *dev = i2c_bus->dev;
463a3ea4bf9SFrank Schaefer 	u16 addr = msg.addr << 1;
46450f0a9dfSMauro Carvalho Chehab 	int rc = -EOPNOTSUPP;
465a3ea4bf9SFrank Schaefer 
466a3ea4bf9SFrank Schaefer 	if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX)
467a3ea4bf9SFrank Schaefer 		rc = em28xx_i2c_recv_bytes(dev, addr, msg.buf, msg.len);
468a3ea4bf9SFrank Schaefer 	else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800)
469a3ea4bf9SFrank Schaefer 		rc = em2800_i2c_recv_bytes(dev, addr, msg.buf, msg.len);
470a3ea4bf9SFrank Schaefer 	else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)
471a3ea4bf9SFrank Schaefer 		rc = em25xx_bus_B_recv_bytes(dev, addr, msg.buf, msg.len);
472a3ea4bf9SFrank Schaefer 	return rc;
473a3ea4bf9SFrank Schaefer }
474a3ea4bf9SFrank Schaefer 
475a3ea4bf9SFrank Schaefer static inline int i2c_send_bytes(struct em28xx_i2c_bus *i2c_bus,
476a3ea4bf9SFrank Schaefer 				 struct i2c_msg msg, int stop)
477a3ea4bf9SFrank Schaefer {
478a3ea4bf9SFrank Schaefer 	struct em28xx *dev = i2c_bus->dev;
479a3ea4bf9SFrank Schaefer 	u16 addr = msg.addr << 1;
48050f0a9dfSMauro Carvalho Chehab 	int rc = -EOPNOTSUPP;
481a3ea4bf9SFrank Schaefer 
482a3ea4bf9SFrank Schaefer 	if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX)
483a3ea4bf9SFrank Schaefer 		rc = em28xx_i2c_send_bytes(dev, addr, msg.buf, msg.len, stop);
484a3ea4bf9SFrank Schaefer 	else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800)
485a3ea4bf9SFrank Schaefer 		rc = em2800_i2c_send_bytes(dev, addr, msg.buf, msg.len);
486a3ea4bf9SFrank Schaefer 	else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)
487a3ea4bf9SFrank Schaefer 		rc = em25xx_bus_B_send_bytes(dev, addr, msg.buf, msg.len);
488a3ea4bf9SFrank Schaefer 	return rc;
489a3ea4bf9SFrank Schaefer }
490a3ea4bf9SFrank Schaefer 
491a3ea4bf9SFrank Schaefer /*
4920c0d06caSMauro Carvalho Chehab  * em28xx_i2c_xfer()
4930c0d06caSMauro Carvalho Chehab  * the main i2c transfer function
4940c0d06caSMauro Carvalho Chehab  */
4950c0d06caSMauro Carvalho Chehab static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
4960c0d06caSMauro Carvalho Chehab 			   struct i2c_msg msgs[], int num)
4970c0d06caSMauro Carvalho Chehab {
498aab3125cSMauro Carvalho Chehab 	struct em28xx_i2c_bus *i2c_bus = i2c_adap->algo_data;
499aab3125cSMauro Carvalho Chehab 	struct em28xx *dev = i2c_bus->dev;
500aab3125cSMauro Carvalho Chehab 	unsigned bus = i2c_bus->bus;
501a3ea4bf9SFrank Schaefer 	int addr, rc, i;
5023190fbeeSMauro Carvalho Chehab 	u8 reg;
5030c0d06caSMauro Carvalho Chehab 
504*cc5c5d20SShuah Khan 	/* prevent i2c xfer attempts after device is disconnected
505*cc5c5d20SShuah Khan 	   some fe's try to do i2c writes/reads from their release
506*cc5c5d20SShuah Khan 	   interfaces when called in disconnect path */
507*cc5c5d20SShuah Khan 	if (dev->disconnected)
508*cc5c5d20SShuah Khan 		return -ENODEV;
509*cc5c5d20SShuah Khan 
510aab3125cSMauro Carvalho Chehab 	rc = rt_mutex_trylock(&dev->i2c_bus_lock);
511aab3125cSMauro Carvalho Chehab 	if (rc < 0)
512aab3125cSMauro Carvalho Chehab 		return rc;
513aab3125cSMauro Carvalho Chehab 
514aab3125cSMauro Carvalho Chehab 	/* Switch I2C bus if needed */
515a3ea4bf9SFrank Schaefer 	if (bus != dev->cur_i2c_bus &&
516a3ea4bf9SFrank Schaefer 	    i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX) {
517aab3125cSMauro Carvalho Chehab 		if (bus == 1)
5183190fbeeSMauro Carvalho Chehab 			reg = EM2874_I2C_SECONDARY_BUS_SELECT;
519aab3125cSMauro Carvalho Chehab 		else
5203190fbeeSMauro Carvalho Chehab 			reg = 0;
5213190fbeeSMauro Carvalho Chehab 		em28xx_write_reg_bits(dev, EM28XX_R06_I2C_CLK, reg,
5223190fbeeSMauro Carvalho Chehab 				      EM2874_I2C_SECONDARY_BUS_SELECT);
523aab3125cSMauro Carvalho Chehab 		dev->cur_i2c_bus = bus;
524aab3125cSMauro Carvalho Chehab 	}
525aab3125cSMauro Carvalho Chehab 
526aab3125cSMauro Carvalho Chehab 	if (num <= 0) {
527aab3125cSMauro Carvalho Chehab 		rt_mutex_unlock(&dev->i2c_bus_lock);
5280c0d06caSMauro Carvalho Chehab 		return 0;
529aab3125cSMauro Carvalho Chehab 	}
5300c0d06caSMauro Carvalho Chehab 	for (i = 0; i < num; i++) {
5310c0d06caSMauro Carvalho Chehab 		addr = msgs[i].addr << 1;
53250f0a9dfSMauro Carvalho Chehab 		if (i2c_debug > 1)
533d7a80eaaSFrank Schaefer 			printk(KERN_DEBUG "%s at %s: %s %s addr=%02x len=%d:",
534d7a80eaaSFrank Schaefer 			       dev->name, __func__ ,
5350c0d06caSMauro Carvalho Chehab 			       (msgs[i].flags & I2C_M_RD) ? "read" : "write",
536d7a80eaaSFrank Schaefer 			       i == num - 1 ? "stop" : "nonstop",
537d7a80eaaSFrank Schaefer 			       addr, msgs[i].len);
538e63b009dSMauro Carvalho Chehab 		if (!msgs[i].len) {
539e63b009dSMauro Carvalho Chehab 			/*
540e63b009dSMauro Carvalho Chehab 			 * no len: check only for device presence
541e63b009dSMauro Carvalho Chehab 			 * This code is only called during device probe.
542e63b009dSMauro Carvalho Chehab 			 */
543a3ea4bf9SFrank Schaefer 			rc = i2c_check_for_device(i2c_bus, addr);
54450f0a9dfSMauro Carvalho Chehab 			if (rc < 0) {
545e63b009dSMauro Carvalho Chehab 				if (rc == -ENXIO) {
54650f0a9dfSMauro Carvalho Chehab 					if (i2c_debug > 1)
54750f0a9dfSMauro Carvalho Chehab 						printk(KERN_CONT " no device\n");
54850f0a9dfSMauro Carvalho Chehab 					rc = -ENODEV;
54950f0a9dfSMauro Carvalho Chehab 				} else {
55050f0a9dfSMauro Carvalho Chehab 					if (i2c_debug > 1)
55150f0a9dfSMauro Carvalho Chehab 						printk(KERN_CONT " ERROR: %i\n", rc);
55250f0a9dfSMauro Carvalho Chehab 				}
553aab3125cSMauro Carvalho Chehab 				rt_mutex_unlock(&dev->i2c_bus_lock);
55450f0a9dfSMauro Carvalho Chehab 				return rc;
5550c0d06caSMauro Carvalho Chehab 			}
5560c0d06caSMauro Carvalho Chehab 		} else if (msgs[i].flags & I2C_M_RD) {
5570c0d06caSMauro Carvalho Chehab 			/* read bytes */
558a3ea4bf9SFrank Schaefer 			rc = i2c_recv_bytes(i2c_bus, msgs[i]);
55950f0a9dfSMauro Carvalho Chehab 
56050f0a9dfSMauro Carvalho Chehab 			if (i2c_debug > 1 && rc >= 0)
56150f0a9dfSMauro Carvalho Chehab 				printk(KERN_CONT " %*ph",
56250f0a9dfSMauro Carvalho Chehab 				       msgs[i].len, msgs[i].buf);
5630c0d06caSMauro Carvalho Chehab 		} else {
56450f0a9dfSMauro Carvalho Chehab 			if (i2c_debug > 1)
56550f0a9dfSMauro Carvalho Chehab 				printk(KERN_CONT " %*ph",
56650f0a9dfSMauro Carvalho Chehab 				       msgs[i].len, msgs[i].buf);
56750f0a9dfSMauro Carvalho Chehab 
5680c0d06caSMauro Carvalho Chehab 			/* write bytes */
569a3ea4bf9SFrank Schaefer 			rc = i2c_send_bytes(i2c_bus, msgs[i], i == num - 1);
5700c0d06caSMauro Carvalho Chehab 		}
57145f04e82SFrank Schaefer 		if (rc < 0) {
57250f0a9dfSMauro Carvalho Chehab 			if (i2c_debug > 1)
57350f0a9dfSMauro Carvalho Chehab 				printk(KERN_CONT " ERROR: %i\n", rc);
574aab3125cSMauro Carvalho Chehab 			rt_mutex_unlock(&dev->i2c_bus_lock);
57545f04e82SFrank Schaefer 			return rc;
57645f04e82SFrank Schaefer 		}
57750f0a9dfSMauro Carvalho Chehab 		if (i2c_debug > 1)
57850f0a9dfSMauro Carvalho Chehab 			printk(KERN_CONT "\n");
5790c0d06caSMauro Carvalho Chehab 	}
5800c0d06caSMauro Carvalho Chehab 
581aab3125cSMauro Carvalho Chehab 	rt_mutex_unlock(&dev->i2c_bus_lock);
5820c0d06caSMauro Carvalho Chehab 	return num;
5830c0d06caSMauro Carvalho Chehab }
5840c0d06caSMauro Carvalho Chehab 
585fa74aca3SFrank Schaefer /*
586fa74aca3SFrank Schaefer  * based on linux/sunrpc/svcauth.h and linux/hash.h
5870c0d06caSMauro Carvalho Chehab  * The original hash function returns a different value, if arch is x86_64
5880c0d06caSMauro Carvalho Chehab  * or i386.
5890c0d06caSMauro Carvalho Chehab  */
5900c0d06caSMauro Carvalho Chehab static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits)
5910c0d06caSMauro Carvalho Chehab {
5920c0d06caSMauro Carvalho Chehab 	unsigned long hash = 0;
5930c0d06caSMauro Carvalho Chehab 	unsigned long l = 0;
5940c0d06caSMauro Carvalho Chehab 	int len = 0;
5950c0d06caSMauro Carvalho Chehab 	unsigned char c;
5960c0d06caSMauro Carvalho Chehab 	do {
5970c0d06caSMauro Carvalho Chehab 		if (len == length) {
5980c0d06caSMauro Carvalho Chehab 			c = (char)len;
5990c0d06caSMauro Carvalho Chehab 			len = -1;
6000c0d06caSMauro Carvalho Chehab 		} else
6010c0d06caSMauro Carvalho Chehab 			c = *buf++;
6020c0d06caSMauro Carvalho Chehab 		l = (l << 8) | c;
6030c0d06caSMauro Carvalho Chehab 		len++;
6040c0d06caSMauro Carvalho Chehab 		if ((len & (32 / 8 - 1)) == 0)
6050c0d06caSMauro Carvalho Chehab 			hash = ((hash^l) * 0x9e370001UL);
6060c0d06caSMauro Carvalho Chehab 	} while (len);
6070c0d06caSMauro Carvalho Chehab 
6080c0d06caSMauro Carvalho Chehab 	return (hash >> (32 - bits)) & 0xffffffffUL;
6090c0d06caSMauro Carvalho Chehab }
6100c0d06caSMauro Carvalho Chehab 
611fa74aca3SFrank Schaefer /*
612fa74aca3SFrank Schaefer  * Helper function to read data blocks from i2c clients with 8 or 16 bit
613fa74aca3SFrank Schaefer  * address width, 8 bit register width and auto incrementation been activated
614fa74aca3SFrank Schaefer  */
615aab3125cSMauro Carvalho Chehab static int em28xx_i2c_read_block(struct em28xx *dev, unsigned bus, u16 addr,
616aab3125cSMauro Carvalho Chehab 				 bool addr_w16, u16 len, u8 *data)
617d832c5b2SFrank Schaefer {
618d832c5b2SFrank Schaefer 	int remain = len, rsize, rsize_max, ret;
619d832c5b2SFrank Schaefer 	u8 buf[2];
620d832c5b2SFrank Schaefer 
621d832c5b2SFrank Schaefer 	/* Sanity check */
622d832c5b2SFrank Schaefer 	if (addr + remain > (addr_w16 * 0xff00 + 0xff + 1))
623d832c5b2SFrank Schaefer 		return -EINVAL;
624d832c5b2SFrank Schaefer 	/* Select address */
625d832c5b2SFrank Schaefer 	buf[0] = addr >> 8;
626d832c5b2SFrank Schaefer 	buf[1] = addr & 0xff;
627aab3125cSMauro Carvalho Chehab 	ret = i2c_master_send(&dev->i2c_client[bus], buf + !addr_w16, 1 + addr_w16);
628d832c5b2SFrank Schaefer 	if (ret < 0)
629d832c5b2SFrank Schaefer 		return ret;
630d832c5b2SFrank Schaefer 	/* Read data */
631d832c5b2SFrank Schaefer 	if (dev->board.is_em2800)
632d832c5b2SFrank Schaefer 		rsize_max = 4;
633d832c5b2SFrank Schaefer 	else
634d832c5b2SFrank Schaefer 		rsize_max = 64;
635d832c5b2SFrank Schaefer 	while (remain > 0) {
636d832c5b2SFrank Schaefer 		if (remain > rsize_max)
637d832c5b2SFrank Schaefer 			rsize = rsize_max;
638d832c5b2SFrank Schaefer 		else
639d832c5b2SFrank Schaefer 			rsize = remain;
640d832c5b2SFrank Schaefer 
641aab3125cSMauro Carvalho Chehab 		ret = i2c_master_recv(&dev->i2c_client[bus], data, rsize);
642d832c5b2SFrank Schaefer 		if (ret < 0)
643d832c5b2SFrank Schaefer 			return ret;
644d832c5b2SFrank Schaefer 
645d832c5b2SFrank Schaefer 		remain -= rsize;
646d832c5b2SFrank Schaefer 		data += rsize;
647d832c5b2SFrank Schaefer 	}
648d832c5b2SFrank Schaefer 
649d832c5b2SFrank Schaefer 	return len;
650d832c5b2SFrank Schaefer }
651d832c5b2SFrank Schaefer 
652aab3125cSMauro Carvalho Chehab static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus,
653aab3125cSMauro Carvalho Chehab 			     u8 **eedata, u16 *eedata_len)
6540c0d06caSMauro Carvalho Chehab {
655510e884cSFrank Schaefer 	const u16 len = 256;
656fa74aca3SFrank Schaefer 	/*
657fa74aca3SFrank Schaefer 	 * FIXME common length/size for bytes to read, to display, hash
658510e884cSFrank Schaefer 	 * calculation and returned device dataset. Simplifies the code a lot,
659fa74aca3SFrank Schaefer 	 * but we might have to deal with multiple sizes in the future !
660fa74aca3SFrank Schaefer 	 */
66150f0a9dfSMauro Carvalho Chehab 	int err;
662510e884cSFrank Schaefer 	struct em28xx_eeprom *dev_config;
663510e884cSFrank Schaefer 	u8 buf, *data;
6640c0d06caSMauro Carvalho Chehab 
665a217968fSFrank Schaefer 	*eedata = NULL;
666510e884cSFrank Schaefer 	*eedata_len = 0;
667a217968fSFrank Schaefer 
668aab3125cSMauro Carvalho Chehab 	/* EEPROM is always on i2c bus 0 on all known devices. */
669aab3125cSMauro Carvalho Chehab 
670aab3125cSMauro Carvalho Chehab 	dev->i2c_client[bus].addr = 0xa0 >> 1;
6710c0d06caSMauro Carvalho Chehab 
6720c0d06caSMauro Carvalho Chehab 	/* Check if board has eeprom */
673aab3125cSMauro Carvalho Chehab 	err = i2c_master_recv(&dev->i2c_client[bus], &buf, 0);
6740c0d06caSMauro Carvalho Chehab 	if (err < 0) {
67512d7ce18SFrank Schaefer 		em28xx_info("board has no eeprom\n");
6760c0d06caSMauro Carvalho Chehab 		return -ENODEV;
6770c0d06caSMauro Carvalho Chehab 	}
6780c0d06caSMauro Carvalho Chehab 
679a217968fSFrank Schaefer 	data = kzalloc(len, GFP_KERNEL);
680a217968fSFrank Schaefer 	if (data == NULL)
681a217968fSFrank Schaefer 		return -ENOMEM;
682a217968fSFrank Schaefer 
683d832c5b2SFrank Schaefer 	/* Read EEPROM content */
684aab3125cSMauro Carvalho Chehab 	err = em28xx_i2c_read_block(dev, bus, 0x0000,
685aab3125cSMauro Carvalho Chehab 				    dev->eeprom_addrwidth_16bit,
686a217968fSFrank Schaefer 				    len, data);
687d832c5b2SFrank Schaefer 	if (err != len) {
68812d7ce18SFrank Schaefer 		em28xx_errdev("failed to read eeprom (err=%d)\n", err);
689510e884cSFrank Schaefer 		goto error;
6900c0d06caSMauro Carvalho Chehab 	}
69190271964SFrank Schaefer 
69250f0a9dfSMauro Carvalho Chehab 	if (i2c_debug) {
69387b52439SFrank Schaefer 		/* Display eeprom content */
69450f0a9dfSMauro Carvalho Chehab 		print_hex_dump(KERN_INFO, "eeprom ", DUMP_PREFIX_OFFSET,
69550f0a9dfSMauro Carvalho Chehab 			       16, 1, data, len, true);
69650f0a9dfSMauro Carvalho Chehab 
69787b52439SFrank Schaefer 		if (dev->eeprom_addrwidth_16bit)
69850f0a9dfSMauro Carvalho Chehab 			em28xx_info("eeprom %06x: ... (skipped)\n", 256);
69987b52439SFrank Schaefer 	}
7000c0d06caSMauro Carvalho Chehab 
70187b52439SFrank Schaefer 	if (dev->eeprom_addrwidth_16bit &&
702a217968fSFrank Schaefer 	    data[0] == 0x26 && data[3] == 0x00) {
70387b52439SFrank Schaefer 		/* new eeprom format; size 4-64kb */
704510e884cSFrank Schaefer 		u16 mc_start;
705510e884cSFrank Schaefer 		u16 hwconf_offset;
706510e884cSFrank Schaefer 
707a217968fSFrank Schaefer 		dev->hash = em28xx_hash_mem(data, len, 32);
708510e884cSFrank Schaefer 		mc_start = (data[1] << 8) + 4;	/* usually 0x0004 */
709510e884cSFrank Schaefer 
710d230d5adSFrank Schaefer 		em28xx_info("EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n",
711510e884cSFrank Schaefer 			    data[0], data[1], data[2], data[3], dev->hash);
712510e884cSFrank Schaefer 		em28xx_info("EEPROM info:\n");
713d230d5adSFrank Schaefer 		em28xx_info("\tmicrocode start address = 0x%04x, boot configuration = 0x%02x\n",
714510e884cSFrank Schaefer 			    mc_start, data[2]);
715fa74aca3SFrank Schaefer 		/*
716fa74aca3SFrank Schaefer 		 * boot configuration (address 0x0002):
71787b52439SFrank Schaefer 		 * [0]   microcode download speed: 1 = 400 kHz; 0 = 100 kHz
71887b52439SFrank Schaefer 		 * [1]   always selects 12 kb RAM
71987b52439SFrank Schaefer 		 * [2]   USB device speed: 1 = force Full Speed; 0 = auto detect
72087b52439SFrank Schaefer 		 * [4]   1 = force fast mode and no suspend for device testing
72187b52439SFrank Schaefer 		 * [5:7] USB PHY tuning registers; determined by device
72287b52439SFrank Schaefer 		 *       characterization
72387b52439SFrank Schaefer 		 */
72487b52439SFrank Schaefer 
725fa74aca3SFrank Schaefer 		/*
726fa74aca3SFrank Schaefer 		 * Read hardware config dataset offset from address
727fa74aca3SFrank Schaefer 		 * (microcode start + 46)
728fa74aca3SFrank Schaefer 		 */
729aab3125cSMauro Carvalho Chehab 		err = em28xx_i2c_read_block(dev, bus, mc_start + 46, 1, 2,
730aab3125cSMauro Carvalho Chehab 					    data);
731510e884cSFrank Schaefer 		if (err != 2) {
732510e884cSFrank Schaefer 			em28xx_errdev("failed to read hardware configuration data from eeprom (err=%d)\n",
733510e884cSFrank Schaefer 				      err);
734510e884cSFrank Schaefer 			goto error;
735510e884cSFrank Schaefer 		}
73687b52439SFrank Schaefer 
737510e884cSFrank Schaefer 		/* Calculate hardware config dataset start address */
738510e884cSFrank Schaefer 		hwconf_offset = mc_start + data[0] + (data[1] << 8);
739510e884cSFrank Schaefer 
740510e884cSFrank Schaefer 		/* Read hardware config dataset */
741fa74aca3SFrank Schaefer 		/*
742fa74aca3SFrank Schaefer 		 * NOTE: the microcode copy can be multiple pages long, but
743510e884cSFrank Schaefer 		 * we assume the hardware config dataset is the same as in
744510e884cSFrank Schaefer 		 * the old eeprom and not longer than 256 bytes.
745510e884cSFrank Schaefer 		 * tveeprom is currently also limited to 256 bytes.
746510e884cSFrank Schaefer 		 */
747aab3125cSMauro Carvalho Chehab 		err = em28xx_i2c_read_block(dev, bus, hwconf_offset, 1, len,
748aab3125cSMauro Carvalho Chehab 					    data);
749510e884cSFrank Schaefer 		if (err != len) {
750510e884cSFrank Schaefer 			em28xx_errdev("failed to read hardware configuration data from eeprom (err=%d)\n",
751510e884cSFrank Schaefer 				      err);
752510e884cSFrank Schaefer 			goto error;
753510e884cSFrank Schaefer 		}
754510e884cSFrank Schaefer 
755510e884cSFrank Schaefer 		/* Verify hardware config dataset */
756510e884cSFrank Schaefer 		/* NOTE: not all devices provide this type of dataset */
757510e884cSFrank Schaefer 		if (data[0] != 0x1a || data[1] != 0xeb ||
758a217968fSFrank Schaefer 		    data[2] != 0x67 || data[3] != 0x95) {
759510e884cSFrank Schaefer 			em28xx_info("\tno hardware configuration dataset found in eeprom\n");
760510e884cSFrank Schaefer 			kfree(data);
761510e884cSFrank Schaefer 			return 0;
762510e884cSFrank Schaefer 		}
763510e884cSFrank Schaefer 
764510e884cSFrank Schaefer 		/* TODO: decrypt eeprom data for camera bridges (em25xx, em276x+) */
765510e884cSFrank Schaefer 
766510e884cSFrank Schaefer 	} else if (!dev->eeprom_addrwidth_16bit &&
767510e884cSFrank Schaefer 		   data[0] == 0x1a && data[1] == 0xeb &&
768510e884cSFrank Schaefer 		   data[2] == 0x67 && data[3] == 0x95) {
769510e884cSFrank Schaefer 		dev->hash = em28xx_hash_mem(data, len, 32);
770d230d5adSFrank Schaefer 		em28xx_info("EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n",
771510e884cSFrank Schaefer 			    data[0], data[1], data[2], data[3], dev->hash);
772510e884cSFrank Schaefer 		em28xx_info("EEPROM info:\n");
773510e884cSFrank Schaefer 	} else {
77487b52439SFrank Schaefer 		em28xx_info("unknown eeprom format or eeprom corrupted !\n");
775510e884cSFrank Schaefer 		err = -ENODEV;
776510e884cSFrank Schaefer 		goto error;
777f55eacbeSFrank Schaefer 	}
778f55eacbeSFrank Schaefer 
779a217968fSFrank Schaefer 	*eedata = data;
780510e884cSFrank Schaefer 	*eedata_len = len;
78132bf7c6cSAlban Browaeys 	dev_config = (void *)*eedata;
782a217968fSFrank Schaefer 
783510e884cSFrank Schaefer 	switch (le16_to_cpu(dev_config->chip_conf) >> 4 & 0x3) {
7840c0d06caSMauro Carvalho Chehab 	case 0:
78512d7ce18SFrank Schaefer 		em28xx_info("\tNo audio on board.\n");
7860c0d06caSMauro Carvalho Chehab 		break;
7870c0d06caSMauro Carvalho Chehab 	case 1:
78812d7ce18SFrank Schaefer 		em28xx_info("\tAC97 audio (5 sample rates)\n");
7890c0d06caSMauro Carvalho Chehab 		break;
7900c0d06caSMauro Carvalho Chehab 	case 2:
791687ff8b0SFrank Schaefer 		if (dev->chip_id < CHIP_ID_EM2860)
79212d7ce18SFrank Schaefer 			em28xx_info("\tI2S audio, sample rate=32k\n");
793687ff8b0SFrank Schaefer 		else
794687ff8b0SFrank Schaefer 			em28xx_info("\tI2S audio, 3 sample rates\n");
7950c0d06caSMauro Carvalho Chehab 		break;
7960c0d06caSMauro Carvalho Chehab 	case 3:
797687ff8b0SFrank Schaefer 		if (dev->chip_id < CHIP_ID_EM2860)
79812d7ce18SFrank Schaefer 			em28xx_info("\tI2S audio, 3 sample rates\n");
799687ff8b0SFrank Schaefer 		else
800687ff8b0SFrank Schaefer 			em28xx_info("\tI2S audio, 5 sample rates\n");
8010c0d06caSMauro Carvalho Chehab 		break;
8020c0d06caSMauro Carvalho Chehab 	}
8030c0d06caSMauro Carvalho Chehab 
804510e884cSFrank Schaefer 	if (le16_to_cpu(dev_config->chip_conf) & 1 << 3)
80512d7ce18SFrank Schaefer 		em28xx_info("\tUSB Remote wakeup capable\n");
8060c0d06caSMauro Carvalho Chehab 
807510e884cSFrank Schaefer 	if (le16_to_cpu(dev_config->chip_conf) & 1 << 2)
80812d7ce18SFrank Schaefer 		em28xx_info("\tUSB Self power capable\n");
8090c0d06caSMauro Carvalho Chehab 
810510e884cSFrank Schaefer 	switch (le16_to_cpu(dev_config->chip_conf) & 0x3) {
8110c0d06caSMauro Carvalho Chehab 	case 0:
81212d7ce18SFrank Schaefer 		em28xx_info("\t500mA max power\n");
8130c0d06caSMauro Carvalho Chehab 		break;
8140c0d06caSMauro Carvalho Chehab 	case 1:
81512d7ce18SFrank Schaefer 		em28xx_info("\t400mA max power\n");
8160c0d06caSMauro Carvalho Chehab 		break;
8170c0d06caSMauro Carvalho Chehab 	case 2:
81812d7ce18SFrank Schaefer 		em28xx_info("\t300mA max power\n");
8190c0d06caSMauro Carvalho Chehab 		break;
8200c0d06caSMauro Carvalho Chehab 	case 3:
82112d7ce18SFrank Schaefer 		em28xx_info("\t200mA max power\n");
8220c0d06caSMauro Carvalho Chehab 		break;
8230c0d06caSMauro Carvalho Chehab 	}
82412d7ce18SFrank Schaefer 	em28xx_info("\tTable at offset 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
825510e884cSFrank Schaefer 		    dev_config->string_idx_table,
826510e884cSFrank Schaefer 		    le16_to_cpu(dev_config->string1),
827510e884cSFrank Schaefer 		    le16_to_cpu(dev_config->string2),
828510e884cSFrank Schaefer 		    le16_to_cpu(dev_config->string3));
8290c0d06caSMauro Carvalho Chehab 
8300c0d06caSMauro Carvalho Chehab 	return 0;
831510e884cSFrank Schaefer 
832510e884cSFrank Schaefer error:
833510e884cSFrank Schaefer 	kfree(data);
834510e884cSFrank Schaefer 	return err;
8350c0d06caSMauro Carvalho Chehab }
8360c0d06caSMauro Carvalho Chehab 
8370c0d06caSMauro Carvalho Chehab /* ----------------------------------------------------------- */
8380c0d06caSMauro Carvalho Chehab 
8390c0d06caSMauro Carvalho Chehab /*
8400c0d06caSMauro Carvalho Chehab  * functionality()
8410c0d06caSMauro Carvalho Chehab  */
842aab3125cSMauro Carvalho Chehab static u32 functionality(struct i2c_adapter *i2c_adap)
8430c0d06caSMauro Carvalho Chehab {
844aab3125cSMauro Carvalho Chehab 	struct em28xx_i2c_bus *i2c_bus = i2c_adap->algo_data;
845aab3125cSMauro Carvalho Chehab 
846a3ea4bf9SFrank Schaefer 	if ((i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX) ||
847a3ea4bf9SFrank Schaefer 	    (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)) {
848a3ea4bf9SFrank Schaefer 		return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
849a3ea4bf9SFrank Schaefer 	} else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800)  {
850a3ea4bf9SFrank Schaefer 		return (I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL) &
851a3ea4bf9SFrank Schaefer 			~I2C_FUNC_SMBUS_WRITE_BLOCK_DATA;
852a3ea4bf9SFrank Schaefer 	}
853a3ea4bf9SFrank Schaefer 
854a3ea4bf9SFrank Schaefer 	WARN(1, "Unknown i2c bus algorithm.\n");
855a3ea4bf9SFrank Schaefer 	return 0;
8560c0d06caSMauro Carvalho Chehab }
8570c0d06caSMauro Carvalho Chehab 
8580c0d06caSMauro Carvalho Chehab static struct i2c_algorithm em28xx_algo = {
8590c0d06caSMauro Carvalho Chehab 	.master_xfer   = em28xx_i2c_xfer,
8600c0d06caSMauro Carvalho Chehab 	.functionality = functionality,
8610c0d06caSMauro Carvalho Chehab };
8620c0d06caSMauro Carvalho Chehab 
8630c0d06caSMauro Carvalho Chehab static struct i2c_adapter em28xx_adap_template = {
8640c0d06caSMauro Carvalho Chehab 	.owner = THIS_MODULE,
8650c0d06caSMauro Carvalho Chehab 	.name = "em28xx",
8660c0d06caSMauro Carvalho Chehab 	.algo = &em28xx_algo,
8670c0d06caSMauro Carvalho Chehab };
8680c0d06caSMauro Carvalho Chehab 
8690c0d06caSMauro Carvalho Chehab static struct i2c_client em28xx_client_template = {
8700c0d06caSMauro Carvalho Chehab 	.name = "em28xx internal",
8710c0d06caSMauro Carvalho Chehab };
8720c0d06caSMauro Carvalho Chehab 
8730c0d06caSMauro Carvalho Chehab /* ----------------------------------------------------------- */
8740c0d06caSMauro Carvalho Chehab 
8750c0d06caSMauro Carvalho Chehab /*
8760c0d06caSMauro Carvalho Chehab  * i2c_devs
8770c0d06caSMauro Carvalho Chehab  * incomplete list of known devices
8780c0d06caSMauro Carvalho Chehab  */
8790c0d06caSMauro Carvalho Chehab static char *i2c_devs[128] = {
8800b3966e4SFrank Schaefer 	[0x3e >> 1] = "remote IR sensor",
8810c0d06caSMauro Carvalho Chehab 	[0x4a >> 1] = "saa7113h",
8820c0d06caSMauro Carvalho Chehab 	[0x52 >> 1] = "drxk",
8830c0d06caSMauro Carvalho Chehab 	[0x60 >> 1] = "remote IR sensor",
8840c0d06caSMauro Carvalho Chehab 	[0x8e >> 1] = "remote IR sensor",
8850c0d06caSMauro Carvalho Chehab 	[0x86 >> 1] = "tda9887",
8860c0d06caSMauro Carvalho Chehab 	[0x80 >> 1] = "msp34xx",
8870c0d06caSMauro Carvalho Chehab 	[0x88 >> 1] = "msp34xx",
8880c0d06caSMauro Carvalho Chehab 	[0xa0 >> 1] = "eeprom",
8890c0d06caSMauro Carvalho Chehab 	[0xb0 >> 1] = "tda9874",
8900c0d06caSMauro Carvalho Chehab 	[0xb8 >> 1] = "tvp5150a",
8910c0d06caSMauro Carvalho Chehab 	[0xba >> 1] = "webcam sensor or tvp5150a",
8920c0d06caSMauro Carvalho Chehab 	[0xc0 >> 1] = "tuner (analog)",
8930c0d06caSMauro Carvalho Chehab 	[0xc2 >> 1] = "tuner (analog)",
8940c0d06caSMauro Carvalho Chehab 	[0xc4 >> 1] = "tuner (analog)",
8950c0d06caSMauro Carvalho Chehab 	[0xc6 >> 1] = "tuner (analog)",
8960c0d06caSMauro Carvalho Chehab };
8970c0d06caSMauro Carvalho Chehab 
8980c0d06caSMauro Carvalho Chehab /*
8990c0d06caSMauro Carvalho Chehab  * do_i2c_scan()
9000c0d06caSMauro Carvalho Chehab  * check i2c address range for devices
9010c0d06caSMauro Carvalho Chehab  */
902aab3125cSMauro Carvalho Chehab void em28xx_do_i2c_scan(struct em28xx *dev, unsigned bus)
9030c0d06caSMauro Carvalho Chehab {
9040c0d06caSMauro Carvalho Chehab 	u8 i2c_devicelist[128];
9050c0d06caSMauro Carvalho Chehab 	unsigned char buf;
9060c0d06caSMauro Carvalho Chehab 	int i, rc;
9070c0d06caSMauro Carvalho Chehab 
9080c0d06caSMauro Carvalho Chehab 	memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist));
9090c0d06caSMauro Carvalho Chehab 
9100c0d06caSMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
911aab3125cSMauro Carvalho Chehab 		dev->i2c_client[bus].addr = i;
912aab3125cSMauro Carvalho Chehab 		rc = i2c_master_recv(&dev->i2c_client[bus], &buf, 0);
9130c0d06caSMauro Carvalho Chehab 		if (rc < 0)
9140c0d06caSMauro Carvalho Chehab 			continue;
9150c0d06caSMauro Carvalho Chehab 		i2c_devicelist[i] = i;
916aab3125cSMauro Carvalho Chehab 		em28xx_info("found i2c device @ 0x%x on bus %d [%s]\n",
917aab3125cSMauro Carvalho Chehab 			    i << 1, bus, i2c_devs[i] ? i2c_devs[i] : "???");
9180c0d06caSMauro Carvalho Chehab 	}
9190c0d06caSMauro Carvalho Chehab 
920aab3125cSMauro Carvalho Chehab 	if (bus == dev->def_i2c_bus)
9210c0d06caSMauro Carvalho Chehab 		dev->i2c_hash = em28xx_hash_mem(i2c_devicelist,
9220c0d06caSMauro Carvalho Chehab 						ARRAY_SIZE(i2c_devicelist), 32);
9230c0d06caSMauro Carvalho Chehab }
9240c0d06caSMauro Carvalho Chehab 
9250c0d06caSMauro Carvalho Chehab /*
9260c0d06caSMauro Carvalho Chehab  * em28xx_i2c_register()
9270c0d06caSMauro Carvalho Chehab  * register i2c bus
9280c0d06caSMauro Carvalho Chehab  */
929a3ea4bf9SFrank Schaefer int em28xx_i2c_register(struct em28xx *dev, unsigned bus,
930a3ea4bf9SFrank Schaefer 			enum em28xx_i2c_algo_type algo_type)
9310c0d06caSMauro Carvalho Chehab {
9320c0d06caSMauro Carvalho Chehab 	int retval;
9330c0d06caSMauro Carvalho Chehab 
9340c0d06caSMauro Carvalho Chehab 	BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg);
9350c0d06caSMauro Carvalho Chehab 	BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req);
9360c0d06caSMauro Carvalho Chehab 
937aab3125cSMauro Carvalho Chehab 	if (bus >= NUM_I2C_BUSES)
938aab3125cSMauro Carvalho Chehab 		return -ENODEV;
939aab3125cSMauro Carvalho Chehab 
940aab3125cSMauro Carvalho Chehab 	dev->i2c_adap[bus] = em28xx_adap_template;
941aab3125cSMauro Carvalho Chehab 	dev->i2c_adap[bus].dev.parent = &dev->udev->dev;
942aab3125cSMauro Carvalho Chehab 	strcpy(dev->i2c_adap[bus].name, dev->name);
943aab3125cSMauro Carvalho Chehab 
944aab3125cSMauro Carvalho Chehab 	dev->i2c_bus[bus].bus = bus;
945a3ea4bf9SFrank Schaefer 	dev->i2c_bus[bus].algo_type = algo_type;
946aab3125cSMauro Carvalho Chehab 	dev->i2c_bus[bus].dev = dev;
947aab3125cSMauro Carvalho Chehab 	dev->i2c_adap[bus].algo_data = &dev->i2c_bus[bus];
948aab3125cSMauro Carvalho Chehab 
949aab3125cSMauro Carvalho Chehab 	retval = i2c_add_adapter(&dev->i2c_adap[bus]);
9500c0d06caSMauro Carvalho Chehab 	if (retval < 0) {
9510c0d06caSMauro Carvalho Chehab 		em28xx_errdev("%s: i2c_add_adapter failed! retval [%d]\n",
9520c0d06caSMauro Carvalho Chehab 			__func__, retval);
9530c0d06caSMauro Carvalho Chehab 		return retval;
9540c0d06caSMauro Carvalho Chehab 	}
9550c0d06caSMauro Carvalho Chehab 
956aab3125cSMauro Carvalho Chehab 	dev->i2c_client[bus] = em28xx_client_template;
957aab3125cSMauro Carvalho Chehab 	dev->i2c_client[bus].adapter = &dev->i2c_adap[bus];
9580c0d06caSMauro Carvalho Chehab 
959aab3125cSMauro Carvalho Chehab 	/* Up to now, all eeproms are at bus 0 */
960aab3125cSMauro Carvalho Chehab 	if (!bus) {
961aab3125cSMauro Carvalho Chehab 		retval = em28xx_i2c_eeprom(dev, bus, &dev->eedata, &dev->eedata_len);
9620c0d06caSMauro Carvalho Chehab 		if ((retval < 0) && (retval != -ENODEV)) {
9630c0d06caSMauro Carvalho Chehab 			em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n",
9640c0d06caSMauro Carvalho Chehab 				__func__, retval);
9650c0d06caSMauro Carvalho Chehab 
9660c0d06caSMauro Carvalho Chehab 			return retval;
9670c0d06caSMauro Carvalho Chehab 		}
968aab3125cSMauro Carvalho Chehab 	}
9690c0d06caSMauro Carvalho Chehab 
9700c0d06caSMauro Carvalho Chehab 	if (i2c_scan)
971aab3125cSMauro Carvalho Chehab 		em28xx_do_i2c_scan(dev, bus);
9720c0d06caSMauro Carvalho Chehab 
9730c0d06caSMauro Carvalho Chehab 	return 0;
9740c0d06caSMauro Carvalho Chehab }
9750c0d06caSMauro Carvalho Chehab 
9760c0d06caSMauro Carvalho Chehab /*
9770c0d06caSMauro Carvalho Chehab  * em28xx_i2c_unregister()
9780c0d06caSMauro Carvalho Chehab  * unregister i2c_bus
9790c0d06caSMauro Carvalho Chehab  */
980aab3125cSMauro Carvalho Chehab int em28xx_i2c_unregister(struct em28xx *dev, unsigned bus)
9810c0d06caSMauro Carvalho Chehab {
982aab3125cSMauro Carvalho Chehab 	if (bus >= NUM_I2C_BUSES)
983aab3125cSMauro Carvalho Chehab 		return -ENODEV;
984aab3125cSMauro Carvalho Chehab 
985aab3125cSMauro Carvalho Chehab 	i2c_del_adapter(&dev->i2c_adap[bus]);
9860c0d06caSMauro Carvalho Chehab 	return 0;
9870c0d06caSMauro Carvalho Chehab }
988