blob: 1683bd9d51eed67ecaef8832832bd1eafeaa1ca5 [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 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080056static int em2800_i2c_send_max4(struct em28xx *dev, unsigned char addr,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080057 char *buf, int len)
58{
59 int ret;
60 int write_timeout;
61 unsigned char b2[6];
62 BUG_ON(len < 1 || len > 4);
63 b2[5] = 0x80 + len - 1;
64 b2[4] = addr;
65 b2[3] = buf[0];
66 if (len > 1)
67 b2[2] = buf[1];
68 if (len > 2)
69 b2[1] = buf[2];
70 if (len > 3)
71 b2[0] = buf[3];
72
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080073 ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080074 if (ret != 2 + len) {
Robert P. J. Daybeb7dd82007-05-09 07:14:03 +020075 em28xx_warn("writing to i2c device failed (error=%i)\n", ret);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080076 return -EIO;
77 }
78 for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
79 write_timeout -= 5) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080080 ret = dev->em28xx_read_reg(dev, 0x05);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080081 if (ret == 0x80 + len - 1)
82 return len;
Markus Rechbergere8e41da2006-02-07 06:49:11 -020083 msleep(5);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080084 }
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080085 em28xx_warn("i2c write timed out\n");
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080086 return -EIO;
87}
88
89/*
90 * em2800_i2c_send_bytes()
91 */
92static int em2800_i2c_send_bytes(void *data, unsigned char addr, char *buf,
93 short len)
94{
95 char *bufPtr = buf;
96 int ret;
97 int wrcount = 0;
98 int count;
99 int maxLen = 4;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800100 struct em28xx *dev = (struct em28xx *)data;
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800101 while (len > 0) {
102 count = (len > maxLen) ? maxLen : len;
103 ret = em2800_i2c_send_max4(dev, addr, bufPtr, count);
104 if (ret > 0) {
105 len -= count;
106 bufPtr += count;
107 wrcount += count;
108 } else
109 return (ret < 0) ? ret : -EFAULT;
110 }
111 return wrcount;
112}
113
114/*
115 * em2800_i2c_check_for_device()
116 * check if there is a i2c_device at the supplied address
117 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800118static int em2800_i2c_check_for_device(struct em28xx *dev, unsigned char addr)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800119{
120 char msg;
121 int ret;
122 int write_timeout;
123 msg = addr;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800124 ret = dev->em28xx_write_regs(dev, 0x04, &msg, 1);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800125 if (ret < 0) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800126 em28xx_warn("setting i2c device address failed (error=%i)\n",
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800127 ret);
128 return ret;
129 }
130 msg = 0x84;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800131 ret = dev->em28xx_write_regs(dev, 0x05, &msg, 1);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800132 if (ret < 0) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800133 em28xx_warn("preparing i2c read failed (error=%i)\n", ret);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800134 return ret;
135 }
136 for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
137 write_timeout -= 5) {
Hans Verkuild45b9b82008-09-04 03:33:43 -0300138 unsigned reg = dev->em28xx_read_reg(dev, 0x5);
139
140 if (reg == 0x94)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800141 return -ENODEV;
Hans Verkuild45b9b82008-09-04 03:33:43 -0300142 else if (reg == 0x84)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800143 return 0;
Markus Rechbergere8e41da2006-02-07 06:49:11 -0200144 msleep(5);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800145 }
146 return -ENODEV;
147}
148
149/*
150 * em2800_i2c_recv_bytes()
151 * read from the i2c device
152 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800153static int em2800_i2c_recv_bytes(struct em28xx *dev, unsigned char addr,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800154 char *buf, int len)
155{
156 int ret;
157 /* check for the device and set i2c read address */
158 ret = em2800_i2c_check_for_device(dev, addr);
159 if (ret) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800160 em28xx_warn
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800161 ("preparing read at i2c address 0x%x failed (error=%i)\n",
162 addr, ret);
163 return ret;
164 }
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800165 ret = dev->em28xx_read_reg_req_len(dev, 0x0, 0x3, buf, len);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800166 if (ret < 0) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800167 em28xx_warn("reading from i2c device at 0x%x failed (error=%i)",
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800168 addr, ret);
169 return ret;
170 }
171 return ret;
172}
173
174/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800175 * em28xx_i2c_send_bytes()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800176 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800177static int em28xx_i2c_send_bytes(void *data, unsigned char addr, char *buf,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800178 short len, int stop)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800179{
180 int wrcount = 0;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800181 struct em28xx *dev = (struct em28xx *)data;
Mauro Carvalho Chehabbbc70e62011-07-09 19:36:11 -0300182 int write_timeout, ret;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800183
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800184 wrcount = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800185
Mauro Carvalho Chehabbbc70e62011-07-09 19:36:11 -0300186 /* Seems to be required after a write */
187 for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
188 write_timeout -= 5) {
189 ret = dev->em28xx_read_reg(dev, 0x05);
190 if (!ret)
191 break;
192 msleep(5);
193 }
194
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800195 return wrcount;
196}
197
198/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800199 * em28xx_i2c_recv_bytes()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800200 * read a byte from the i2c device
201 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800202static int em28xx_i2c_recv_bytes(struct em28xx *dev, unsigned char addr,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800203 char *buf, int len)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800204{
205 int ret;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800206 ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800207 if (ret < 0) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800208 em28xx_warn("reading i2c device failed (error=%i)\n", ret);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800209 return ret;
210 }
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800211 if (dev->em28xx_read_reg(dev, 0x5) != 0)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800212 return -ENODEV;
213 return ret;
214}
215
216/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800217 * em28xx_i2c_check_for_device()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800218 * check if there is a i2c_device at the supplied address
219 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800220static int em28xx_i2c_check_for_device(struct em28xx *dev, unsigned char addr)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800221{
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800222 int ret;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800223
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800224 ret = dev->em28xx_read_reg_req(dev, 2, addr);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800225 if (ret < 0) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800226 em28xx_warn("reading from i2c device failed (error=%i)\n", ret);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800227 return ret;
228 }
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800229 if (dev->em28xx_read_reg(dev, 0x5) != 0)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800230 return -ENODEV;
231 return 0;
232}
233
234/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800235 * em28xx_i2c_xfer()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800236 * the main i2c transfer function
237 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800238static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800239 struct i2c_msg msgs[], int num)
240{
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800241 struct em28xx *dev = i2c_adap->algo_data;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800242 int addr, rc, i, byte;
243
244 if (num <= 0)
245 return 0;
246 for (i = 0; i < num; i++) {
247 addr = msgs[i].addr << 1;
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300248 dprintk2(2, "%s %s addr=%x len=%d:",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800249 (msgs[i].flags & I2C_M_RD) ? "read" : "write",
250 i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300251 if (!msgs[i].len) { /* no len: check only for device presence */
Mauro Carvalho Chehab505b6d02008-11-25 09:39:50 -0300252 if (dev->board.is_em2800)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800253 rc = em2800_i2c_check_for_device(dev, addr);
254 else
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800255 rc = em28xx_i2c_check_for_device(dev, addr);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800256 if (rc < 0) {
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300257 dprintk2(2, " no device\n");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800258 return rc;
259 }
260
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800261 } else if (msgs[i].flags & I2C_M_RD) {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800262 /* read bytes */
Mauro Carvalho Chehab505b6d02008-11-25 09:39:50 -0300263 if (dev->board.is_em2800)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800264 rc = em2800_i2c_recv_bytes(dev, addr,
265 msgs[i].buf,
266 msgs[i].len);
267 else
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800268 rc = em28xx_i2c_recv_bytes(dev, addr,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800269 msgs[i].buf,
270 msgs[i].len);
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300271 if (i2c_debug >= 2) {
272 for (byte = 0; byte < msgs[i].len; byte++)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800273 printk(" %02x", msgs[i].buf[byte]);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800274 }
275 } else {
276 /* write bytes */
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300277 if (i2c_debug >= 2) {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800278 for (byte = 0; byte < msgs[i].len; byte++)
279 printk(" %02x", msgs[i].buf[byte]);
280 }
Mauro Carvalho Chehab505b6d02008-11-25 09:39:50 -0300281 if (dev->board.is_em2800)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800282 rc = em2800_i2c_send_bytes(dev, addr,
283 msgs[i].buf,
284 msgs[i].len);
285 else
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800286 rc = em28xx_i2c_send_bytes(dev, addr,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800287 msgs[i].buf,
288 msgs[i].len,
289 i == num - 1);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800290 }
Markus Rechbergere8e41da2006-02-07 06:49:11 -0200291 if (rc < 0)
292 goto err;
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300293 if (i2c_debug >= 2)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800294 printk("\n");
295 }
296
297 return num;
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300298err:
299 dprintk2(2, " ERROR: %i\n", rc);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800300 return rc;
301}
302
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -0300303/* based on linux/sunrpc/svcauth.h and linux/hash.h
304 * The original hash function returns a different value, if arch is x86_64
305 * or i386.
306 */
307static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits)
308{
309 unsigned long hash = 0;
310 unsigned long l = 0;
311 int len = 0;
312 unsigned char c;
313 do {
314 if (len == length) {
315 c = (char)len;
316 len = -1;
317 } else
318 c = *buf++;
319 l = (l << 8) | c;
320 len++;
321 if ((len & (32 / 8 - 1)) == 0)
322 hash = ((hash^l) * 0x9e370001UL);
323 } while (len);
324
325 return (hash >> (32 - bits)) & 0xffffffffUL;
326}
327
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800328static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800329{
330 unsigned char buf, *p = eedata;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800331 struct em28xx_eeprom *em_eeprom = (void *)eedata;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800332 int i, err, size = len, block;
333
Mauro Carvalho Chehabfec528b2011-07-03 21:05:06 -0300334 if (dev->chip_id == CHIP_ID_EM2874 ||
335 dev->chip_id == CHIP_ID_EM28174 ||
336 dev->chip_id == CHIP_ID_EM2884) {
Devin Heitmuellera527c9f2008-11-12 02:05:10 -0300337 /* Empia switched to a 16-bit addressable eeprom in newer
338 devices. While we could certainly write a routine to read
339 the eeprom, there is nothing of use in there that cannot be
340 accessed through registers, and there is the risk that we
341 could corrupt the eeprom (since a 16-bit read call is
342 interpreted as a write call by 8-bit eeproms).
343 */
344 return 0;
345 }
346
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800347 dev->i2c_client.addr = 0xa0 >> 1;
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800348
349 /* Check if board has eeprom */
350 err = i2c_master_recv(&dev->i2c_client, &buf, 0);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300351 if (err < 0) {
Mauro Carvalho Chehabc41109f2008-11-15 23:44:14 -0300352 em28xx_errdev("board has no eeprom\n");
353 memset(eedata, 0, len);
354 return -ENODEV;
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300355 }
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800356
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800357 buf = 0;
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300358
359 err = i2c_master_send(&dev->i2c_client, &buf, 1);
360 if (err != 1) {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800361 printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
362 dev->name, err);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300363 return err;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800364 }
365 while (size > 0) {
366 if (size > 16)
367 block = 16;
368 else
369 block = size;
370
371 if (block !=
372 (err = i2c_master_recv(&dev->i2c_client, p, block))) {
373 printk(KERN_WARNING
374 "%s: i2c eeprom read error (err=%d)\n",
375 dev->name, err);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300376 return err;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800377 }
378 size -= block;
379 p += block;
380 }
381 for (i = 0; i < len; i++) {
382 if (0 == (i % 16))
383 printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
384 printk(" %02x", eedata[i]);
385 if (15 == (i % 16))
386 printk("\n");
387 }
388
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -0300389 if (em_eeprom->id == 0x9567eb1a)
390 dev->hash = em28xx_hash_mem(eedata, len, 32);
391
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300392 printk(KERN_INFO "%s: EEPROM ID= 0x%08x, EEPROM hash = 0x%08lx\n",
393 dev->name, em_eeprom->id, dev->hash);
394
395 printk(KERN_INFO "%s: EEPROM info:\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800396
397 switch (em_eeprom->chip_conf >> 4 & 0x3) {
398 case 0:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300399 printk(KERN_INFO "%s:\tNo audio on board.\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800400 break;
401 case 1:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300402 printk(KERN_INFO "%s:\tAC97 audio (5 sample rates)\n",
403 dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800404 break;
405 case 2:
Nicola Soranzoa1a6ee72009-02-10 23:28:24 -0300406 printk(KERN_INFO "%s:\tI2S audio, sample rate=32k\n",
407 dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800408 break;
409 case 3:
Nicola Soranzoa1a6ee72009-02-10 23:28:24 -0300410 printk(KERN_INFO "%s:\tI2S audio, 3 sample rates\n",
411 dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800412 break;
413 }
414
415 if (em_eeprom->chip_conf & 1 << 3)
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300416 printk(KERN_INFO "%s:\tUSB Remote wakeup capable\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800417
418 if (em_eeprom->chip_conf & 1 << 2)
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300419 printk(KERN_INFO "%s:\tUSB Self power capable\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800420
421 switch (em_eeprom->chip_conf & 0x3) {
422 case 0:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300423 printk(KERN_INFO "%s:\t500mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800424 break;
425 case 1:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300426 printk(KERN_INFO "%s:\t400mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800427 break;
428 case 2:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300429 printk(KERN_INFO "%s:\t300mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800430 break;
431 case 3:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300432 printk(KERN_INFO "%s:\t200mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800433 break;
434 }
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300435 printk(KERN_INFO "%s:\tTable at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
436 dev->name,
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300437 em_eeprom->string_idx_table,
438 em_eeprom->string1,
439 em_eeprom->string2,
440 em_eeprom->string3);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800441
442 return 0;
443}
444
445/* ----------------------------------------------------------- */
446
447/*
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800448 * functionality()
449 */
450static u32 functionality(struct i2c_adapter *adap)
451{
452 return I2C_FUNC_SMBUS_EMUL;
453}
454
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800455static struct i2c_algorithm em28xx_algo = {
456 .master_xfer = em28xx_i2c_xfer,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800457 .functionality = functionality,
458};
459
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800460static struct i2c_adapter em28xx_adap_template = {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800461 .owner = THIS_MODULE,
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800462 .name = "em28xx",
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800463 .algo = &em28xx_algo,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800464};
465
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800466static struct i2c_client em28xx_client_template = {
467 .name = "em28xx internal",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800468};
469
470/* ----------------------------------------------------------- */
471
472/*
473 * i2c_devs
474 * incomplete list of known devices
475 */
476static char *i2c_devs[128] = {
477 [0x4a >> 1] = "saa7113h",
Martin Blumenstingl729841e2012-06-12 18:19:27 -0300478 [0x52 >> 1] = "drxk",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800479 [0x60 >> 1] = "remote IR sensor",
Markus Rechbergerda45a2a2005-11-08 21:37:31 -0800480 [0x8e >> 1] = "remote IR sensor",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800481 [0x86 >> 1] = "tda9887",
482 [0x80 >> 1] = "msp34xx",
483 [0x88 >> 1] = "msp34xx",
484 [0xa0 >> 1] = "eeprom",
Vitaly Wool2bd1d9eb2009-03-04 08:27:52 -0300485 [0xb0 >> 1] = "tda9874",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800486 [0xb8 >> 1] = "tvp5150a",
Mauro Carvalho Chehab791a08f2009-07-03 15:36:18 -0300487 [0xba >> 1] = "webcam sensor or tvp5150a",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800488 [0xc0 >> 1] = "tuner (analog)",
489 [0xc2 >> 1] = "tuner (analog)",
490 [0xc4 >> 1] = "tuner (analog)",
491 [0xc6 >> 1] = "tuner (analog)",
492};
493
494/*
495 * do_i2c_scan()
496 * check i2c address range for devices
497 */
Sascha Sommerfad7b952007-11-04 08:06:48 -0300498void em28xx_do_i2c_scan(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800499{
Sascha Sommerfad7b952007-11-04 08:06:48 -0300500 u8 i2c_devicelist[128];
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800501 unsigned char buf;
502 int i, rc;
503
Sascha Sommerfad7b952007-11-04 08:06:48 -0300504 memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist));
505
Mauro Carvalho Chehab53c4e952007-03-29 08:42:30 -0300506 for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
Sascha Sommerfad7b952007-11-04 08:06:48 -0300507 dev->i2c_client.addr = i;
508 rc = i2c_master_recv(&dev->i2c_client, &buf, 0);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800509 if (rc < 0)
510 continue;
Sascha Sommerfad7b952007-11-04 08:06:48 -0300511 i2c_devicelist[i] = i;
512 printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n",
513 dev->name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800514 }
Sascha Sommerfad7b952007-11-04 08:06:48 -0300515
516 dev->i2c_hash = em28xx_hash_mem(i2c_devicelist,
517 ARRAY_SIZE(i2c_devicelist), 32);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800518}
519
520/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800521 * em28xx_i2c_register()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800522 * register i2c bus
523 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800524int em28xx_i2c_register(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800525{
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300526 int retval;
527
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800528 BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg);
529 BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req);
530 dev->i2c_adap = em28xx_adap_template;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800531 dev->i2c_adap.dev.parent = &dev->udev->dev;
532 strcpy(dev->i2c_adap.name, dev->name);
533 dev->i2c_adap.algo_data = dev;
Douglas Schilling Landgraff2cf2502009-03-31 17:10:58 -0300534 i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300535
536 retval = i2c_add_adapter(&dev->i2c_adap);
537 if (retval < 0) {
538 em28xx_errdev("%s: i2c_add_adapter failed! retval [%d]\n",
539 __func__, retval);
540 return retval;
541 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800542
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800543 dev->i2c_client = em28xx_client_template;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800544 dev->i2c_client.adapter = &dev->i2c_adap;
545
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300546 retval = em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata));
Mauro Carvalho Chehabc41109f2008-11-15 23:44:14 -0300547 if ((retval < 0) && (retval != -ENODEV)) {
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300548 em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n",
549 __func__, retval);
Mauro Carvalho Chehabc41109f2008-11-15 23:44:14 -0300550
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300551 return retval;
552 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800553
554 if (i2c_scan)
Sascha Sommerfad7b952007-11-04 08:06:48 -0300555 em28xx_do_i2c_scan(dev);
Mauro Carvalho Chehabc41109f2008-11-15 23:44:14 -0300556
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800557 return 0;
558}
559
560/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800561 * em28xx_i2c_unregister()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800562 * unregister i2c_bus
563 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800564int em28xx_i2c_unregister(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800565{
566 i2c_del_adapter(&dev->i2c_adap);
567 return 0;
568}