blob: 44533e4574ffe6fd2cc746aab0d249b48a0510b1 [file] [log] [blame]
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001/*
Mauro Carvalho Chehabf7abcd32005-11-08 21:38:25 -08002 em28xx-i2c.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08003
Mauro Carvalho Chehabf7abcd32005-11-08 21:38:25 -08004 Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
5 Markus Rechberger <mrechberger@gmail.com>
Mauro Carvalho Chehab2e7c6dc2006-04-03 07:53:40 -03006 Mauro Carvalho Chehab <mchehab@infradead.org>
Mauro Carvalho Chehabf7abcd32005-11-08 21:38:25 -08007 Sascha Sommer <saschasommer@freenet.de>
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08008
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24#include <linux/module.h>
25#include <linux/kernel.h>
26#include <linux/usb.h>
27#include <linux/i2c.h>
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080028
Mauro Carvalho Chehabf7abcd32005-11-08 21:38:25 -080029#include "em28xx.h"
Mauro Carvalho Chehab6c362c82007-10-29 23:36:12 -030030#include "tuner-xc2028.h"
Michael Krufky5e453dc2006-01-09 15:32:31 -020031#include <media/v4l2-common.h>
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -080032#include <media/tuner.h>
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080033
34/* ----------------------------------------------------------- */
35
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030036static unsigned int i2c_scan;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080037module_param(i2c_scan, int, 0444);
38MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
39
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030040static unsigned int i2c_debug;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080041module_param(i2c_debug, int, 0644);
42MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
43
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -030044#define dprintk2(lvl, fmt, args...) \
45do { \
46 if (i2c_debug >= lvl) { \
47 printk(KERN_DEBUG "%s at %s: " fmt, \
48 dev->name, __func__ , ##args); \
49 } \
50} while (0)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080051
52/*
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080053 * em2800_i2c_send_max4()
54 * send up to 4 bytes to the i2c device
55 */
Frank Schaefera6bad042012-12-16 14:23:27 -030056static int em2800_i2c_send_max4(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080057{
58 int ret;
59 int write_timeout;
Frank Schaefera6bad042012-12-16 14:23:27 -030060 u8 b2[6];
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080061 BUG_ON(len < 1 || len > 4);
62 b2[5] = 0x80 + len - 1;
63 b2[4] = addr;
64 b2[3] = buf[0];
65 if (len > 1)
66 b2[2] = buf[1];
67 if (len > 2)
68 b2[1] = buf[2];
69 if (len > 3)
70 b2[0] = buf[3];
71
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080072 ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080073 if (ret != 2 + len) {
Robert P. J. Daybeb7dd82007-05-09 07:14:03 +020074 em28xx_warn("writing to i2c device failed (error=%i)\n", ret);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080075 return -EIO;
76 }
77 for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
78 write_timeout -= 5) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080079 ret = dev->em28xx_read_reg(dev, 0x05);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080080 if (ret == 0x80 + len - 1)
81 return len;
Markus Rechbergere8e41da2006-02-07 06:49:11 -020082 msleep(5);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080083 }
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080084 em28xx_warn("i2c write timed out\n");
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080085 return -EIO;
86}
87
88/*
89 * em2800_i2c_send_bytes()
90 */
Frank Schaefera6bad042012-12-16 14:23:27 -030091static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080092{
Frank Schaefera6bad042012-12-16 14:23:27 -030093 u8 *bufPtr = buf;
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080094 int ret;
95 int wrcount = 0;
96 int count;
97 int maxLen = 4;
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080098 while (len > 0) {
99 count = (len > maxLen) ? maxLen : len;
100 ret = em2800_i2c_send_max4(dev, addr, bufPtr, count);
101 if (ret > 0) {
102 len -= count;
103 bufPtr += count;
104 wrcount += count;
105 } else
106 return (ret < 0) ? ret : -EFAULT;
107 }
108 return wrcount;
109}
110
111/*
112 * em2800_i2c_check_for_device()
113 * check if there is a i2c_device at the supplied address
114 */
Frank Schaefera6bad042012-12-16 14:23:27 -0300115static int em2800_i2c_check_for_device(struct em28xx *dev, u8 addr)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800116{
Frank Schaefera6bad042012-12-16 14:23:27 -0300117 u8 msg;
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800118 int ret;
119 int write_timeout;
120 msg = addr;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800121 ret = dev->em28xx_write_regs(dev, 0x04, &msg, 1);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800122 if (ret < 0) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800123 em28xx_warn("setting i2c device address failed (error=%i)\n",
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800124 ret);
125 return ret;
126 }
127 msg = 0x84;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800128 ret = dev->em28xx_write_regs(dev, 0x05, &msg, 1);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800129 if (ret < 0) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800130 em28xx_warn("preparing i2c read failed (error=%i)\n", ret);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800131 return ret;
132 }
133 for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
134 write_timeout -= 5) {
Hans Verkuild45b9b82008-09-04 03:33:43 -0300135 unsigned reg = dev->em28xx_read_reg(dev, 0x5);
136
137 if (reg == 0x94)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800138 return -ENODEV;
Hans Verkuild45b9b82008-09-04 03:33:43 -0300139 else if (reg == 0x84)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800140 return 0;
Markus Rechbergere8e41da2006-02-07 06:49:11 -0200141 msleep(5);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800142 }
143 return -ENODEV;
144}
145
146/*
147 * em2800_i2c_recv_bytes()
148 * read from the i2c device
149 */
Frank Schaefera6bad042012-12-16 14:23:27 -0300150static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800151{
152 int ret;
153 /* check for the device and set i2c read address */
154 ret = em2800_i2c_check_for_device(dev, addr);
155 if (ret) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800156 em28xx_warn
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800157 ("preparing read at i2c address 0x%x failed (error=%i)\n",
158 addr, ret);
159 return ret;
160 }
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800161 ret = dev->em28xx_read_reg_req_len(dev, 0x0, 0x3, buf, len);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800162 if (ret < 0) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800163 em28xx_warn("reading from i2c device at 0x%x failed (error=%i)",
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800164 addr, ret);
165 return ret;
166 }
167 return ret;
168}
169
170/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800171 * em28xx_i2c_send_bytes()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800172 */
Frank Schaefera6bad042012-12-16 14:23:27 -0300173static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
174 u16 len, int stop)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800175{
176 int wrcount = 0;
Mauro Carvalho Chehabbbc70e62011-07-09 19:36:11 -0300177 int write_timeout, ret;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800178
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800179 wrcount = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800180
Mauro Carvalho Chehabbbc70e62011-07-09 19:36:11 -0300181 /* Seems to be required after a write */
182 for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
183 write_timeout -= 5) {
184 ret = dev->em28xx_read_reg(dev, 0x05);
185 if (!ret)
186 break;
187 msleep(5);
188 }
189
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800190 return wrcount;
191}
192
193/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800194 * em28xx_i2c_recv_bytes()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800195 * read a byte from the i2c device
196 */
Frank Schaefera6bad042012-12-16 14:23:27 -0300197static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800198{
199 int ret;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800200 ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800201 if (ret < 0) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800202 em28xx_warn("reading i2c device failed (error=%i)\n", ret);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800203 return ret;
204 }
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800205 if (dev->em28xx_read_reg(dev, 0x5) != 0)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800206 return -ENODEV;
207 return ret;
208}
209
210/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800211 * em28xx_i2c_check_for_device()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800212 * check if there is a i2c_device at the supplied address
213 */
Frank Schaefera6bad042012-12-16 14:23:27 -0300214static int em28xx_i2c_check_for_device(struct em28xx *dev, u16 addr)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800215{
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800216 int ret;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800217
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800218 ret = dev->em28xx_read_reg_req(dev, 2, addr);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800219 if (ret < 0) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800220 em28xx_warn("reading from i2c device failed (error=%i)\n", ret);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800221 return ret;
222 }
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800223 if (dev->em28xx_read_reg(dev, 0x5) != 0)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800224 return -ENODEV;
225 return 0;
226}
227
228/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800229 * em28xx_i2c_xfer()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800230 * the main i2c transfer function
231 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800232static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800233 struct i2c_msg msgs[], int num)
234{
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800235 struct em28xx *dev = i2c_adap->algo_data;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800236 int addr, rc, i, byte;
237
238 if (num <= 0)
239 return 0;
240 for (i = 0; i < num; i++) {
241 addr = msgs[i].addr << 1;
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300242 dprintk2(2, "%s %s addr=%x len=%d:",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800243 (msgs[i].flags & I2C_M_RD) ? "read" : "write",
244 i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300245 if (!msgs[i].len) { /* no len: check only for device presence */
Mauro Carvalho Chehab505b6d02008-11-25 09:39:50 -0300246 if (dev->board.is_em2800)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800247 rc = em2800_i2c_check_for_device(dev, addr);
248 else
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800249 rc = em28xx_i2c_check_for_device(dev, addr);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800250 if (rc < 0) {
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300251 dprintk2(2, " no device\n");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800252 return rc;
253 }
254
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800255 } else if (msgs[i].flags & I2C_M_RD) {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800256 /* read bytes */
Mauro Carvalho Chehab505b6d02008-11-25 09:39:50 -0300257 if (dev->board.is_em2800)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800258 rc = em2800_i2c_recv_bytes(dev, addr,
259 msgs[i].buf,
260 msgs[i].len);
261 else
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800262 rc = em28xx_i2c_recv_bytes(dev, addr,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800263 msgs[i].buf,
264 msgs[i].len);
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300265 if (i2c_debug >= 2) {
266 for (byte = 0; byte < msgs[i].len; byte++)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800267 printk(" %02x", msgs[i].buf[byte]);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800268 }
269 } else {
270 /* write bytes */
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300271 if (i2c_debug >= 2) {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800272 for (byte = 0; byte < msgs[i].len; byte++)
273 printk(" %02x", msgs[i].buf[byte]);
274 }
Mauro Carvalho Chehab505b6d02008-11-25 09:39:50 -0300275 if (dev->board.is_em2800)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800276 rc = em2800_i2c_send_bytes(dev, addr,
277 msgs[i].buf,
278 msgs[i].len);
279 else
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800280 rc = em28xx_i2c_send_bytes(dev, addr,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800281 msgs[i].buf,
282 msgs[i].len,
283 i == num - 1);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800284 }
Markus Rechbergere8e41da2006-02-07 06:49:11 -0200285 if (rc < 0)
286 goto err;
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300287 if (i2c_debug >= 2)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800288 printk("\n");
289 }
290
291 return num;
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300292err:
293 dprintk2(2, " ERROR: %i\n", rc);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800294 return rc;
295}
296
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -0300297/* based on linux/sunrpc/svcauth.h and linux/hash.h
298 * The original hash function returns a different value, if arch is x86_64
299 * or i386.
300 */
301static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits)
302{
303 unsigned long hash = 0;
304 unsigned long l = 0;
305 int len = 0;
306 unsigned char c;
307 do {
308 if (len == length) {
309 c = (char)len;
310 len = -1;
311 } else
312 c = *buf++;
313 l = (l << 8) | c;
314 len++;
315 if ((len & (32 / 8 - 1)) == 0)
316 hash = ((hash^l) * 0x9e370001UL);
317 } while (len);
318
319 return (hash >> (32 - bits)) & 0xffffffffUL;
320}
321
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800322static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800323{
324 unsigned char buf, *p = eedata;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800325 struct em28xx_eeprom *em_eeprom = (void *)eedata;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800326 int i, err, size = len, block;
327
Mauro Carvalho Chehabfec528b2011-07-03 21:05:06 -0300328 if (dev->chip_id == CHIP_ID_EM2874 ||
329 dev->chip_id == CHIP_ID_EM28174 ||
330 dev->chip_id == CHIP_ID_EM2884) {
Devin Heitmuellera527c9f2008-11-12 02:05:10 -0300331 /* Empia switched to a 16-bit addressable eeprom in newer
332 devices. While we could certainly write a routine to read
333 the eeprom, there is nothing of use in there that cannot be
334 accessed through registers, and there is the risk that we
335 could corrupt the eeprom (since a 16-bit read call is
336 interpreted as a write call by 8-bit eeproms).
337 */
338 return 0;
339 }
340
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800341 dev->i2c_client.addr = 0xa0 >> 1;
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800342
343 /* Check if board has eeprom */
344 err = i2c_master_recv(&dev->i2c_client, &buf, 0);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300345 if (err < 0) {
Mauro Carvalho Chehabc41109f2008-11-15 23:44:14 -0300346 em28xx_errdev("board has no eeprom\n");
347 memset(eedata, 0, len);
348 return -ENODEV;
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300349 }
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800350
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800351 buf = 0;
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300352
353 err = i2c_master_send(&dev->i2c_client, &buf, 1);
354 if (err != 1) {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800355 printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
356 dev->name, err);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300357 return err;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800358 }
359 while (size > 0) {
360 if (size > 16)
361 block = 16;
362 else
363 block = size;
364
365 if (block !=
366 (err = i2c_master_recv(&dev->i2c_client, p, block))) {
367 printk(KERN_WARNING
368 "%s: i2c eeprom read error (err=%d)\n",
369 dev->name, err);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300370 return err;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800371 }
372 size -= block;
373 p += block;
374 }
375 for (i = 0; i < len; i++) {
376 if (0 == (i % 16))
377 printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
378 printk(" %02x", eedata[i]);
379 if (15 == (i % 16))
380 printk("\n");
381 }
382
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -0300383 if (em_eeprom->id == 0x9567eb1a)
384 dev->hash = em28xx_hash_mem(eedata, len, 32);
385
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300386 printk(KERN_INFO "%s: EEPROM ID= 0x%08x, EEPROM hash = 0x%08lx\n",
387 dev->name, em_eeprom->id, dev->hash);
388
389 printk(KERN_INFO "%s: EEPROM info:\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800390
391 switch (em_eeprom->chip_conf >> 4 & 0x3) {
392 case 0:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300393 printk(KERN_INFO "%s:\tNo audio on board.\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800394 break;
395 case 1:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300396 printk(KERN_INFO "%s:\tAC97 audio (5 sample rates)\n",
397 dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800398 break;
399 case 2:
Nicola Soranzoa1a6ee72009-02-10 23:28:24 -0300400 printk(KERN_INFO "%s:\tI2S audio, sample rate=32k\n",
401 dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800402 break;
403 case 3:
Nicola Soranzoa1a6ee72009-02-10 23:28:24 -0300404 printk(KERN_INFO "%s:\tI2S audio, 3 sample rates\n",
405 dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800406 break;
407 }
408
409 if (em_eeprom->chip_conf & 1 << 3)
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300410 printk(KERN_INFO "%s:\tUSB Remote wakeup capable\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800411
412 if (em_eeprom->chip_conf & 1 << 2)
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300413 printk(KERN_INFO "%s:\tUSB Self power capable\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800414
415 switch (em_eeprom->chip_conf & 0x3) {
416 case 0:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300417 printk(KERN_INFO "%s:\t500mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800418 break;
419 case 1:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300420 printk(KERN_INFO "%s:\t400mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800421 break;
422 case 2:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300423 printk(KERN_INFO "%s:\t300mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800424 break;
425 case 3:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300426 printk(KERN_INFO "%s:\t200mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800427 break;
428 }
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300429 printk(KERN_INFO "%s:\tTable at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
430 dev->name,
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300431 em_eeprom->string_idx_table,
432 em_eeprom->string1,
433 em_eeprom->string2,
434 em_eeprom->string3);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800435
436 return 0;
437}
438
439/* ----------------------------------------------------------- */
440
441/*
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800442 * functionality()
443 */
444static u32 functionality(struct i2c_adapter *adap)
445{
446 return I2C_FUNC_SMBUS_EMUL;
447}
448
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800449static struct i2c_algorithm em28xx_algo = {
450 .master_xfer = em28xx_i2c_xfer,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800451 .functionality = functionality,
452};
453
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800454static struct i2c_adapter em28xx_adap_template = {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800455 .owner = THIS_MODULE,
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800456 .name = "em28xx",
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800457 .algo = &em28xx_algo,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800458};
459
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800460static struct i2c_client em28xx_client_template = {
461 .name = "em28xx internal",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800462};
463
464/* ----------------------------------------------------------- */
465
466/*
467 * i2c_devs
468 * incomplete list of known devices
469 */
470static char *i2c_devs[128] = {
471 [0x4a >> 1] = "saa7113h",
Martin Blumenstingl729841e2012-06-12 18:19:27 -0300472 [0x52 >> 1] = "drxk",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800473 [0x60 >> 1] = "remote IR sensor",
Markus Rechbergerda45a2a2005-11-08 21:37:31 -0800474 [0x8e >> 1] = "remote IR sensor",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800475 [0x86 >> 1] = "tda9887",
476 [0x80 >> 1] = "msp34xx",
477 [0x88 >> 1] = "msp34xx",
478 [0xa0 >> 1] = "eeprom",
Vitaly Wool2bd1d9eb2009-03-04 08:27:52 -0300479 [0xb0 >> 1] = "tda9874",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800480 [0xb8 >> 1] = "tvp5150a",
Mauro Carvalho Chehab791a08f2009-07-03 15:36:18 -0300481 [0xba >> 1] = "webcam sensor or tvp5150a",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800482 [0xc0 >> 1] = "tuner (analog)",
483 [0xc2 >> 1] = "tuner (analog)",
484 [0xc4 >> 1] = "tuner (analog)",
485 [0xc6 >> 1] = "tuner (analog)",
486};
487
488/*
489 * do_i2c_scan()
490 * check i2c address range for devices
491 */
Sascha Sommerfad7b952007-11-04 08:06:48 -0300492void em28xx_do_i2c_scan(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800493{
Sascha Sommerfad7b952007-11-04 08:06:48 -0300494 u8 i2c_devicelist[128];
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800495 unsigned char buf;
496 int i, rc;
497
Sascha Sommerfad7b952007-11-04 08:06:48 -0300498 memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist));
499
Mauro Carvalho Chehab53c4e952007-03-29 08:42:30 -0300500 for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
Sascha Sommerfad7b952007-11-04 08:06:48 -0300501 dev->i2c_client.addr = i;
502 rc = i2c_master_recv(&dev->i2c_client, &buf, 0);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800503 if (rc < 0)
504 continue;
Sascha Sommerfad7b952007-11-04 08:06:48 -0300505 i2c_devicelist[i] = i;
506 printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n",
507 dev->name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800508 }
Sascha Sommerfad7b952007-11-04 08:06:48 -0300509
510 dev->i2c_hash = em28xx_hash_mem(i2c_devicelist,
511 ARRAY_SIZE(i2c_devicelist), 32);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800512}
513
514/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800515 * em28xx_i2c_register()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800516 * register i2c bus
517 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800518int em28xx_i2c_register(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800519{
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300520 int retval;
521
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800522 BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg);
523 BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req);
524 dev->i2c_adap = em28xx_adap_template;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800525 dev->i2c_adap.dev.parent = &dev->udev->dev;
526 strcpy(dev->i2c_adap.name, dev->name);
527 dev->i2c_adap.algo_data = dev;
Douglas Schilling Landgraff2cf2502009-03-31 17:10:58 -0300528 i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300529
530 retval = i2c_add_adapter(&dev->i2c_adap);
531 if (retval < 0) {
532 em28xx_errdev("%s: i2c_add_adapter failed! retval [%d]\n",
533 __func__, retval);
534 return retval;
535 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800536
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800537 dev->i2c_client = em28xx_client_template;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800538 dev->i2c_client.adapter = &dev->i2c_adap;
539
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300540 retval = em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata));
Mauro Carvalho Chehabc41109f2008-11-15 23:44:14 -0300541 if ((retval < 0) && (retval != -ENODEV)) {
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300542 em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n",
543 __func__, retval);
Mauro Carvalho Chehabc41109f2008-11-15 23:44:14 -0300544
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300545 return retval;
546 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800547
548 if (i2c_scan)
Sascha Sommerfad7b952007-11-04 08:06:48 -0300549 em28xx_do_i2c_scan(dev);
Mauro Carvalho Chehabc41109f2008-11-15 23:44:14 -0300550
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800551 return 0;
552}
553
554/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800555 * em28xx_i2c_unregister()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800556 * unregister i2c_bus
557 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800558int em28xx_i2c_unregister(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800559{
560 i2c_del_adapter(&dev->i2c_adap);
561 return 0;
562}