blob: 36f5a9bc8b765b56129dd6368d88146d938edb72 [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
45#define dprintk1(lvl, fmt, args...) \
46do { \
47 if (i2c_debug >= lvl) { \
48 printk(fmt, ##args); \
49 } \
50} while (0)
51
52#define dprintk2(lvl, fmt, args...) \
53do { \
54 if (i2c_debug >= lvl) { \
55 printk(KERN_DEBUG "%s at %s: " fmt, \
56 dev->name, __func__ , ##args); \
57 } \
58} while (0)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080059
60/*
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080061 * em2800_i2c_send_max4()
62 * send up to 4 bytes to the i2c device
63 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080064static int em2800_i2c_send_max4(struct em28xx *dev, unsigned char addr,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080065 char *buf, int len)
66{
67 int ret;
68 int write_timeout;
69 unsigned char b2[6];
70 BUG_ON(len < 1 || len > 4);
71 b2[5] = 0x80 + len - 1;
72 b2[4] = addr;
73 b2[3] = buf[0];
74 if (len > 1)
75 b2[2] = buf[1];
76 if (len > 2)
77 b2[1] = buf[2];
78 if (len > 3)
79 b2[0] = buf[3];
80
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080081 ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080082 if (ret != 2 + len) {
Robert P. J. Daybeb7dd82007-05-09 07:14:03 +020083 em28xx_warn("writing to i2c device failed (error=%i)\n", ret);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080084 return -EIO;
85 }
86 for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
87 write_timeout -= 5) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080088 ret = dev->em28xx_read_reg(dev, 0x05);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080089 if (ret == 0x80 + len - 1)
90 return len;
Markus Rechbergere8e41da2006-02-07 06:49:11 -020091 msleep(5);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080092 }
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080093 em28xx_warn("i2c write timed out\n");
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080094 return -EIO;
95}
96
97/*
98 * em2800_i2c_send_bytes()
99 */
100static int em2800_i2c_send_bytes(void *data, unsigned char addr, char *buf,
101 short len)
102{
103 char *bufPtr = buf;
104 int ret;
105 int wrcount = 0;
106 int count;
107 int maxLen = 4;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800108 struct em28xx *dev = (struct em28xx *)data;
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800109 while (len > 0) {
110 count = (len > maxLen) ? maxLen : len;
111 ret = em2800_i2c_send_max4(dev, addr, bufPtr, count);
112 if (ret > 0) {
113 len -= count;
114 bufPtr += count;
115 wrcount += count;
116 } else
117 return (ret < 0) ? ret : -EFAULT;
118 }
119 return wrcount;
120}
121
122/*
123 * em2800_i2c_check_for_device()
124 * check if there is a i2c_device at the supplied address
125 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800126static int em2800_i2c_check_for_device(struct em28xx *dev, unsigned char addr)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800127{
128 char msg;
129 int ret;
130 int write_timeout;
131 msg = addr;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800132 ret = dev->em28xx_write_regs(dev, 0x04, &msg, 1);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800133 if (ret < 0) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800134 em28xx_warn("setting i2c device address failed (error=%i)\n",
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800135 ret);
136 return ret;
137 }
138 msg = 0x84;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800139 ret = dev->em28xx_write_regs(dev, 0x05, &msg, 1);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800140 if (ret < 0) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800141 em28xx_warn("preparing i2c read failed (error=%i)\n", ret);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800142 return ret;
143 }
144 for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
145 write_timeout -= 5) {
Hans Verkuild45b9b82008-09-04 03:33:43 -0300146 unsigned reg = dev->em28xx_read_reg(dev, 0x5);
147
148 if (reg == 0x94)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800149 return -ENODEV;
Hans Verkuild45b9b82008-09-04 03:33:43 -0300150 else if (reg == 0x84)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800151 return 0;
Markus Rechbergere8e41da2006-02-07 06:49:11 -0200152 msleep(5);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800153 }
154 return -ENODEV;
155}
156
157/*
158 * em2800_i2c_recv_bytes()
159 * read from the i2c device
160 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800161static int em2800_i2c_recv_bytes(struct em28xx *dev, unsigned char addr,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800162 char *buf, int len)
163{
164 int ret;
165 /* check for the device and set i2c read address */
166 ret = em2800_i2c_check_for_device(dev, addr);
167 if (ret) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800168 em28xx_warn
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800169 ("preparing read at i2c address 0x%x failed (error=%i)\n",
170 addr, ret);
171 return ret;
172 }
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800173 ret = dev->em28xx_read_reg_req_len(dev, 0x0, 0x3, buf, len);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800174 if (ret < 0) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800175 em28xx_warn("reading from i2c device at 0x%x failed (error=%i)",
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800176 addr, ret);
177 return ret;
178 }
179 return ret;
180}
181
182/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800183 * em28xx_i2c_send_bytes()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800184 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800185static int em28xx_i2c_send_bytes(void *data, unsigned char addr, char *buf,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800186 short len, int stop)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800187{
188 int wrcount = 0;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800189 struct em28xx *dev = (struct em28xx *)data;
Mauro Carvalho Chehabbbc70e62011-07-09 19:36:11 -0300190 int write_timeout, ret;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800191
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800192 wrcount = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800193
Mauro Carvalho Chehabbbc70e62011-07-09 19:36:11 -0300194 /* Seems to be required after a write */
195 for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
196 write_timeout -= 5) {
197 ret = dev->em28xx_read_reg(dev, 0x05);
198 if (!ret)
199 break;
200 msleep(5);
201 }
202
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800203 return wrcount;
204}
205
206/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800207 * em28xx_i2c_recv_bytes()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800208 * read a byte from the i2c device
209 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800210static int em28xx_i2c_recv_bytes(struct em28xx *dev, unsigned char addr,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800211 char *buf, int len)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800212{
213 int ret;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800214 ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800215 if (ret < 0) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800216 em28xx_warn("reading i2c device failed (error=%i)\n", ret);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800217 return ret;
218 }
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800219 if (dev->em28xx_read_reg(dev, 0x5) != 0)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800220 return -ENODEV;
221 return ret;
222}
223
224/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800225 * em28xx_i2c_check_for_device()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800226 * check if there is a i2c_device at the supplied address
227 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800228static int em28xx_i2c_check_for_device(struct em28xx *dev, unsigned char addr)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800229{
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800230 int ret;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800231
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800232 ret = dev->em28xx_read_reg_req(dev, 2, addr);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800233 if (ret < 0) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800234 em28xx_warn("reading from i2c device failed (error=%i)\n", ret);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800235 return ret;
236 }
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800237 if (dev->em28xx_read_reg(dev, 0x5) != 0)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800238 return -ENODEV;
239 return 0;
240}
241
242/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800243 * em28xx_i2c_xfer()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800244 * the main i2c transfer function
245 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800246static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800247 struct i2c_msg msgs[], int num)
248{
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800249 struct em28xx *dev = i2c_adap->algo_data;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800250 int addr, rc, i, byte;
251
252 if (num <= 0)
253 return 0;
254 for (i = 0; i < num; i++) {
255 addr = msgs[i].addr << 1;
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300256 dprintk2(2, "%s %s addr=%x len=%d:",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800257 (msgs[i].flags & I2C_M_RD) ? "read" : "write",
258 i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300259 if (!msgs[i].len) { /* no len: check only for device presence */
Mauro Carvalho Chehab505b6d02008-11-25 09:39:50 -0300260 if (dev->board.is_em2800)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800261 rc = em2800_i2c_check_for_device(dev, addr);
262 else
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800263 rc = em28xx_i2c_check_for_device(dev, addr);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800264 if (rc < 0) {
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300265 dprintk2(2, " no device\n");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800266 return rc;
267 }
268
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800269 } else if (msgs[i].flags & I2C_M_RD) {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800270 /* read bytes */
Mauro Carvalho Chehab505b6d02008-11-25 09:39:50 -0300271 if (dev->board.is_em2800)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800272 rc = em2800_i2c_recv_bytes(dev, addr,
273 msgs[i].buf,
274 msgs[i].len);
275 else
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800276 rc = em28xx_i2c_recv_bytes(dev, addr,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800277 msgs[i].buf,
278 msgs[i].len);
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300279 if (i2c_debug >= 2) {
280 for (byte = 0; byte < msgs[i].len; byte++)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800281 printk(" %02x", msgs[i].buf[byte]);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800282 }
283 } else {
284 /* write bytes */
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300285 if (i2c_debug >= 2) {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800286 for (byte = 0; byte < msgs[i].len; byte++)
287 printk(" %02x", msgs[i].buf[byte]);
288 }
Mauro Carvalho Chehab505b6d02008-11-25 09:39:50 -0300289 if (dev->board.is_em2800)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800290 rc = em2800_i2c_send_bytes(dev, addr,
291 msgs[i].buf,
292 msgs[i].len);
293 else
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800294 rc = em28xx_i2c_send_bytes(dev, addr,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800295 msgs[i].buf,
296 msgs[i].len,
297 i == num - 1);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800298 }
Markus Rechbergere8e41da2006-02-07 06:49:11 -0200299 if (rc < 0)
300 goto err;
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300301 if (i2c_debug >= 2)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800302 printk("\n");
303 }
304
305 return num;
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300306err:
307 dprintk2(2, " ERROR: %i\n", rc);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800308 return rc;
309}
310
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -0300311/* based on linux/sunrpc/svcauth.h and linux/hash.h
312 * The original hash function returns a different value, if arch is x86_64
313 * or i386.
314 */
315static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits)
316{
317 unsigned long hash = 0;
318 unsigned long l = 0;
319 int len = 0;
320 unsigned char c;
321 do {
322 if (len == length) {
323 c = (char)len;
324 len = -1;
325 } else
326 c = *buf++;
327 l = (l << 8) | c;
328 len++;
329 if ((len & (32 / 8 - 1)) == 0)
330 hash = ((hash^l) * 0x9e370001UL);
331 } while (len);
332
333 return (hash >> (32 - bits)) & 0xffffffffUL;
334}
335
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800336static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800337{
338 unsigned char buf, *p = eedata;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800339 struct em28xx_eeprom *em_eeprom = (void *)eedata;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800340 int i, err, size = len, block;
341
Mauro Carvalho Chehabfec528b2011-07-03 21:05:06 -0300342 if (dev->chip_id == CHIP_ID_EM2874 ||
343 dev->chip_id == CHIP_ID_EM28174 ||
344 dev->chip_id == CHIP_ID_EM2884) {
Devin Heitmuellera527c9f2008-11-12 02:05:10 -0300345 /* Empia switched to a 16-bit addressable eeprom in newer
346 devices. While we could certainly write a routine to read
347 the eeprom, there is nothing of use in there that cannot be
348 accessed through registers, and there is the risk that we
349 could corrupt the eeprom (since a 16-bit read call is
350 interpreted as a write call by 8-bit eeproms).
351 */
352 return 0;
353 }
354
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800355 dev->i2c_client.addr = 0xa0 >> 1;
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800356
357 /* Check if board has eeprom */
358 err = i2c_master_recv(&dev->i2c_client, &buf, 0);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300359 if (err < 0) {
Mauro Carvalho Chehabc41109f2008-11-15 23:44:14 -0300360 em28xx_errdev("board has no eeprom\n");
361 memset(eedata, 0, len);
362 return -ENODEV;
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300363 }
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800364
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800365 buf = 0;
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300366
367 err = i2c_master_send(&dev->i2c_client, &buf, 1);
368 if (err != 1) {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800369 printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
370 dev->name, err);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300371 return err;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800372 }
373 while (size > 0) {
374 if (size > 16)
375 block = 16;
376 else
377 block = size;
378
379 if (block !=
380 (err = i2c_master_recv(&dev->i2c_client, p, block))) {
381 printk(KERN_WARNING
382 "%s: i2c eeprom read error (err=%d)\n",
383 dev->name, err);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300384 return err;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800385 }
386 size -= block;
387 p += block;
388 }
389 for (i = 0; i < len; i++) {
390 if (0 == (i % 16))
391 printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
392 printk(" %02x", eedata[i]);
393 if (15 == (i % 16))
394 printk("\n");
395 }
396
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -0300397 if (em_eeprom->id == 0x9567eb1a)
398 dev->hash = em28xx_hash_mem(eedata, len, 32);
399
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300400 printk(KERN_INFO "%s: EEPROM ID= 0x%08x, EEPROM hash = 0x%08lx\n",
401 dev->name, em_eeprom->id, dev->hash);
402
403 printk(KERN_INFO "%s: EEPROM info:\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800404
405 switch (em_eeprom->chip_conf >> 4 & 0x3) {
406 case 0:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300407 printk(KERN_INFO "%s:\tNo audio on board.\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800408 break;
409 case 1:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300410 printk(KERN_INFO "%s:\tAC97 audio (5 sample rates)\n",
411 dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800412 break;
413 case 2:
Nicola Soranzoa1a6ee72009-02-10 23:28:24 -0300414 printk(KERN_INFO "%s:\tI2S audio, sample rate=32k\n",
415 dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800416 break;
417 case 3:
Nicola Soranzoa1a6ee72009-02-10 23:28:24 -0300418 printk(KERN_INFO "%s:\tI2S audio, 3 sample rates\n",
419 dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800420 break;
421 }
422
423 if (em_eeprom->chip_conf & 1 << 3)
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300424 printk(KERN_INFO "%s:\tUSB Remote wakeup capable\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800425
426 if (em_eeprom->chip_conf & 1 << 2)
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300427 printk(KERN_INFO "%s:\tUSB Self power capable\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800428
429 switch (em_eeprom->chip_conf & 0x3) {
430 case 0:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300431 printk(KERN_INFO "%s:\t500mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800432 break;
433 case 1:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300434 printk(KERN_INFO "%s:\t400mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800435 break;
436 case 2:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300437 printk(KERN_INFO "%s:\t300mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800438 break;
439 case 3:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300440 printk(KERN_INFO "%s:\t200mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800441 break;
442 }
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300443 printk(KERN_INFO "%s:\tTable at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
444 dev->name,
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300445 em_eeprom->string_idx_table,
446 em_eeprom->string1,
447 em_eeprom->string2,
448 em_eeprom->string3);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800449
450 return 0;
451}
452
453/* ----------------------------------------------------------- */
454
455/*
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800456 * functionality()
457 */
458static u32 functionality(struct i2c_adapter *adap)
459{
460 return I2C_FUNC_SMBUS_EMUL;
461}
462
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800463static struct i2c_algorithm em28xx_algo = {
464 .master_xfer = em28xx_i2c_xfer,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800465 .functionality = functionality,
466};
467
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800468static struct i2c_adapter em28xx_adap_template = {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800469 .owner = THIS_MODULE,
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800470 .name = "em28xx",
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800471 .algo = &em28xx_algo,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800472};
473
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800474static struct i2c_client em28xx_client_template = {
475 .name = "em28xx internal",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800476};
477
478/* ----------------------------------------------------------- */
479
480/*
481 * i2c_devs
482 * incomplete list of known devices
483 */
484static char *i2c_devs[128] = {
485 [0x4a >> 1] = "saa7113h",
486 [0x60 >> 1] = "remote IR sensor",
Markus Rechbergerda45a2a2005-11-08 21:37:31 -0800487 [0x8e >> 1] = "remote IR sensor",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800488 [0x86 >> 1] = "tda9887",
489 [0x80 >> 1] = "msp34xx",
490 [0x88 >> 1] = "msp34xx",
491 [0xa0 >> 1] = "eeprom",
Vitaly Wool2bd1d9e2009-03-04 08:27:52 -0300492 [0xb0 >> 1] = "tda9874",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800493 [0xb8 >> 1] = "tvp5150a",
Mauro Carvalho Chehab791a08f2009-07-03 15:36:18 -0300494 [0xba >> 1] = "webcam sensor or tvp5150a",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800495 [0xc0 >> 1] = "tuner (analog)",
496 [0xc2 >> 1] = "tuner (analog)",
497 [0xc4 >> 1] = "tuner (analog)",
498 [0xc6 >> 1] = "tuner (analog)",
499};
500
501/*
502 * do_i2c_scan()
503 * check i2c address range for devices
504 */
Sascha Sommerfad7b952007-11-04 08:06:48 -0300505void em28xx_do_i2c_scan(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800506{
Sascha Sommerfad7b952007-11-04 08:06:48 -0300507 u8 i2c_devicelist[128];
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800508 unsigned char buf;
509 int i, rc;
510
Sascha Sommerfad7b952007-11-04 08:06:48 -0300511 memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist));
512
Mauro Carvalho Chehab53c4e952007-03-29 08:42:30 -0300513 for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
Sascha Sommerfad7b952007-11-04 08:06:48 -0300514 dev->i2c_client.addr = i;
515 rc = i2c_master_recv(&dev->i2c_client, &buf, 0);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800516 if (rc < 0)
517 continue;
Sascha Sommerfad7b952007-11-04 08:06:48 -0300518 i2c_devicelist[i] = i;
519 printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n",
520 dev->name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800521 }
Sascha Sommerfad7b952007-11-04 08:06:48 -0300522
523 dev->i2c_hash = em28xx_hash_mem(i2c_devicelist,
524 ARRAY_SIZE(i2c_devicelist), 32);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800525}
526
527/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800528 * em28xx_i2c_register()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800529 * register i2c bus
530 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800531int em28xx_i2c_register(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800532{
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300533 int retval;
534
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800535 BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg);
536 BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req);
537 dev->i2c_adap = em28xx_adap_template;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800538 dev->i2c_adap.dev.parent = &dev->udev->dev;
539 strcpy(dev->i2c_adap.name, dev->name);
540 dev->i2c_adap.algo_data = dev;
Douglas Schilling Landgraff2cf2502009-03-31 17:10:58 -0300541 i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300542
543 retval = i2c_add_adapter(&dev->i2c_adap);
544 if (retval < 0) {
545 em28xx_errdev("%s: i2c_add_adapter failed! retval [%d]\n",
546 __func__, retval);
547 return retval;
548 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800549
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800550 dev->i2c_client = em28xx_client_template;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800551 dev->i2c_client.adapter = &dev->i2c_adap;
552
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300553 retval = em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata));
Mauro Carvalho Chehabc41109f2008-11-15 23:44:14 -0300554 if ((retval < 0) && (retval != -ENODEV)) {
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300555 em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n",
556 __func__, retval);
Mauro Carvalho Chehabc41109f2008-11-15 23:44:14 -0300557
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300558 return retval;
559 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800560
561 if (i2c_scan)
Sascha Sommerfad7b952007-11-04 08:06:48 -0300562 em28xx_do_i2c_scan(dev);
Mauro Carvalho Chehabc41109f2008-11-15 23:44:14 -0300563
Jean Delvarec668f322009-05-13 16:48:50 -0300564 /* Instantiate the IR receiver device, if present */
565 em28xx_register_i2c_ir(dev);
566
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800567 return 0;
568}
569
570/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800571 * em28xx_i2c_unregister()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800572 * unregister i2c_bus
573 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800574int em28xx_i2c_unregister(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800575{
576 i2c_del_adapter(&dev->i2c_adap);
577 return 0;
578}