blob: c508c1297a26a0745cae07c2eb1b27aa27f01e2a [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/*
Frank Schaeferf5ae3712013-01-03 14:27:02 -030053 * em2800_i2c_send_bytes()
54 * send up to 4 bytes to the em2800 i2c device
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080055 */
Frank Schaeferf5ae3712013-01-03 14:27:02 -030056static int em2800_i2c_send_bytes(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];
Frank Schaeferf5ae3712013-01-03 14:27:02 -030061
62 if (len < 1 || len > 4)
63 return -EOPNOTSUPP;
64
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080065 BUG_ON(len < 1 || len > 4);
66 b2[5] = 0x80 + len - 1;
67 b2[4] = addr;
68 b2[3] = buf[0];
69 if (len > 1)
70 b2[2] = buf[1];
71 if (len > 2)
72 b2[1] = buf[2];
73 if (len > 3)
74 b2[0] = buf[3];
75
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080076 ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080077 if (ret != 2 + len) {
Robert P. J. Daybeb7dd82007-05-09 07:14:03 +020078 em28xx_warn("writing to i2c device failed (error=%i)\n", ret);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080079 return -EIO;
80 }
81 for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
82 write_timeout -= 5) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080083 ret = dev->em28xx_read_reg(dev, 0x05);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080084 if (ret == 0x80 + len - 1)
85 return len;
Markus Rechbergere8e41da2006-02-07 06:49:11 -020086 msleep(5);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080087 }
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080088 em28xx_warn("i2c write timed out\n");
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080089 return -EIO;
90}
91
92/*
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080093 * em2800_i2c_check_for_device()
94 * check if there is a i2c_device at the supplied address
95 */
Frank Schaefera6bad042012-12-16 14:23:27 -030096static int em2800_i2c_check_for_device(struct em28xx *dev, u8 addr)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080097{
Frank Schaefera6bad042012-12-16 14:23:27 -030098 u8 msg;
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080099 int ret;
100 int write_timeout;
101 msg = addr;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800102 ret = dev->em28xx_write_regs(dev, 0x04, &msg, 1);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800103 if (ret < 0) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800104 em28xx_warn("setting i2c device address failed (error=%i)\n",
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800105 ret);
106 return ret;
107 }
108 msg = 0x84;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800109 ret = dev->em28xx_write_regs(dev, 0x05, &msg, 1);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800110 if (ret < 0) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800111 em28xx_warn("preparing i2c read failed (error=%i)\n", ret);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800112 return ret;
113 }
114 for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
115 write_timeout -= 5) {
Hans Verkuild45b9b82008-09-04 03:33:43 -0300116 unsigned reg = dev->em28xx_read_reg(dev, 0x5);
117
118 if (reg == 0x94)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800119 return -ENODEV;
Hans Verkuild45b9b82008-09-04 03:33:43 -0300120 else if (reg == 0x84)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800121 return 0;
Markus Rechbergere8e41da2006-02-07 06:49:11 -0200122 msleep(5);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800123 }
124 return -ENODEV;
125}
126
127/*
128 * em2800_i2c_recv_bytes()
129 * read from the i2c device
130 */
Frank Schaefera6bad042012-12-16 14:23:27 -0300131static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800132{
133 int ret;
Frank Schaeferf5ae3712013-01-03 14:27:02 -0300134
135 if (len < 1 || len > 4)
136 return -EOPNOTSUPP;
137
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800138 /* check for the device and set i2c read address */
139 ret = em2800_i2c_check_for_device(dev, addr);
140 if (ret) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800141 em28xx_warn
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800142 ("preparing read at i2c address 0x%x failed (error=%i)\n",
143 addr, ret);
144 return ret;
145 }
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800146 ret = dev->em28xx_read_reg_req_len(dev, 0x0, 0x3, buf, len);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800147 if (ret < 0) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800148 em28xx_warn("reading from i2c device at 0x%x failed (error=%i)",
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800149 addr, ret);
150 return ret;
151 }
152 return ret;
153}
154
155/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800156 * em28xx_i2c_send_bytes()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800157 */
Frank Schaefera6bad042012-12-16 14:23:27 -0300158static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
159 u16 len, int stop)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800160{
161 int wrcount = 0;
Mauro Carvalho Chehabbbc70e62011-07-09 19:36:11 -0300162 int write_timeout, ret;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800163
Frank Schaeferf5ae3712013-01-03 14:27:02 -0300164 if (len < 1 || len > 64)
165 return -EOPNOTSUPP;
166
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800167 wrcount = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800168
Mauro Carvalho Chehabbbc70e62011-07-09 19:36:11 -0300169 /* Seems to be required after a write */
170 for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
171 write_timeout -= 5) {
172 ret = dev->em28xx_read_reg(dev, 0x05);
173 if (!ret)
174 break;
175 msleep(5);
176 }
177
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800178 return wrcount;
179}
180
181/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800182 * em28xx_i2c_recv_bytes()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800183 * read a byte from the i2c device
184 */
Frank Schaefera6bad042012-12-16 14:23:27 -0300185static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800186{
187 int ret;
Frank Schaeferf5ae3712013-01-03 14:27:02 -0300188
189 if (len < 1 || len > 64)
190 return -EOPNOTSUPP;
191
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800192 ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800193 if (ret < 0) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800194 em28xx_warn("reading i2c device failed (error=%i)\n", ret);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800195 return ret;
196 }
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800197 if (dev->em28xx_read_reg(dev, 0x5) != 0)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800198 return -ENODEV;
199 return ret;
200}
201
202/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800203 * em28xx_i2c_check_for_device()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800204 * check if there is a i2c_device at the supplied address
205 */
Frank Schaefera6bad042012-12-16 14:23:27 -0300206static int em28xx_i2c_check_for_device(struct em28xx *dev, u16 addr)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800207{
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800208 int ret;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800209
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800210 ret = dev->em28xx_read_reg_req(dev, 2, addr);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800211 if (ret < 0) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800212 em28xx_warn("reading from i2c device failed (error=%i)\n", ret);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800213 return ret;
214 }
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800215 if (dev->em28xx_read_reg(dev, 0x5) != 0)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800216 return -ENODEV;
217 return 0;
218}
219
220/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800221 * em28xx_i2c_xfer()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800222 * the main i2c transfer function
223 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800224static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800225 struct i2c_msg msgs[], int num)
226{
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800227 struct em28xx *dev = i2c_adap->algo_data;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800228 int addr, rc, i, byte;
229
230 if (num <= 0)
231 return 0;
232 for (i = 0; i < num; i++) {
233 addr = msgs[i].addr << 1;
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300234 dprintk2(2, "%s %s addr=%x len=%d:",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800235 (msgs[i].flags & I2C_M_RD) ? "read" : "write",
236 i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300237 if (!msgs[i].len) { /* no len: check only for device presence */
Mauro Carvalho Chehab505b6d02008-11-25 09:39:50 -0300238 if (dev->board.is_em2800)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800239 rc = em2800_i2c_check_for_device(dev, addr);
240 else
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800241 rc = em28xx_i2c_check_for_device(dev, addr);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800242 if (rc < 0) {
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300243 dprintk2(2, " no device\n");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800244 return rc;
245 }
246
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800247 } else if (msgs[i].flags & I2C_M_RD) {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800248 /* read bytes */
Mauro Carvalho Chehab505b6d02008-11-25 09:39:50 -0300249 if (dev->board.is_em2800)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800250 rc = em2800_i2c_recv_bytes(dev, addr,
251 msgs[i].buf,
252 msgs[i].len);
253 else
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800254 rc = em28xx_i2c_recv_bytes(dev, addr,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800255 msgs[i].buf,
256 msgs[i].len);
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300257 if (i2c_debug >= 2) {
258 for (byte = 0; byte < msgs[i].len; byte++)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800259 printk(" %02x", msgs[i].buf[byte]);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800260 }
261 } else {
262 /* write bytes */
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300263 if (i2c_debug >= 2) {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800264 for (byte = 0; byte < msgs[i].len; byte++)
265 printk(" %02x", msgs[i].buf[byte]);
266 }
Mauro Carvalho Chehab505b6d02008-11-25 09:39:50 -0300267 if (dev->board.is_em2800)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800268 rc = em2800_i2c_send_bytes(dev, addr,
269 msgs[i].buf,
270 msgs[i].len);
271 else
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800272 rc = em28xx_i2c_send_bytes(dev, addr,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800273 msgs[i].buf,
274 msgs[i].len,
275 i == num - 1);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800276 }
Markus Rechbergere8e41da2006-02-07 06:49:11 -0200277 if (rc < 0)
278 goto err;
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300279 if (i2c_debug >= 2)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800280 printk("\n");
281 }
282
283 return num;
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300284err:
285 dprintk2(2, " ERROR: %i\n", rc);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800286 return rc;
287}
288
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -0300289/* based on linux/sunrpc/svcauth.h and linux/hash.h
290 * The original hash function returns a different value, if arch is x86_64
291 * or i386.
292 */
293static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits)
294{
295 unsigned long hash = 0;
296 unsigned long l = 0;
297 int len = 0;
298 unsigned char c;
299 do {
300 if (len == length) {
301 c = (char)len;
302 len = -1;
303 } else
304 c = *buf++;
305 l = (l << 8) | c;
306 len++;
307 if ((len & (32 / 8 - 1)) == 0)
308 hash = ((hash^l) * 0x9e370001UL);
309 } while (len);
310
311 return (hash >> (32 - bits)) & 0xffffffffUL;
312}
313
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800314static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800315{
316 unsigned char buf, *p = eedata;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800317 struct em28xx_eeprom *em_eeprom = (void *)eedata;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800318 int i, err, size = len, block;
319
Mauro Carvalho Chehabfec528b2011-07-03 21:05:06 -0300320 if (dev->chip_id == CHIP_ID_EM2874 ||
321 dev->chip_id == CHIP_ID_EM28174 ||
322 dev->chip_id == CHIP_ID_EM2884) {
Devin Heitmuellera527c9f2008-11-12 02:05:10 -0300323 /* Empia switched to a 16-bit addressable eeprom in newer
324 devices. While we could certainly write a routine to read
325 the eeprom, there is nothing of use in there that cannot be
326 accessed through registers, and there is the risk that we
327 could corrupt the eeprom (since a 16-bit read call is
328 interpreted as a write call by 8-bit eeproms).
329 */
330 return 0;
331 }
332
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800333 dev->i2c_client.addr = 0xa0 >> 1;
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800334
335 /* Check if board has eeprom */
336 err = i2c_master_recv(&dev->i2c_client, &buf, 0);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300337 if (err < 0) {
Mauro Carvalho Chehabc41109f2008-11-15 23:44:14 -0300338 em28xx_errdev("board has no eeprom\n");
339 memset(eedata, 0, len);
340 return -ENODEV;
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300341 }
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800342
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800343 buf = 0;
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300344
345 err = i2c_master_send(&dev->i2c_client, &buf, 1);
346 if (err != 1) {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800347 printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
348 dev->name, err);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300349 return err;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800350 }
351 while (size > 0) {
352 if (size > 16)
353 block = 16;
354 else
355 block = size;
356
357 if (block !=
358 (err = i2c_master_recv(&dev->i2c_client, p, block))) {
359 printk(KERN_WARNING
360 "%s: i2c eeprom read error (err=%d)\n",
361 dev->name, err);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300362 return err;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800363 }
364 size -= block;
365 p += block;
366 }
367 for (i = 0; i < len; i++) {
368 if (0 == (i % 16))
369 printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
370 printk(" %02x", eedata[i]);
371 if (15 == (i % 16))
372 printk("\n");
373 }
374
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -0300375 if (em_eeprom->id == 0x9567eb1a)
376 dev->hash = em28xx_hash_mem(eedata, len, 32);
377
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300378 printk(KERN_INFO "%s: EEPROM ID= 0x%08x, EEPROM hash = 0x%08lx\n",
379 dev->name, em_eeprom->id, dev->hash);
380
381 printk(KERN_INFO "%s: EEPROM info:\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800382
383 switch (em_eeprom->chip_conf >> 4 & 0x3) {
384 case 0:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300385 printk(KERN_INFO "%s:\tNo audio on board.\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800386 break;
387 case 1:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300388 printk(KERN_INFO "%s:\tAC97 audio (5 sample rates)\n",
389 dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800390 break;
391 case 2:
Nicola Soranzoa1a6ee72009-02-10 23:28:24 -0300392 printk(KERN_INFO "%s:\tI2S audio, sample rate=32k\n",
393 dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800394 break;
395 case 3:
Nicola Soranzoa1a6ee72009-02-10 23:28:24 -0300396 printk(KERN_INFO "%s:\tI2S audio, 3 sample rates\n",
397 dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800398 break;
399 }
400
401 if (em_eeprom->chip_conf & 1 << 3)
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300402 printk(KERN_INFO "%s:\tUSB Remote wakeup capable\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800403
404 if (em_eeprom->chip_conf & 1 << 2)
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300405 printk(KERN_INFO "%s:\tUSB Self power capable\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800406
407 switch (em_eeprom->chip_conf & 0x3) {
408 case 0:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300409 printk(KERN_INFO "%s:\t500mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800410 break;
411 case 1:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300412 printk(KERN_INFO "%s:\t400mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800413 break;
414 case 2:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300415 printk(KERN_INFO "%s:\t300mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800416 break;
417 case 3:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300418 printk(KERN_INFO "%s:\t200mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800419 break;
420 }
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300421 printk(KERN_INFO "%s:\tTable at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
422 dev->name,
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300423 em_eeprom->string_idx_table,
424 em_eeprom->string1,
425 em_eeprom->string2,
426 em_eeprom->string3);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800427
428 return 0;
429}
430
431/* ----------------------------------------------------------- */
432
433/*
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800434 * functionality()
435 */
436static u32 functionality(struct i2c_adapter *adap)
437{
438 return I2C_FUNC_SMBUS_EMUL;
439}
440
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800441static struct i2c_algorithm em28xx_algo = {
442 .master_xfer = em28xx_i2c_xfer,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800443 .functionality = functionality,
444};
445
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800446static struct i2c_adapter em28xx_adap_template = {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800447 .owner = THIS_MODULE,
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800448 .name = "em28xx",
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800449 .algo = &em28xx_algo,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800450};
451
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800452static struct i2c_client em28xx_client_template = {
453 .name = "em28xx internal",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800454};
455
456/* ----------------------------------------------------------- */
457
458/*
459 * i2c_devs
460 * incomplete list of known devices
461 */
462static char *i2c_devs[128] = {
463 [0x4a >> 1] = "saa7113h",
Martin Blumenstingl729841e2012-06-12 18:19:27 -0300464 [0x52 >> 1] = "drxk",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800465 [0x60 >> 1] = "remote IR sensor",
Markus Rechbergerda45a2a2005-11-08 21:37:31 -0800466 [0x8e >> 1] = "remote IR sensor",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800467 [0x86 >> 1] = "tda9887",
468 [0x80 >> 1] = "msp34xx",
469 [0x88 >> 1] = "msp34xx",
470 [0xa0 >> 1] = "eeprom",
Vitaly Wool2bd1d9eb2009-03-04 08:27:52 -0300471 [0xb0 >> 1] = "tda9874",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800472 [0xb8 >> 1] = "tvp5150a",
Mauro Carvalho Chehab791a08f2009-07-03 15:36:18 -0300473 [0xba >> 1] = "webcam sensor or tvp5150a",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800474 [0xc0 >> 1] = "tuner (analog)",
475 [0xc2 >> 1] = "tuner (analog)",
476 [0xc4 >> 1] = "tuner (analog)",
477 [0xc6 >> 1] = "tuner (analog)",
478};
479
480/*
481 * do_i2c_scan()
482 * check i2c address range for devices
483 */
Sascha Sommerfad7b952007-11-04 08:06:48 -0300484void em28xx_do_i2c_scan(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800485{
Sascha Sommerfad7b952007-11-04 08:06:48 -0300486 u8 i2c_devicelist[128];
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800487 unsigned char buf;
488 int i, rc;
489
Sascha Sommerfad7b952007-11-04 08:06:48 -0300490 memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist));
491
Mauro Carvalho Chehab53c4e952007-03-29 08:42:30 -0300492 for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
Sascha Sommerfad7b952007-11-04 08:06:48 -0300493 dev->i2c_client.addr = i;
494 rc = i2c_master_recv(&dev->i2c_client, &buf, 0);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800495 if (rc < 0)
496 continue;
Sascha Sommerfad7b952007-11-04 08:06:48 -0300497 i2c_devicelist[i] = i;
498 printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n",
499 dev->name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800500 }
Sascha Sommerfad7b952007-11-04 08:06:48 -0300501
502 dev->i2c_hash = em28xx_hash_mem(i2c_devicelist,
503 ARRAY_SIZE(i2c_devicelist), 32);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800504}
505
506/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800507 * em28xx_i2c_register()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800508 * register i2c bus
509 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800510int em28xx_i2c_register(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800511{
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300512 int retval;
513
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800514 BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg);
515 BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req);
516 dev->i2c_adap = em28xx_adap_template;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800517 dev->i2c_adap.dev.parent = &dev->udev->dev;
518 strcpy(dev->i2c_adap.name, dev->name);
519 dev->i2c_adap.algo_data = dev;
Douglas Schilling Landgraff2cf2502009-03-31 17:10:58 -0300520 i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300521
522 retval = i2c_add_adapter(&dev->i2c_adap);
523 if (retval < 0) {
524 em28xx_errdev("%s: i2c_add_adapter failed! retval [%d]\n",
525 __func__, retval);
526 return retval;
527 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800528
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800529 dev->i2c_client = em28xx_client_template;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800530 dev->i2c_client.adapter = &dev->i2c_adap;
531
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300532 retval = em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata));
Mauro Carvalho Chehabc41109f2008-11-15 23:44:14 -0300533 if ((retval < 0) && (retval != -ENODEV)) {
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300534 em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n",
535 __func__, retval);
Mauro Carvalho Chehabc41109f2008-11-15 23:44:14 -0300536
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300537 return retval;
538 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800539
540 if (i2c_scan)
Sascha Sommerfad7b952007-11-04 08:06:48 -0300541 em28xx_do_i2c_scan(dev);
Mauro Carvalho Chehabc41109f2008-11-15 23:44:14 -0300542
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800543 return 0;
544}
545
546/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800547 * em28xx_i2c_unregister()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800548 * unregister i2c_bus
549 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800550int em28xx_i2c_unregister(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800551{
552 i2c_del_adapter(&dev->i2c_adap);
553 return 0;
554}