xref: /linux/drivers/media/usb/em28xx/em28xx-i2c.c (revision 29b05e22f5c68c657f5ec30a31023b81124287fb)
1a6c2ba28Sakpm@osdl.org /*
2f7abcd38SMauro Carvalho Chehab    em28xx-i2c.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
3a6c2ba28Sakpm@osdl.org 
4f7abcd38SMauro Carvalho Chehab    Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
5f7abcd38SMauro Carvalho Chehab 		      Markus Rechberger <mrechberger@gmail.com>
62e7c6dc3SMauro Carvalho Chehab 		      Mauro Carvalho Chehab <mchehab@infradead.org>
7f7abcd38SMauro Carvalho Chehab 		      Sascha Sommer <saschasommer@freenet.de>
8a3ea4bf9SFrank Schaefer    Copyright (C) 2013 Frank Schäfer <fschaefer.oss@googlemail.com>
9a6c2ba28Sakpm@osdl.org 
10a6c2ba28Sakpm@osdl.org    This program is free software; you can redistribute it and/or modify
11a6c2ba28Sakpm@osdl.org    it under the terms of the GNU General Public License as published by
12a6c2ba28Sakpm@osdl.org    the Free Software Foundation; either version 2 of the License, or
13a6c2ba28Sakpm@osdl.org    (at your option) any later version.
14a6c2ba28Sakpm@osdl.org 
15a6c2ba28Sakpm@osdl.org    This program is distributed in the hope that it will be useful,
16a6c2ba28Sakpm@osdl.org    but WITHOUT ANY WARRANTY; without even the implied warranty of
17a6c2ba28Sakpm@osdl.org    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18a6c2ba28Sakpm@osdl.org    GNU General Public License for more details.
19a6c2ba28Sakpm@osdl.org 
20a6c2ba28Sakpm@osdl.org    You should have received a copy of the GNU General Public License
21a6c2ba28Sakpm@osdl.org    along with this program; if not, write to the Free Software
22a6c2ba28Sakpm@osdl.org    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23a6c2ba28Sakpm@osdl.org  */
24a6c2ba28Sakpm@osdl.org 
258314d402SMauro Carvalho Chehab #include "em28xx.h"
268314d402SMauro Carvalho Chehab 
27a6c2ba28Sakpm@osdl.org #include <linux/module.h>
28a6c2ba28Sakpm@osdl.org #include <linux/kernel.h>
29a6c2ba28Sakpm@osdl.org #include <linux/usb.h>
30a6c2ba28Sakpm@osdl.org #include <linux/i2c.h>
314b83626aSMauro Carvalho Chehab #include <linux/jiffies.h>
32a6c2ba28Sakpm@osdl.org 
336c362c8eSMauro Carvalho Chehab #include "tuner-xc2028.h"
345e453dc7SMichael Krufky #include <media/v4l2-common.h>
35d5e52653SMauro Carvalho Chehab #include <media/tuner.h>
36a6c2ba28Sakpm@osdl.org 
37a6c2ba28Sakpm@osdl.org /* ----------------------------------------------------------- */
38a6c2ba28Sakpm@osdl.org 
39ff699e6bSDouglas Schilling Landgraf static unsigned int i2c_scan;
40a6c2ba28Sakpm@osdl.org module_param(i2c_scan, int, 0444);
41a6c2ba28Sakpm@osdl.org MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
42a6c2ba28Sakpm@osdl.org 
43ff699e6bSDouglas Schilling Landgraf static unsigned int i2c_debug;
44a6c2ba28Sakpm@osdl.org module_param(i2c_debug, int, 0644);
4550f0a9dfSMauro Carvalho Chehab MODULE_PARM_DESC(i2c_debug, "i2c debug message level (1: normal debug, 2: show I2C transfers)");
46a6c2ba28Sakpm@osdl.org 
47ce8591ffSMauro Carvalho Chehab #define dprintk(level, fmt, arg...) do {				\
48ce8591ffSMauro Carvalho Chehab 	if (i2c_debug > level)						\
49*29b05e22SMauro Carvalho Chehab 		dev_printk(KERN_DEBUG, &dev->intf->dev,			\
50ce8591ffSMauro Carvalho Chehab 			   "i2c: %s: " fmt, __func__, ## arg);		\
51ce8591ffSMauro Carvalho Chehab } while (0)
52ce8591ffSMauro Carvalho Chehab 
53ce8591ffSMauro Carvalho Chehab 
54a6c2ba28Sakpm@osdl.org /*
55f5ae371aSFrank Schaefer  * em2800_i2c_send_bytes()
56f5ae371aSFrank Schaefer  * send up to 4 bytes to the em2800 i2c device
57596d92d5SMauro Carvalho Chehab  */
58f5ae371aSFrank Schaefer static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
59596d92d5SMauro Carvalho Chehab {
60d1b7213bSMauro Carvalho Chehab 	unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT);
61596d92d5SMauro Carvalho Chehab 	int ret;
62a6bad040SFrank Schaefer 	u8 b2[6];
63f5ae371aSFrank Schaefer 
64f5ae371aSFrank Schaefer 	if (len < 1 || len > 4)
65f5ae371aSFrank Schaefer 		return -EOPNOTSUPP;
66f5ae371aSFrank Schaefer 
67596d92d5SMauro Carvalho Chehab 	BUG_ON(len < 1 || len > 4);
68596d92d5SMauro Carvalho Chehab 	b2[5] = 0x80 + len - 1;
69596d92d5SMauro Carvalho Chehab 	b2[4] = addr;
70596d92d5SMauro Carvalho Chehab 	b2[3] = buf[0];
71596d92d5SMauro Carvalho Chehab 	if (len > 1)
72596d92d5SMauro Carvalho Chehab 		b2[2] = buf[1];
73596d92d5SMauro Carvalho Chehab 	if (len > 2)
74596d92d5SMauro Carvalho Chehab 		b2[1] = buf[2];
75596d92d5SMauro Carvalho Chehab 	if (len > 3)
76596d92d5SMauro Carvalho Chehab 		b2[0] = buf[3];
77596d92d5SMauro Carvalho Chehab 
782fcc82d8SFrank Schaefer 	/* trigger write */
793acf2809SMauro Carvalho Chehab 	ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len);
80596d92d5SMauro Carvalho Chehab 	if (ret != 2 + len) {
81*29b05e22SMauro Carvalho Chehab 		dev_warn(&dev->intf->dev,
82ce8591ffSMauro Carvalho Chehab 			 "failed to trigger write to i2c address 0x%x (error=%i)\n",
83d230d5adSFrank Schaefer 			    addr, ret);
8445f04e82SFrank Schaefer 		return (ret < 0) ? ret : -EIO;
85596d92d5SMauro Carvalho Chehab 	}
862fcc82d8SFrank Schaefer 	/* wait for completion */
874b83626aSMauro Carvalho Chehab 	while (time_is_after_jiffies(timeout)) {
883acf2809SMauro Carvalho Chehab 		ret = dev->em28xx_read_reg(dev, 0x05);
894b83626aSMauro Carvalho Chehab 		if (ret == 0x80 + len - 1)
90596d92d5SMauro Carvalho Chehab 			return len;
914b83626aSMauro Carvalho Chehab 		if (ret == 0x94 + len - 1) {
92ce8591ffSMauro Carvalho Chehab 			dprintk(1, "R05 returned 0x%02x: I2C ACK error\n", ret);
93e63b009dSMauro Carvalho Chehab 			return -ENXIO;
944b83626aSMauro Carvalho Chehab 		}
954b83626aSMauro Carvalho Chehab 		if (ret < 0) {
96*29b05e22SMauro Carvalho Chehab 			dev_warn(&dev->intf->dev,
97ce8591ffSMauro Carvalho Chehab 				 "failed to get i2c transfer status from bridge register (error=%i)\n",
98d230d5adSFrank Schaefer 				ret);
9945f04e82SFrank Schaefer 			return ret;
10045f04e82SFrank Schaefer 		}
101e8e41da4SMarkus Rechberger 		msleep(5);
102596d92d5SMauro Carvalho Chehab 	}
103ce8591ffSMauro Carvalho Chehab 	dprintk(0, "write to i2c device at 0x%x timed out\n", addr);
104e63b009dSMauro Carvalho Chehab 	return -ETIMEDOUT;
105596d92d5SMauro Carvalho Chehab }
106596d92d5SMauro Carvalho Chehab 
107596d92d5SMauro Carvalho Chehab /*
108596d92d5SMauro Carvalho Chehab  * em2800_i2c_recv_bytes()
1092fcc82d8SFrank Schaefer  * read up to 4 bytes from the em2800 i2c device
110596d92d5SMauro Carvalho Chehab  */
111a6bad040SFrank Schaefer static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
112596d92d5SMauro Carvalho Chehab {
113d1b7213bSMauro Carvalho Chehab 	unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT);
1142fcc82d8SFrank Schaefer 	u8 buf2[4];
115596d92d5SMauro Carvalho Chehab 	int ret;
1162fcc82d8SFrank Schaefer 	int i;
117f5ae371aSFrank Schaefer 
118f5ae371aSFrank Schaefer 	if (len < 1 || len > 4)
119f5ae371aSFrank Schaefer 		return -EOPNOTSUPP;
120f5ae371aSFrank Schaefer 
1212fcc82d8SFrank Schaefer 	/* trigger read */
1222fcc82d8SFrank Schaefer 	buf2[1] = 0x84 + len - 1;
1232fcc82d8SFrank Schaefer 	buf2[0] = addr;
1242fcc82d8SFrank Schaefer 	ret = dev->em28xx_write_regs(dev, 0x04, buf2, 2);
1252fcc82d8SFrank Schaefer 	if (ret != 2) {
126*29b05e22SMauro Carvalho Chehab 		dev_warn(&dev->intf->dev,
127ce8591ffSMauro Carvalho Chehab 			 "failed to trigger read from i2c address 0x%x (error=%i)\n",
128d230d5adSFrank Schaefer 			 addr, ret);
1292fcc82d8SFrank Schaefer 		return (ret < 0) ? ret : -EIO;
1302fcc82d8SFrank Schaefer 	}
1312fcc82d8SFrank Schaefer 
1322fcc82d8SFrank Schaefer 	/* wait for completion */
1334b83626aSMauro Carvalho Chehab 	while (time_is_after_jiffies(timeout)) {
1342fcc82d8SFrank Schaefer 		ret = dev->em28xx_read_reg(dev, 0x05);
1354b83626aSMauro Carvalho Chehab 		if (ret == 0x84 + len - 1)
1362fcc82d8SFrank Schaefer 			break;
1374b83626aSMauro Carvalho Chehab 		if (ret == 0x94 + len - 1) {
138ce8591ffSMauro Carvalho Chehab 			dprintk(1, "R05 returned 0x%02x: I2C ACK error\n",
139d845fb3aSMauro Carvalho Chehab 				ret);
140e63b009dSMauro Carvalho Chehab 			return -ENXIO;
1414b83626aSMauro Carvalho Chehab 		}
1424b83626aSMauro Carvalho Chehab 		if (ret < 0) {
143*29b05e22SMauro Carvalho Chehab 			dev_warn(&dev->intf->dev,
144ce8591ffSMauro Carvalho Chehab 				 "failed to get i2c transfer status from bridge register (error=%i)\n",
145d230d5adSFrank Schaefer 				 ret);
146596d92d5SMauro Carvalho Chehab 			return ret;
147596d92d5SMauro Carvalho Chehab 		}
1482fcc82d8SFrank Schaefer 		msleep(5);
1492fcc82d8SFrank Schaefer 	}
15050f0a9dfSMauro Carvalho Chehab 	if (ret != 0x84 + len - 1) {
151ce8591ffSMauro Carvalho Chehab 		dprintk(0, "read from i2c device at 0x%x timed out\n", addr);
15250f0a9dfSMauro Carvalho Chehab 	}
1532fcc82d8SFrank Schaefer 
1542fcc82d8SFrank Schaefer 	/* get the received message */
1552fcc82d8SFrank Schaefer 	ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len);
1562fcc82d8SFrank Schaefer 	if (ret != len) {
157*29b05e22SMauro Carvalho Chehab 		dev_warn(&dev->intf->dev,
158ce8591ffSMauro Carvalho Chehab 			 "reading from i2c device at 0x%x failed: couldn't get the received message from the bridge (error=%i)\n",
159d230d5adSFrank Schaefer 			 addr, ret);
1602fcc82d8SFrank Schaefer 		return (ret < 0) ? ret : -EIO;
1612fcc82d8SFrank Schaefer 	}
1622fcc82d8SFrank Schaefer 	for (i = 0; i < len; i++)
1632fcc82d8SFrank Schaefer 		buf[i] = buf2[len - 1 - i];
1642fcc82d8SFrank Schaefer 
165596d92d5SMauro Carvalho Chehab 	return ret;
166596d92d5SMauro Carvalho Chehab }
1672fcc82d8SFrank Schaefer 
1682fcc82d8SFrank Schaefer /*
1692fcc82d8SFrank Schaefer  * em2800_i2c_check_for_device()
1702fcc82d8SFrank Schaefer  * check if there is an i2c device at the supplied address
1712fcc82d8SFrank Schaefer  */
1722fcc82d8SFrank Schaefer static int em2800_i2c_check_for_device(struct em28xx *dev, u8 addr)
1732fcc82d8SFrank Schaefer {
1742fcc82d8SFrank Schaefer 	u8 buf;
1752fcc82d8SFrank Schaefer 	int ret;
1762fcc82d8SFrank Schaefer 
1772fcc82d8SFrank Schaefer 	ret = em2800_i2c_recv_bytes(dev, addr, &buf, 1);
1782fcc82d8SFrank Schaefer 	if (ret == 1)
1792fcc82d8SFrank Schaefer 		return 0;
1802fcc82d8SFrank Schaefer 	return (ret < 0) ? ret : -EIO;
181596d92d5SMauro Carvalho Chehab }
182596d92d5SMauro Carvalho Chehab 
183596d92d5SMauro Carvalho Chehab /*
1843acf2809SMauro Carvalho Chehab  * em28xx_i2c_send_bytes()
185a6c2ba28Sakpm@osdl.org  */
186a6bad040SFrank Schaefer static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
187a6bad040SFrank Schaefer 				 u16 len, int stop)
188a6c2ba28Sakpm@osdl.org {
189d1b7213bSMauro Carvalho Chehab 	unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT);
1904b83626aSMauro Carvalho Chehab 	int ret;
191a6c2ba28Sakpm@osdl.org 
192f5ae371aSFrank Schaefer 	if (len < 1 || len > 64)
193f5ae371aSFrank Schaefer 		return -EOPNOTSUPP;
194fa74aca3SFrank Schaefer 	/*
195fa74aca3SFrank Schaefer 	 * NOTE: limited by the USB ctrl message constraints
196fa74aca3SFrank Schaefer 	 * Zero length reads always succeed, even if no device is connected
197fa74aca3SFrank Schaefer 	 */
198f5ae371aSFrank Schaefer 
19945f04e82SFrank Schaefer 	/* Write to i2c device */
20045f04e82SFrank Schaefer 	ret = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len);
20145f04e82SFrank Schaefer 	if (ret != len) {
20245f04e82SFrank Schaefer 		if (ret < 0) {
203*29b05e22SMauro Carvalho Chehab 			dev_warn(&dev->intf->dev,
204ce8591ffSMauro Carvalho Chehab 				 "writing to i2c device at 0x%x failed (error=%i)\n",
205d230d5adSFrank Schaefer 				 addr, ret);
20645f04e82SFrank Schaefer 			return ret;
20745f04e82SFrank Schaefer 		} else {
208*29b05e22SMauro Carvalho Chehab 			dev_warn(&dev->intf->dev,
209ce8591ffSMauro Carvalho Chehab 				 "%i bytes write to i2c device at 0x%x requested, but %i bytes written\n",
21045f04e82SFrank Schaefer 				 len, addr, ret);
21145f04e82SFrank Schaefer 			return -EIO;
21245f04e82SFrank Schaefer 		}
21345f04e82SFrank Schaefer 	}
214a6c2ba28Sakpm@osdl.org 
2154b83626aSMauro Carvalho Chehab 	/* wait for completion */
2164b83626aSMauro Carvalho Chehab 	while (time_is_after_jiffies(timeout)) {
217bbc70e64SMauro Carvalho Chehab 		ret = dev->em28xx_read_reg(dev, 0x05);
2184b83626aSMauro Carvalho Chehab 		if (ret == 0) /* success */
21945f04e82SFrank Schaefer 			return len;
2204b83626aSMauro Carvalho Chehab 		if (ret == 0x10) {
221ce8591ffSMauro Carvalho Chehab 			dprintk(1, "I2C ACK error on writing to addr 0x%02x\n",
222d845fb3aSMauro Carvalho Chehab 				addr);
223e63b009dSMauro Carvalho Chehab 			return -ENXIO;
2244b83626aSMauro Carvalho Chehab 		}
2254b83626aSMauro Carvalho Chehab 		if (ret < 0) {
226*29b05e22SMauro Carvalho Chehab 			dev_warn(&dev->intf->dev,
227ce8591ffSMauro Carvalho Chehab 				 "failed to get i2c transfer status from bridge register (error=%i)\n",
228d230d5adSFrank Schaefer 				 ret);
22945f04e82SFrank Schaefer 			return ret;
230bbc70e64SMauro Carvalho Chehab 		}
23145f04e82SFrank Schaefer 		msleep(5);
232fa74aca3SFrank Schaefer 		/*
233fa74aca3SFrank Schaefer 		 * NOTE: do we really have to wait for success ?
234fa74aca3SFrank Schaefer 		 * Never seen anything else than 0x00 or 0x10
235fa74aca3SFrank Schaefer 		 * (even with high payload) ...
236fa74aca3SFrank Schaefer 		 */
23745f04e82SFrank Schaefer 	}
238123a17d1SFrank Schaefer 
239123a17d1SFrank Schaefer 	if (ret == 0x02 || ret == 0x04) {
240123a17d1SFrank Schaefer 		/* NOTE: these errors seem to be related to clock stretching */
241ce8591ffSMauro Carvalho Chehab 		dprintk(0,
242ce8591ffSMauro Carvalho Chehab 			"write to i2c device at 0x%x timed out (status=%i)\n",
24350f0a9dfSMauro Carvalho Chehab 			addr, ret);
244e63b009dSMauro Carvalho Chehab 		return -ETIMEDOUT;
245a6c2ba28Sakpm@osdl.org 	}
246a6c2ba28Sakpm@osdl.org 
247*29b05e22SMauro Carvalho Chehab 	dev_warn(&dev->intf->dev,
248ce8591ffSMauro Carvalho Chehab 		 "write to i2c device at 0x%x failed with unknown error (status=%i)\n",
249123a17d1SFrank Schaefer 		 addr, ret);
250123a17d1SFrank Schaefer 	return -EIO;
251123a17d1SFrank Schaefer }
252123a17d1SFrank Schaefer 
253a6c2ba28Sakpm@osdl.org /*
2543acf2809SMauro Carvalho Chehab  * em28xx_i2c_recv_bytes()
255a6c2ba28Sakpm@osdl.org  * read a byte from the i2c device
256a6c2ba28Sakpm@osdl.org  */
257a6bad040SFrank Schaefer static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
258a6c2ba28Sakpm@osdl.org {
259a6c2ba28Sakpm@osdl.org 	int ret;
260f5ae371aSFrank Schaefer 
261f5ae371aSFrank Schaefer 	if (len < 1 || len > 64)
262f5ae371aSFrank Schaefer 		return -EOPNOTSUPP;
263fa74aca3SFrank Schaefer 	/*
264fa74aca3SFrank Schaefer 	 * NOTE: limited by the USB ctrl message constraints
265fa74aca3SFrank Schaefer 	 * Zero length reads always succeed, even if no device is connected
266fa74aca3SFrank Schaefer 	 */
267f5ae371aSFrank Schaefer 
26845f04e82SFrank Schaefer 	/* Read data from i2c device */
2693acf2809SMauro Carvalho Chehab 	ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
270a6c2ba28Sakpm@osdl.org 	if (ret < 0) {
271*29b05e22SMauro Carvalho Chehab 		dev_warn(&dev->intf->dev,
272ce8591ffSMauro Carvalho Chehab 			 "reading from i2c device at 0x%x failed (error=%i)\n",
2737f6301d1SFrank Schaefer 			 addr, ret);
27445f04e82SFrank Schaefer 		return ret;
27545f04e82SFrank Schaefer 	}
276fa74aca3SFrank Schaefer 	/*
277fa74aca3SFrank Schaefer 	 * NOTE: some devices with two i2c busses have the bad habit to return 0
2787f6301d1SFrank Schaefer 	 * bytes if we are on bus B AND there was no write attempt to the
2797f6301d1SFrank Schaefer 	 * specified slave address before AND no device is present at the
2807f6301d1SFrank Schaefer 	 * requested slave address.
281e63b009dSMauro Carvalho Chehab 	 * Anyway, the next check will fail with -ENXIO in this case, so avoid
2827f6301d1SFrank Schaefer 	 * spamming the system log on device probing and do nothing here.
2837f6301d1SFrank Schaefer 	 */
28445f04e82SFrank Schaefer 
28545f04e82SFrank Schaefer 	/* Check success of the i2c operation */
28645f04e82SFrank Schaefer 	ret = dev->em28xx_read_reg(dev, 0x05);
2874b83626aSMauro Carvalho Chehab 	if (ret == 0) /* success */
2884b83626aSMauro Carvalho Chehab 		return len;
28945f04e82SFrank Schaefer 	if (ret < 0) {
290*29b05e22SMauro Carvalho Chehab 		dev_warn(&dev->intf->dev,
291ce8591ffSMauro Carvalho Chehab 			 "failed to get i2c transfer status from bridge register (error=%i)\n",
292d230d5adSFrank Schaefer 			 ret);
293a6c2ba28Sakpm@osdl.org 		return ret;
294a6c2ba28Sakpm@osdl.org 	}
295d845fb3aSMauro Carvalho Chehab 	if (ret == 0x10) {
296ce8591ffSMauro Carvalho Chehab 		dprintk(1, "I2C ACK error on writing to addr 0x%02x\n",
297d845fb3aSMauro Carvalho Chehab 			addr);
298e63b009dSMauro Carvalho Chehab 		return -ENXIO;
299d845fb3aSMauro Carvalho Chehab 	}
3004b83626aSMauro Carvalho Chehab 
301123a17d1SFrank Schaefer 	if (ret == 0x02 || ret == 0x04) {
302123a17d1SFrank Schaefer 		/* NOTE: these errors seem to be related to clock stretching */
303ce8591ffSMauro Carvalho Chehab 		dprintk(0,
304ce8591ffSMauro Carvalho Chehab 			"write to i2c device at 0x%x timed out (status=%i)\n",
305123a17d1SFrank Schaefer 			addr, ret);
306e63b009dSMauro Carvalho Chehab 		return -ETIMEDOUT;
30745f04e82SFrank Schaefer 	}
308a6c2ba28Sakpm@osdl.org 
309*29b05e22SMauro Carvalho Chehab 	dev_warn(&dev->intf->dev,
310ce8591ffSMauro Carvalho Chehab 		 "write to i2c device at 0x%x failed with unknown error (status=%i)\n",
311123a17d1SFrank Schaefer 		 addr, ret);
312123a17d1SFrank Schaefer 	return -EIO;
313123a17d1SFrank Schaefer }
314123a17d1SFrank Schaefer 
315a6c2ba28Sakpm@osdl.org /*
3163acf2809SMauro Carvalho Chehab  * em28xx_i2c_check_for_device()
317a6c2ba28Sakpm@osdl.org  * check if there is a i2c_device at the supplied address
318a6c2ba28Sakpm@osdl.org  */
319a6bad040SFrank Schaefer static int em28xx_i2c_check_for_device(struct em28xx *dev, u16 addr)
320a6c2ba28Sakpm@osdl.org {
321a6c2ba28Sakpm@osdl.org 	int ret;
32245f04e82SFrank Schaefer 	u8 buf;
323a6c2ba28Sakpm@osdl.org 
32445f04e82SFrank Schaefer 	ret = em28xx_i2c_recv_bytes(dev, addr, &buf, 1);
32545f04e82SFrank Schaefer 	if (ret == 1)
326a6c2ba28Sakpm@osdl.org 		return 0;
32745f04e82SFrank Schaefer 	return (ret < 0) ? ret : -EIO;
328a6c2ba28Sakpm@osdl.org }
329a6c2ba28Sakpm@osdl.org 
330a6c2ba28Sakpm@osdl.org /*
331a3ea4bf9SFrank Schaefer  * em25xx_bus_B_send_bytes
332a3ea4bf9SFrank Schaefer  * write bytes to the i2c device
333a3ea4bf9SFrank Schaefer  */
334a3ea4bf9SFrank Schaefer static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
335a3ea4bf9SFrank Schaefer 				   u16 len)
336a3ea4bf9SFrank Schaefer {
337a3ea4bf9SFrank Schaefer 	int ret;
338a3ea4bf9SFrank Schaefer 
339a3ea4bf9SFrank Schaefer 	if (len < 1 || len > 64)
340a3ea4bf9SFrank Schaefer 		return -EOPNOTSUPP;
341a3ea4bf9SFrank Schaefer 	/*
342a3ea4bf9SFrank Schaefer 	 * NOTE: limited by the USB ctrl message constraints
343a3ea4bf9SFrank Schaefer 	 * Zero length reads always succeed, even if no device is connected
344a3ea4bf9SFrank Schaefer 	 */
345a3ea4bf9SFrank Schaefer 
346a3ea4bf9SFrank Schaefer 	/* Set register and write value */
347a3ea4bf9SFrank Schaefer 	ret = dev->em28xx_write_regs_req(dev, 0x06, addr, buf, len);
348a3ea4bf9SFrank Schaefer 	if (ret != len) {
349a3ea4bf9SFrank Schaefer 		if (ret < 0) {
350*29b05e22SMauro Carvalho Chehab 			dev_warn(&dev->intf->dev,
351ce8591ffSMauro Carvalho Chehab 				 "writing to i2c device at 0x%x failed (error=%i)\n",
352a3ea4bf9SFrank Schaefer 				 addr, ret);
353a3ea4bf9SFrank Schaefer 			return ret;
354a3ea4bf9SFrank Schaefer 		} else {
355*29b05e22SMauro Carvalho Chehab 			dev_warn(&dev->intf->dev,
356ce8591ffSMauro Carvalho Chehab 				 "%i bytes write to i2c device at 0x%x requested, but %i bytes written\n",
357a3ea4bf9SFrank Schaefer 				 len, addr, ret);
358a3ea4bf9SFrank Schaefer 			return -EIO;
359a3ea4bf9SFrank Schaefer 		}
360a3ea4bf9SFrank Schaefer 	}
361a3ea4bf9SFrank Schaefer 	/* Check success */
362a3ea4bf9SFrank Schaefer 	ret = dev->em28xx_read_reg_req(dev, 0x08, 0x0000);
363a3ea4bf9SFrank Schaefer 	/*
364a3ea4bf9SFrank Schaefer 	 * NOTE: the only error we've seen so far is
365a3ea4bf9SFrank Schaefer 	 * 0x01 when the slave device is not present
366a3ea4bf9SFrank Schaefer 	 */
367a3ea4bf9SFrank Schaefer 	if (!ret)
368a3ea4bf9SFrank Schaefer 		return len;
369d845fb3aSMauro Carvalho Chehab 	else if (ret > 0) {
370ce8591ffSMauro Carvalho Chehab 		dprintk(1, "Bus B R08 returned 0x%02x: I2C ACK error\n", ret);
371e63b009dSMauro Carvalho Chehab 		return -ENXIO;
372d845fb3aSMauro Carvalho Chehab 	}
373a3ea4bf9SFrank Schaefer 
374a3ea4bf9SFrank Schaefer 	return ret;
375a3ea4bf9SFrank Schaefer 	/*
376a3ea4bf9SFrank Schaefer 	 * NOTE: With chip types (other chip IDs) which actually don't support
377a3ea4bf9SFrank Schaefer 	 * this operation, it seems to succeed ALWAYS ! (even if there is no
378a3ea4bf9SFrank Schaefer 	 * slave device or even no second i2c bus provided)
379a3ea4bf9SFrank Schaefer 	 */
380a3ea4bf9SFrank Schaefer }
381a3ea4bf9SFrank Schaefer 
382a3ea4bf9SFrank Schaefer /*
383a3ea4bf9SFrank Schaefer  * em25xx_bus_B_recv_bytes
384a3ea4bf9SFrank Schaefer  * read bytes from the i2c device
385a3ea4bf9SFrank Schaefer  */
386a3ea4bf9SFrank Schaefer static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf,
387a3ea4bf9SFrank Schaefer 				   u16 len)
388a3ea4bf9SFrank Schaefer {
389a3ea4bf9SFrank Schaefer 	int ret;
390a3ea4bf9SFrank Schaefer 
391a3ea4bf9SFrank Schaefer 	if (len < 1 || len > 64)
392a3ea4bf9SFrank Schaefer 		return -EOPNOTSUPP;
393a3ea4bf9SFrank Schaefer 	/*
394a3ea4bf9SFrank Schaefer 	 * NOTE: limited by the USB ctrl message constraints
395a3ea4bf9SFrank Schaefer 	 * Zero length reads always succeed, even if no device is connected
396a3ea4bf9SFrank Schaefer 	 */
397a3ea4bf9SFrank Schaefer 
398a3ea4bf9SFrank Schaefer 	/* Read value */
399a3ea4bf9SFrank Schaefer 	ret = dev->em28xx_read_reg_req_len(dev, 0x06, addr, buf, len);
400a3ea4bf9SFrank Schaefer 	if (ret < 0) {
401*29b05e22SMauro Carvalho Chehab 		dev_warn(&dev->intf->dev,
402ce8591ffSMauro Carvalho Chehab 			 "reading from i2c device at 0x%x failed (error=%i)\n",
403a3ea4bf9SFrank Schaefer 			 addr, ret);
404a3ea4bf9SFrank Schaefer 		return ret;
405a3ea4bf9SFrank Schaefer 	}
406a3ea4bf9SFrank Schaefer 	/*
407a3ea4bf9SFrank Schaefer 	 * NOTE: some devices with two i2c busses have the bad habit to return 0
408a3ea4bf9SFrank Schaefer 	 * bytes if we are on bus B AND there was no write attempt to the
409a3ea4bf9SFrank Schaefer 	 * specified slave address before AND no device is present at the
410a3ea4bf9SFrank Schaefer 	 * requested slave address.
411e63b009dSMauro Carvalho Chehab 	 * Anyway, the next check will fail with -ENXIO in this case, so avoid
412a3ea4bf9SFrank Schaefer 	 * spamming the system log on device probing and do nothing here.
413a3ea4bf9SFrank Schaefer 	 */
414a3ea4bf9SFrank Schaefer 
415a3ea4bf9SFrank Schaefer 	/* Check success */
416a3ea4bf9SFrank Schaefer 	ret = dev->em28xx_read_reg_req(dev, 0x08, 0x0000);
417a3ea4bf9SFrank Schaefer 	/*
418a3ea4bf9SFrank Schaefer 	 * NOTE: the only error we've seen so far is
419a3ea4bf9SFrank Schaefer 	 * 0x01 when the slave device is not present
420a3ea4bf9SFrank Schaefer 	 */
421a3ea4bf9SFrank Schaefer 	if (!ret)
422a3ea4bf9SFrank Schaefer 		return len;
423d845fb3aSMauro Carvalho Chehab 	else if (ret > 0) {
424ce8591ffSMauro Carvalho Chehab 		dprintk(1, "Bus B R08 returned 0x%02x: I2C ACK error\n", ret);
425e63b009dSMauro Carvalho Chehab 		return -ENXIO;
426d845fb3aSMauro Carvalho Chehab 	}
427a3ea4bf9SFrank Schaefer 
428a3ea4bf9SFrank Schaefer 	return ret;
429a3ea4bf9SFrank Schaefer 	/*
430a3ea4bf9SFrank Schaefer 	 * NOTE: With chip types (other chip IDs) which actually don't support
431a3ea4bf9SFrank Schaefer 	 * this operation, it seems to succeed ALWAYS ! (even if there is no
432a3ea4bf9SFrank Schaefer 	 * slave device or even no second i2c bus provided)
433a3ea4bf9SFrank Schaefer 	 */
434a3ea4bf9SFrank Schaefer }
435a3ea4bf9SFrank Schaefer 
436a3ea4bf9SFrank Schaefer /*
437a3ea4bf9SFrank Schaefer  * em25xx_bus_B_check_for_device()
438a3ea4bf9SFrank Schaefer  * check if there is a i2c device at the supplied address
439a3ea4bf9SFrank Schaefer  */
440a3ea4bf9SFrank Schaefer static int em25xx_bus_B_check_for_device(struct em28xx *dev, u16 addr)
441a3ea4bf9SFrank Schaefer {
442a3ea4bf9SFrank Schaefer 	u8 buf;
443a3ea4bf9SFrank Schaefer 	int ret;
444a3ea4bf9SFrank Schaefer 
445a3ea4bf9SFrank Schaefer 	ret = em25xx_bus_B_recv_bytes(dev, addr, &buf, 1);
446a3ea4bf9SFrank Schaefer 	if (ret < 0)
447a3ea4bf9SFrank Schaefer 		return ret;
448a3ea4bf9SFrank Schaefer 
449a3ea4bf9SFrank Schaefer 	return 0;
450a3ea4bf9SFrank Schaefer 	/*
451a3ea4bf9SFrank Schaefer 	 * NOTE: With chips which do not support this operation,
452a3ea4bf9SFrank Schaefer 	 * it seems to succeed ALWAYS ! (even if no device connected)
453a3ea4bf9SFrank Schaefer 	 */
454a3ea4bf9SFrank Schaefer }
455a3ea4bf9SFrank Schaefer 
456a3ea4bf9SFrank Schaefer static inline int i2c_check_for_device(struct em28xx_i2c_bus *i2c_bus, u16 addr)
457a3ea4bf9SFrank Schaefer {
458a3ea4bf9SFrank Schaefer 	struct em28xx *dev = i2c_bus->dev;
459a3ea4bf9SFrank Schaefer 	int rc = -EOPNOTSUPP;
460a3ea4bf9SFrank Schaefer 
461a3ea4bf9SFrank Schaefer 	if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX)
462a3ea4bf9SFrank Schaefer 		rc = em28xx_i2c_check_for_device(dev, addr);
463a3ea4bf9SFrank Schaefer 	else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800)
464a3ea4bf9SFrank Schaefer 		rc = em2800_i2c_check_for_device(dev, addr);
465a3ea4bf9SFrank Schaefer 	else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)
466a3ea4bf9SFrank Schaefer 		rc = em25xx_bus_B_check_for_device(dev, addr);
467a3ea4bf9SFrank Schaefer 	return rc;
468a3ea4bf9SFrank Schaefer }
469a3ea4bf9SFrank Schaefer 
470a3ea4bf9SFrank Schaefer static inline int i2c_recv_bytes(struct em28xx_i2c_bus *i2c_bus,
471a3ea4bf9SFrank Schaefer 				 struct i2c_msg msg)
472a3ea4bf9SFrank Schaefer {
473a3ea4bf9SFrank Schaefer 	struct em28xx *dev = i2c_bus->dev;
474a3ea4bf9SFrank Schaefer 	u16 addr = msg.addr << 1;
47550f0a9dfSMauro Carvalho Chehab 	int rc = -EOPNOTSUPP;
476a3ea4bf9SFrank Schaefer 
477a3ea4bf9SFrank Schaefer 	if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX)
478a3ea4bf9SFrank Schaefer 		rc = em28xx_i2c_recv_bytes(dev, addr, msg.buf, msg.len);
479a3ea4bf9SFrank Schaefer 	else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800)
480a3ea4bf9SFrank Schaefer 		rc = em2800_i2c_recv_bytes(dev, addr, msg.buf, msg.len);
481a3ea4bf9SFrank Schaefer 	else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)
482a3ea4bf9SFrank Schaefer 		rc = em25xx_bus_B_recv_bytes(dev, addr, msg.buf, msg.len);
483a3ea4bf9SFrank Schaefer 	return rc;
484a3ea4bf9SFrank Schaefer }
485a3ea4bf9SFrank Schaefer 
486a3ea4bf9SFrank Schaefer static inline int i2c_send_bytes(struct em28xx_i2c_bus *i2c_bus,
487a3ea4bf9SFrank Schaefer 				 struct i2c_msg msg, int stop)
488a3ea4bf9SFrank Schaefer {
489a3ea4bf9SFrank Schaefer 	struct em28xx *dev = i2c_bus->dev;
490a3ea4bf9SFrank Schaefer 	u16 addr = msg.addr << 1;
49150f0a9dfSMauro Carvalho Chehab 	int rc = -EOPNOTSUPP;
492a3ea4bf9SFrank Schaefer 
493a3ea4bf9SFrank Schaefer 	if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX)
494a3ea4bf9SFrank Schaefer 		rc = em28xx_i2c_send_bytes(dev, addr, msg.buf, msg.len, stop);
495a3ea4bf9SFrank Schaefer 	else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800)
496a3ea4bf9SFrank Schaefer 		rc = em2800_i2c_send_bytes(dev, addr, msg.buf, msg.len);
497a3ea4bf9SFrank Schaefer 	else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)
498a3ea4bf9SFrank Schaefer 		rc = em25xx_bus_B_send_bytes(dev, addr, msg.buf, msg.len);
499a3ea4bf9SFrank Schaefer 	return rc;
500a3ea4bf9SFrank Schaefer }
501a3ea4bf9SFrank Schaefer 
502a3ea4bf9SFrank Schaefer /*
5033acf2809SMauro Carvalho Chehab  * em28xx_i2c_xfer()
504a6c2ba28Sakpm@osdl.org  * the main i2c transfer function
505a6c2ba28Sakpm@osdl.org  */
5063acf2809SMauro Carvalho Chehab static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
507a6c2ba28Sakpm@osdl.org 			   struct i2c_msg msgs[], int num)
508a6c2ba28Sakpm@osdl.org {
509aab3125cSMauro Carvalho Chehab 	struct em28xx_i2c_bus *i2c_bus = i2c_adap->algo_data;
510aab3125cSMauro Carvalho Chehab 	struct em28xx *dev = i2c_bus->dev;
511aab3125cSMauro Carvalho Chehab 	unsigned bus = i2c_bus->bus;
512a3ea4bf9SFrank Schaefer 	int addr, rc, i;
5133190fbeeSMauro Carvalho Chehab 	u8 reg;
514a6c2ba28Sakpm@osdl.org 
515cc5c5d20SShuah Khan 	/* prevent i2c xfer attempts after device is disconnected
516cc5c5d20SShuah Khan 	   some fe's try to do i2c writes/reads from their release
517cc5c5d20SShuah Khan 	   interfaces when called in disconnect path */
518cc5c5d20SShuah Khan 	if (dev->disconnected)
519cc5c5d20SShuah Khan 		return -ENODEV;
520cc5c5d20SShuah Khan 
521e44c153bSDan Carpenter 	if (!rt_mutex_trylock(&dev->i2c_bus_lock))
522e44c153bSDan Carpenter 		return -EAGAIN;
523aab3125cSMauro Carvalho Chehab 
524aab3125cSMauro Carvalho Chehab 	/* Switch I2C bus if needed */
525a3ea4bf9SFrank Schaefer 	if (bus != dev->cur_i2c_bus &&
526a3ea4bf9SFrank Schaefer 	    i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX) {
527aab3125cSMauro Carvalho Chehab 		if (bus == 1)
5283190fbeeSMauro Carvalho Chehab 			reg = EM2874_I2C_SECONDARY_BUS_SELECT;
529aab3125cSMauro Carvalho Chehab 		else
5303190fbeeSMauro Carvalho Chehab 			reg = 0;
5313190fbeeSMauro Carvalho Chehab 		em28xx_write_reg_bits(dev, EM28XX_R06_I2C_CLK, reg,
5323190fbeeSMauro Carvalho Chehab 				      EM2874_I2C_SECONDARY_BUS_SELECT);
533aab3125cSMauro Carvalho Chehab 		dev->cur_i2c_bus = bus;
534aab3125cSMauro Carvalho Chehab 	}
535aab3125cSMauro Carvalho Chehab 
536aab3125cSMauro Carvalho Chehab 	if (num <= 0) {
537aab3125cSMauro Carvalho Chehab 		rt_mutex_unlock(&dev->i2c_bus_lock);
538a6c2ba28Sakpm@osdl.org 		return 0;
539aab3125cSMauro Carvalho Chehab 	}
540a6c2ba28Sakpm@osdl.org 	for (i = 0; i < num; i++) {
541a6c2ba28Sakpm@osdl.org 		addr = msgs[i].addr << 1;
542e63b009dSMauro Carvalho Chehab 		if (!msgs[i].len) {
543e63b009dSMauro Carvalho Chehab 			/*
544e63b009dSMauro Carvalho Chehab 			 * no len: check only for device presence
545e63b009dSMauro Carvalho Chehab 			 * This code is only called during device probe.
546e63b009dSMauro Carvalho Chehab 			 */
547a3ea4bf9SFrank Schaefer 			rc = i2c_check_for_device(i2c_bus, addr);
548ce8591ffSMauro Carvalho Chehab 
549ce8591ffSMauro Carvalho Chehab 			if (rc == -ENXIO)
55050f0a9dfSMauro Carvalho Chehab 				rc = -ENODEV;
551596d92d5SMauro Carvalho Chehab 		} else if (msgs[i].flags & I2C_M_RD) {
552a6c2ba28Sakpm@osdl.org 			/* read bytes */
553a3ea4bf9SFrank Schaefer 			rc = i2c_recv_bytes(i2c_bus, msgs[i]);
554a6c2ba28Sakpm@osdl.org 		} else {
555a6c2ba28Sakpm@osdl.org 			/* write bytes */
556a3ea4bf9SFrank Schaefer 			rc = i2c_send_bytes(i2c_bus, msgs[i], i == num - 1);
557e8e41da4SMarkus Rechberger 		}
558ce8591ffSMauro Carvalho Chehab 
559ce8591ffSMauro Carvalho Chehab 		if (rc < 0)
560ce8591ffSMauro Carvalho Chehab 			goto error;
561ce8591ffSMauro Carvalho Chehab 
562ce8591ffSMauro Carvalho Chehab 		dprintk(2, "%s %s addr=%02x len=%d: %*ph\n",
563ce8591ffSMauro Carvalho Chehab 			(msgs[i].flags & I2C_M_RD) ? "read" : "write",
564ce8591ffSMauro Carvalho Chehab 			i == num - 1 ? "stop" : "nonstop",
565ce8591ffSMauro Carvalho Chehab 			addr, msgs[i].len,
566ce8591ffSMauro Carvalho Chehab 			msgs[i].len, msgs[i].buf);
567a6c2ba28Sakpm@osdl.org 	}
568a6c2ba28Sakpm@osdl.org 
569aab3125cSMauro Carvalho Chehab 	rt_mutex_unlock(&dev->i2c_bus_lock);
570a6c2ba28Sakpm@osdl.org 	return num;
571ce8591ffSMauro Carvalho Chehab 
572ce8591ffSMauro Carvalho Chehab error:
573ce8591ffSMauro Carvalho Chehab 	dprintk(2, "%s %s addr=%02x len=%d: %sERROR: %i\n",
574ce8591ffSMauro Carvalho Chehab 		(msgs[i].flags & I2C_M_RD) ? "read" : "write",
575ce8591ffSMauro Carvalho Chehab 		i == num - 1 ? "stop" : "nonstop",
576ce8591ffSMauro Carvalho Chehab 		addr, msgs[i].len,
577ce8591ffSMauro Carvalho Chehab 		(rc == -ENODEV) ? "no device " : "",
578ce8591ffSMauro Carvalho Chehab 		rc);
579ce8591ffSMauro Carvalho Chehab 
580ce8591ffSMauro Carvalho Chehab 	rt_mutex_unlock(&dev->i2c_bus_lock);
581ce8591ffSMauro Carvalho Chehab 	return rc;
582a6c2ba28Sakpm@osdl.org }
583a6c2ba28Sakpm@osdl.org 
584fa74aca3SFrank Schaefer /*
585fa74aca3SFrank Schaefer  * based on linux/sunrpc/svcauth.h and linux/hash.h
58603910cc3SMauro Carvalho Chehab  * The original hash function returns a different value, if arch is x86_64
58703910cc3SMauro Carvalho Chehab  * or i386.
58803910cc3SMauro Carvalho Chehab  */
58903910cc3SMauro Carvalho Chehab static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits)
59003910cc3SMauro Carvalho Chehab {
59103910cc3SMauro Carvalho Chehab 	unsigned long hash = 0;
59203910cc3SMauro Carvalho Chehab 	unsigned long l = 0;
59303910cc3SMauro Carvalho Chehab 	int len = 0;
59403910cc3SMauro Carvalho Chehab 	unsigned char c;
595fdf1bc9fSMauro Carvalho Chehab 
59603910cc3SMauro Carvalho Chehab 	do {
59703910cc3SMauro Carvalho Chehab 		if (len == length) {
59803910cc3SMauro Carvalho Chehab 			c = (char)len;
59903910cc3SMauro Carvalho Chehab 			len = -1;
60003910cc3SMauro Carvalho Chehab 		} else
60103910cc3SMauro Carvalho Chehab 			c = *buf++;
60203910cc3SMauro Carvalho Chehab 		l = (l << 8) | c;
60303910cc3SMauro Carvalho Chehab 		len++;
60403910cc3SMauro Carvalho Chehab 		if ((len & (32 / 8 - 1)) == 0)
60503910cc3SMauro Carvalho Chehab 			hash = ((hash^l) * 0x9e370001UL);
60603910cc3SMauro Carvalho Chehab 	} while (len);
60703910cc3SMauro Carvalho Chehab 
60803910cc3SMauro Carvalho Chehab 	return (hash >> (32 - bits)) & 0xffffffffUL;
60903910cc3SMauro Carvalho Chehab }
61003910cc3SMauro 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)
654a6c2ba28Sakpm@osdl.org {
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;
664a6c2ba28Sakpm@osdl.org 
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;
671596d92d5SMauro Carvalho Chehab 
672596d92d5SMauro Carvalho Chehab 	/* Check if board has eeprom */
673aab3125cSMauro Carvalho Chehab 	err = i2c_master_recv(&dev->i2c_client[bus], &buf, 0);
674f2a01a00SDouglas Schilling Landgraf 	if (err < 0) {
675*29b05e22SMauro Carvalho Chehab 		dev_info(&dev->intf->dev, "board has no eeprom\n");
676c41109fcSMauro Carvalho Chehab 		return -ENODEV;
677f2a01a00SDouglas Schilling Landgraf 	}
678596d92d5SMauro 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) {
688*29b05e22SMauro Carvalho Chehab 		dev_err(&dev->intf->dev,
689ce8591ffSMauro Carvalho Chehab 			"failed to read eeprom (err=%d)\n", err);
690510e884cSFrank Schaefer 		goto error;
691a6c2ba28Sakpm@osdl.org 	}
69290271964SFrank Schaefer 
69350f0a9dfSMauro Carvalho Chehab 	if (i2c_debug) {
69487b52439SFrank Schaefer 		/* Display eeprom content */
695ce8591ffSMauro Carvalho Chehab 		print_hex_dump(KERN_DEBUG, "em28xx eeprom ", DUMP_PREFIX_OFFSET,
69650f0a9dfSMauro Carvalho Chehab 			       16, 1, data, len, true);
69750f0a9dfSMauro Carvalho Chehab 
69887b52439SFrank Schaefer 		if (dev->eeprom_addrwidth_16bit)
699*29b05e22SMauro Carvalho Chehab 			dev_info(&dev->intf->dev,
700ce8591ffSMauro Carvalho Chehab 				 "eeprom %06x: ... (skipped)\n", 256);
70187b52439SFrank Schaefer 	}
702a6c2ba28Sakpm@osdl.org 
70387b52439SFrank Schaefer 	if (dev->eeprom_addrwidth_16bit &&
704a217968fSFrank Schaefer 	    data[0] == 0x26 && data[3] == 0x00) {
70587b52439SFrank Schaefer 		/* new eeprom format; size 4-64kb */
706510e884cSFrank Schaefer 		u16 mc_start;
707510e884cSFrank Schaefer 		u16 hwconf_offset;
708510e884cSFrank Schaefer 
709a217968fSFrank Schaefer 		dev->hash = em28xx_hash_mem(data, len, 32);
710510e884cSFrank Schaefer 		mc_start = (data[1] << 8) + 4;	/* usually 0x0004 */
711510e884cSFrank Schaefer 
712*29b05e22SMauro Carvalho Chehab 		dev_info(&dev->intf->dev,
713ce8591ffSMauro Carvalho Chehab 			 "EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n",
714510e884cSFrank Schaefer 			 data[0], data[1], data[2], data[3], dev->hash);
715*29b05e22SMauro Carvalho Chehab 		dev_info(&dev->intf->dev,
716ce8591ffSMauro Carvalho Chehab 			 "EEPROM info:\n");
717*29b05e22SMauro Carvalho Chehab 		dev_info(&dev->intf->dev,
718ce8591ffSMauro Carvalho Chehab 			 "\tmicrocode start address = 0x%04x, boot configuration = 0x%02x\n",
719510e884cSFrank Schaefer 			 mc_start, data[2]);
720fa74aca3SFrank Schaefer 		/*
721fa74aca3SFrank Schaefer 		 * boot configuration (address 0x0002):
72287b52439SFrank Schaefer 		 * [0]   microcode download speed: 1 = 400 kHz; 0 = 100 kHz
72387b52439SFrank Schaefer 		 * [1]   always selects 12 kb RAM
72487b52439SFrank Schaefer 		 * [2]   USB device speed: 1 = force Full Speed; 0 = auto detect
72587b52439SFrank Schaefer 		 * [4]   1 = force fast mode and no suspend for device testing
72687b52439SFrank Schaefer 		 * [5:7] USB PHY tuning registers; determined by device
72787b52439SFrank Schaefer 		 *       characterization
72887b52439SFrank Schaefer 		 */
72987b52439SFrank Schaefer 
730fa74aca3SFrank Schaefer 		/*
731fa74aca3SFrank Schaefer 		 * Read hardware config dataset offset from address
732fa74aca3SFrank Schaefer 		 * (microcode start + 46)
733fa74aca3SFrank Schaefer 		 */
734aab3125cSMauro Carvalho Chehab 		err = em28xx_i2c_read_block(dev, bus, mc_start + 46, 1, 2,
735aab3125cSMauro Carvalho Chehab 					    data);
736510e884cSFrank Schaefer 		if (err != 2) {
737*29b05e22SMauro Carvalho Chehab 			dev_err(&dev->intf->dev,
738ce8591ffSMauro Carvalho Chehab 				"failed to read hardware configuration data from eeprom (err=%d)\n",
739510e884cSFrank Schaefer 				err);
740510e884cSFrank Schaefer 			goto error;
741510e884cSFrank Schaefer 		}
74287b52439SFrank Schaefer 
743510e884cSFrank Schaefer 		/* Calculate hardware config dataset start address */
744510e884cSFrank Schaefer 		hwconf_offset = mc_start + data[0] + (data[1] << 8);
745510e884cSFrank Schaefer 
746510e884cSFrank Schaefer 		/* Read hardware config dataset */
747fa74aca3SFrank Schaefer 		/*
748fa74aca3SFrank Schaefer 		 * NOTE: the microcode copy can be multiple pages long, but
749510e884cSFrank Schaefer 		 * we assume the hardware config dataset is the same as in
750510e884cSFrank Schaefer 		 * the old eeprom and not longer than 256 bytes.
751510e884cSFrank Schaefer 		 * tveeprom is currently also limited to 256 bytes.
752510e884cSFrank Schaefer 		 */
753aab3125cSMauro Carvalho Chehab 		err = em28xx_i2c_read_block(dev, bus, hwconf_offset, 1, len,
754aab3125cSMauro Carvalho Chehab 					    data);
755510e884cSFrank Schaefer 		if (err != len) {
756*29b05e22SMauro Carvalho Chehab 			dev_err(&dev->intf->dev,
757ce8591ffSMauro Carvalho Chehab 				"failed to read hardware configuration data from eeprom (err=%d)\n",
758510e884cSFrank Schaefer 				err);
759510e884cSFrank Schaefer 			goto error;
760510e884cSFrank Schaefer 		}
761510e884cSFrank Schaefer 
762510e884cSFrank Schaefer 		/* Verify hardware config dataset */
763510e884cSFrank Schaefer 		/* NOTE: not all devices provide this type of dataset */
764510e884cSFrank Schaefer 		if (data[0] != 0x1a || data[1] != 0xeb ||
765a217968fSFrank Schaefer 		    data[2] != 0x67 || data[3] != 0x95) {
766*29b05e22SMauro Carvalho Chehab 			dev_info(&dev->intf->dev,
767ce8591ffSMauro Carvalho Chehab 				 "\tno hardware configuration dataset found in eeprom\n");
768510e884cSFrank Schaefer 			kfree(data);
769510e884cSFrank Schaefer 			return 0;
770510e884cSFrank Schaefer 		}
771510e884cSFrank Schaefer 
772510e884cSFrank Schaefer 		/* TODO: decrypt eeprom data for camera bridges (em25xx, em276x+) */
773510e884cSFrank Schaefer 
774510e884cSFrank Schaefer 	} else if (!dev->eeprom_addrwidth_16bit &&
775510e884cSFrank Schaefer 		   data[0] == 0x1a && data[1] == 0xeb &&
776510e884cSFrank Schaefer 		   data[2] == 0x67 && data[3] == 0x95) {
777510e884cSFrank Schaefer 		dev->hash = em28xx_hash_mem(data, len, 32);
778*29b05e22SMauro Carvalho Chehab 		dev_info(&dev->intf->dev,
779ce8591ffSMauro Carvalho Chehab 			 "EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n",
780510e884cSFrank Schaefer 			 data[0], data[1], data[2], data[3], dev->hash);
781*29b05e22SMauro Carvalho Chehab 		dev_info(&dev->intf->dev,
782ce8591ffSMauro Carvalho Chehab 			 "EEPROM info:\n");
783510e884cSFrank Schaefer 	} else {
784*29b05e22SMauro Carvalho Chehab 		dev_info(&dev->intf->dev,
785ce8591ffSMauro Carvalho Chehab 			 "unknown eeprom format or eeprom corrupted !\n");
786510e884cSFrank Schaefer 		err = -ENODEV;
787510e884cSFrank Schaefer 		goto error;
788f55eacbeSFrank Schaefer 	}
789f55eacbeSFrank Schaefer 
790a217968fSFrank Schaefer 	*eedata = data;
791510e884cSFrank Schaefer 	*eedata_len = len;
79232bf7c6cSAlban Browaeys 	dev_config = (void *)*eedata;
793a217968fSFrank Schaefer 
794510e884cSFrank Schaefer 	switch (le16_to_cpu(dev_config->chip_conf) >> 4 & 0x3) {
795a6c2ba28Sakpm@osdl.org 	case 0:
796*29b05e22SMauro Carvalho Chehab 		dev_info(&dev->intf->dev, "\tNo audio on board.\n");
797a6c2ba28Sakpm@osdl.org 		break;
798a6c2ba28Sakpm@osdl.org 	case 1:
799*29b05e22SMauro Carvalho Chehab 		dev_info(&dev->intf->dev, "\tAC97 audio (5 sample rates)\n");
800a6c2ba28Sakpm@osdl.org 		break;
801a6c2ba28Sakpm@osdl.org 	case 2:
802687ff8b0SFrank Schaefer 		if (dev->chip_id < CHIP_ID_EM2860)
803*29b05e22SMauro Carvalho Chehab 			dev_info(&dev->intf->dev,
804ce8591ffSMauro Carvalho Chehab 				 "\tI2S audio, sample rate=32k\n");
805687ff8b0SFrank Schaefer 		else
806*29b05e22SMauro Carvalho Chehab 			dev_info(&dev->intf->dev,
807ce8591ffSMauro Carvalho Chehab 				 "\tI2S audio, 3 sample rates\n");
808a6c2ba28Sakpm@osdl.org 		break;
809a6c2ba28Sakpm@osdl.org 	case 3:
810687ff8b0SFrank Schaefer 		if (dev->chip_id < CHIP_ID_EM2860)
811*29b05e22SMauro Carvalho Chehab 			dev_info(&dev->intf->dev,
812ce8591ffSMauro Carvalho Chehab 				 "\tI2S audio, 3 sample rates\n");
813687ff8b0SFrank Schaefer 		else
814*29b05e22SMauro Carvalho Chehab 			dev_info(&dev->intf->dev,
815ce8591ffSMauro Carvalho Chehab 				 "\tI2S audio, 5 sample rates\n");
816a6c2ba28Sakpm@osdl.org 		break;
817a6c2ba28Sakpm@osdl.org 	}
818a6c2ba28Sakpm@osdl.org 
819510e884cSFrank Schaefer 	if (le16_to_cpu(dev_config->chip_conf) & 1 << 3)
820*29b05e22SMauro Carvalho Chehab 		dev_info(&dev->intf->dev, "\tUSB Remote wakeup capable\n");
821a6c2ba28Sakpm@osdl.org 
822510e884cSFrank Schaefer 	if (le16_to_cpu(dev_config->chip_conf) & 1 << 2)
823*29b05e22SMauro Carvalho Chehab 		dev_info(&dev->intf->dev, "\tUSB Self power capable\n");
824a6c2ba28Sakpm@osdl.org 
825510e884cSFrank Schaefer 	switch (le16_to_cpu(dev_config->chip_conf) & 0x3) {
826a6c2ba28Sakpm@osdl.org 	case 0:
827*29b05e22SMauro Carvalho Chehab 		dev_info(&dev->intf->dev, "\t500mA max power\n");
828a6c2ba28Sakpm@osdl.org 		break;
829a6c2ba28Sakpm@osdl.org 	case 1:
830*29b05e22SMauro Carvalho Chehab 		dev_info(&dev->intf->dev, "\t400mA max power\n");
831a6c2ba28Sakpm@osdl.org 		break;
832a6c2ba28Sakpm@osdl.org 	case 2:
833*29b05e22SMauro Carvalho Chehab 		dev_info(&dev->intf->dev, "\t300mA max power\n");
834a6c2ba28Sakpm@osdl.org 		break;
835a6c2ba28Sakpm@osdl.org 	case 3:
836*29b05e22SMauro Carvalho Chehab 		dev_info(&dev->intf->dev, "\t200mA max power\n");
837a6c2ba28Sakpm@osdl.org 		break;
838a6c2ba28Sakpm@osdl.org 	}
839*29b05e22SMauro Carvalho Chehab 	dev_info(&dev->intf->dev,
840ce8591ffSMauro Carvalho Chehab 		 "\tTable at offset 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
841510e884cSFrank Schaefer 		 dev_config->string_idx_table,
842510e884cSFrank Schaefer 		 le16_to_cpu(dev_config->string1),
843510e884cSFrank Schaefer 		 le16_to_cpu(dev_config->string2),
844510e884cSFrank Schaefer 		 le16_to_cpu(dev_config->string3));
845a6c2ba28Sakpm@osdl.org 
846a6c2ba28Sakpm@osdl.org 	return 0;
847510e884cSFrank Schaefer 
848510e884cSFrank Schaefer error:
849510e884cSFrank Schaefer 	kfree(data);
850510e884cSFrank Schaefer 	return err;
851a6c2ba28Sakpm@osdl.org }
852a6c2ba28Sakpm@osdl.org 
853a6c2ba28Sakpm@osdl.org /* ----------------------------------------------------------- */
854a6c2ba28Sakpm@osdl.org 
855a6c2ba28Sakpm@osdl.org /*
856a6c2ba28Sakpm@osdl.org  * functionality()
857a6c2ba28Sakpm@osdl.org  */
858aab3125cSMauro Carvalho Chehab static u32 functionality(struct i2c_adapter *i2c_adap)
859a6c2ba28Sakpm@osdl.org {
860aab3125cSMauro Carvalho Chehab 	struct em28xx_i2c_bus *i2c_bus = i2c_adap->algo_data;
861aab3125cSMauro Carvalho Chehab 
862a3ea4bf9SFrank Schaefer 	if ((i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX) ||
863a3ea4bf9SFrank Schaefer 	    (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)) {
864a3ea4bf9SFrank Schaefer 		return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
865a3ea4bf9SFrank Schaefer 	} else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800)  {
866a3ea4bf9SFrank Schaefer 		return (I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL) &
867a3ea4bf9SFrank Schaefer 			~I2C_FUNC_SMBUS_WRITE_BLOCK_DATA;
868a3ea4bf9SFrank Schaefer 	}
869a3ea4bf9SFrank Schaefer 
870a3ea4bf9SFrank Schaefer 	WARN(1, "Unknown i2c bus algorithm.\n");
871a3ea4bf9SFrank Schaefer 	return 0;
872a6c2ba28Sakpm@osdl.org }
873a6c2ba28Sakpm@osdl.org 
87478f2c50bSJulia Lawall static const struct i2c_algorithm em28xx_algo = {
8753acf2809SMauro Carvalho Chehab 	.master_xfer   = em28xx_i2c_xfer,
876a6c2ba28Sakpm@osdl.org 	.functionality = functionality,
877a6c2ba28Sakpm@osdl.org };
878a6c2ba28Sakpm@osdl.org 
8793acf2809SMauro Carvalho Chehab static struct i2c_adapter em28xx_adap_template = {
880a6c2ba28Sakpm@osdl.org 	.owner = THIS_MODULE,
8813acf2809SMauro Carvalho Chehab 	.name = "em28xx",
8823acf2809SMauro Carvalho Chehab 	.algo = &em28xx_algo,
883a6c2ba28Sakpm@osdl.org };
884a6c2ba28Sakpm@osdl.org 
8853acf2809SMauro Carvalho Chehab static struct i2c_client em28xx_client_template = {
8863acf2809SMauro Carvalho Chehab 	.name = "em28xx internal",
887a6c2ba28Sakpm@osdl.org };
888a6c2ba28Sakpm@osdl.org 
889a6c2ba28Sakpm@osdl.org /* ----------------------------------------------------------- */
890a6c2ba28Sakpm@osdl.org 
891a6c2ba28Sakpm@osdl.org /*
892a6c2ba28Sakpm@osdl.org  * i2c_devs
893a6c2ba28Sakpm@osdl.org  * incomplete list of known devices
894a6c2ba28Sakpm@osdl.org  */
895a6c2ba28Sakpm@osdl.org static char *i2c_devs[128] = {
8969aa785b1SWilson Michaels        [0x1c >> 1] = "lgdt330x",
8970b3966e4SFrank Schaefer 	[0x3e >> 1] = "remote IR sensor",
898a6c2ba28Sakpm@osdl.org 	[0x4a >> 1] = "saa7113h",
899729841edSMartin Blumenstingl 	[0x52 >> 1] = "drxk",
900a6c2ba28Sakpm@osdl.org 	[0x60 >> 1] = "remote IR sensor",
901da45a2a5SMarkus Rechberger 	[0x8e >> 1] = "remote IR sensor",
902a6c2ba28Sakpm@osdl.org 	[0x86 >> 1] = "tda9887",
903a6c2ba28Sakpm@osdl.org 	[0x80 >> 1] = "msp34xx",
904a6c2ba28Sakpm@osdl.org 	[0x88 >> 1] = "msp34xx",
905a6c2ba28Sakpm@osdl.org 	[0xa0 >> 1] = "eeprom",
9062bd1d9ebSVitaly Wool 	[0xb0 >> 1] = "tda9874",
907a6c2ba28Sakpm@osdl.org 	[0xb8 >> 1] = "tvp5150a",
908791a08fcSMauro Carvalho Chehab 	[0xba >> 1] = "webcam sensor or tvp5150a",
909a6c2ba28Sakpm@osdl.org 	[0xc0 >> 1] = "tuner (analog)",
910a6c2ba28Sakpm@osdl.org 	[0xc2 >> 1] = "tuner (analog)",
911a6c2ba28Sakpm@osdl.org 	[0xc4 >> 1] = "tuner (analog)",
912a6c2ba28Sakpm@osdl.org 	[0xc6 >> 1] = "tuner (analog)",
913a6c2ba28Sakpm@osdl.org };
914a6c2ba28Sakpm@osdl.org 
915a6c2ba28Sakpm@osdl.org /*
916a6c2ba28Sakpm@osdl.org  * do_i2c_scan()
917a6c2ba28Sakpm@osdl.org  * check i2c address range for devices
918a6c2ba28Sakpm@osdl.org  */
919aab3125cSMauro Carvalho Chehab void em28xx_do_i2c_scan(struct em28xx *dev, unsigned bus)
920a6c2ba28Sakpm@osdl.org {
921fad7b958SSascha Sommer 	u8 i2c_devicelist[128];
922a6c2ba28Sakpm@osdl.org 	unsigned char buf;
923a6c2ba28Sakpm@osdl.org 	int i, rc;
924a6c2ba28Sakpm@osdl.org 
925fad7b958SSascha Sommer 	memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist));
926fad7b958SSascha Sommer 
92753c4e955SMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
928aab3125cSMauro Carvalho Chehab 		dev->i2c_client[bus].addr = i;
929aab3125cSMauro Carvalho Chehab 		rc = i2c_master_recv(&dev->i2c_client[bus], &buf, 0);
930a6c2ba28Sakpm@osdl.org 		if (rc < 0)
931a6c2ba28Sakpm@osdl.org 			continue;
932fad7b958SSascha Sommer 		i2c_devicelist[i] = i;
933*29b05e22SMauro Carvalho Chehab 		dev_info(&dev->intf->dev,
934ce8591ffSMauro Carvalho Chehab 			 "found i2c device @ 0x%x on bus %d [%s]\n",
935aab3125cSMauro Carvalho Chehab 			 i << 1, bus, i2c_devs[i] ? i2c_devs[i] : "???");
936a6c2ba28Sakpm@osdl.org 	}
937fad7b958SSascha Sommer 
938aab3125cSMauro Carvalho Chehab 	if (bus == dev->def_i2c_bus)
939fad7b958SSascha Sommer 		dev->i2c_hash = em28xx_hash_mem(i2c_devicelist,
940fad7b958SSascha Sommer 						ARRAY_SIZE(i2c_devicelist), 32);
941a6c2ba28Sakpm@osdl.org }
942a6c2ba28Sakpm@osdl.org 
943a6c2ba28Sakpm@osdl.org /*
9443acf2809SMauro Carvalho Chehab  * em28xx_i2c_register()
945a6c2ba28Sakpm@osdl.org  * register i2c bus
946a6c2ba28Sakpm@osdl.org  */
947a3ea4bf9SFrank Schaefer int em28xx_i2c_register(struct em28xx *dev, unsigned bus,
948a3ea4bf9SFrank Schaefer 			enum em28xx_i2c_algo_type algo_type)
949a6c2ba28Sakpm@osdl.org {
950f2a01a00SDouglas Schilling Landgraf 	int retval;
951f2a01a00SDouglas Schilling Landgraf 
9523acf2809SMauro Carvalho Chehab 	BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg);
9533acf2809SMauro Carvalho Chehab 	BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req);
954f2a01a00SDouglas Schilling Landgraf 
955aab3125cSMauro Carvalho Chehab 	if (bus >= NUM_I2C_BUSES)
956aab3125cSMauro Carvalho Chehab 		return -ENODEV;
957aab3125cSMauro Carvalho Chehab 
958aab3125cSMauro Carvalho Chehab 	dev->i2c_adap[bus] = em28xx_adap_template;
959*29b05e22SMauro Carvalho Chehab 	dev->i2c_adap[bus].dev.parent = &dev->intf->dev;
960*29b05e22SMauro Carvalho Chehab 	strcpy(dev->i2c_adap[bus].name, dev_name(&dev->intf->dev));
961aab3125cSMauro Carvalho Chehab 
962aab3125cSMauro Carvalho Chehab 	dev->i2c_bus[bus].bus = bus;
963a3ea4bf9SFrank Schaefer 	dev->i2c_bus[bus].algo_type = algo_type;
964aab3125cSMauro Carvalho Chehab 	dev->i2c_bus[bus].dev = dev;
965aab3125cSMauro Carvalho Chehab 	dev->i2c_adap[bus].algo_data = &dev->i2c_bus[bus];
966aab3125cSMauro Carvalho Chehab 
967aab3125cSMauro Carvalho Chehab 	retval = i2c_add_adapter(&dev->i2c_adap[bus]);
968f2a01a00SDouglas Schilling Landgraf 	if (retval < 0) {
969*29b05e22SMauro Carvalho Chehab 		dev_err(&dev->intf->dev,
970ce8591ffSMauro Carvalho Chehab 			"%s: i2c_add_adapter failed! retval [%d]\n",
971f2a01a00SDouglas Schilling Landgraf 			__func__, retval);
972f2a01a00SDouglas Schilling Landgraf 		return retval;
973f2a01a00SDouglas Schilling Landgraf 	}
974a6c2ba28Sakpm@osdl.org 
975aab3125cSMauro Carvalho Chehab 	dev->i2c_client[bus] = em28xx_client_template;
976aab3125cSMauro Carvalho Chehab 	dev->i2c_client[bus].adapter = &dev->i2c_adap[bus];
977a6c2ba28Sakpm@osdl.org 
978aab3125cSMauro Carvalho Chehab 	/* Up to now, all eeproms are at bus 0 */
979aab3125cSMauro Carvalho Chehab 	if (!bus) {
980aab3125cSMauro Carvalho Chehab 		retval = em28xx_i2c_eeprom(dev, bus, &dev->eedata, &dev->eedata_len);
981c41109fcSMauro Carvalho Chehab 		if ((retval < 0) && (retval != -ENODEV)) {
982*29b05e22SMauro Carvalho Chehab 			dev_err(&dev->intf->dev,
983ce8591ffSMauro Carvalho Chehab 				"%s: em28xx_i2_eeprom failed! retval [%d]\n",
984f2a01a00SDouglas Schilling Landgraf 				__func__, retval);
985c41109fcSMauro Carvalho Chehab 
986f2a01a00SDouglas Schilling Landgraf 			return retval;
987f2a01a00SDouglas Schilling Landgraf 		}
988aab3125cSMauro Carvalho Chehab 	}
989a6c2ba28Sakpm@osdl.org 
990a6c2ba28Sakpm@osdl.org 	if (i2c_scan)
991aab3125cSMauro Carvalho Chehab 		em28xx_do_i2c_scan(dev, bus);
992c41109fcSMauro Carvalho Chehab 
993a6c2ba28Sakpm@osdl.org 	return 0;
994a6c2ba28Sakpm@osdl.org }
995a6c2ba28Sakpm@osdl.org 
996a6c2ba28Sakpm@osdl.org /*
9973acf2809SMauro Carvalho Chehab  * em28xx_i2c_unregister()
998a6c2ba28Sakpm@osdl.org  * unregister i2c_bus
999a6c2ba28Sakpm@osdl.org  */
1000aab3125cSMauro Carvalho Chehab int em28xx_i2c_unregister(struct em28xx *dev, unsigned bus)
1001a6c2ba28Sakpm@osdl.org {
1002aab3125cSMauro Carvalho Chehab 	if (bus >= NUM_I2C_BUSES)
1003aab3125cSMauro Carvalho Chehab 		return -ENODEV;
1004aab3125cSMauro Carvalho Chehab 
1005aab3125cSMauro Carvalho Chehab 	i2c_del_adapter(&dev->i2c_adap[bus]);
1006a6c2ba28Sakpm@osdl.org 	return 0;
1007a6c2ba28Sakpm@osdl.org }
1008