blob: 4a24ed08e46a191030c487f7a645fc46786e890f [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
Frank Schaefer2fcc82d2013-01-03 14:27:03 -030076 /* trigger write */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080077 ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080078 if (ret != 2 + len) {
Robert P. J. Daybeb7dd82007-05-09 07:14:03 +020079 em28xx_warn("writing to i2c device failed (error=%i)\n", ret);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080080 return -EIO;
81 }
Frank Schaefer2fcc82d2013-01-03 14:27:03 -030082 /* wait for completion */
83 for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0;
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080084 write_timeout -= 5) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080085 ret = dev->em28xx_read_reg(dev, 0x05);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080086 if (ret == 0x80 + len - 1)
87 return len;
Markus Rechbergere8e41da2006-02-07 06:49:11 -020088 msleep(5);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080089 }
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080090 em28xx_warn("i2c write timed out\n");
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080091 return -EIO;
92}
93
94/*
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080095 * em2800_i2c_recv_bytes()
Frank Schaefer2fcc82d2013-01-03 14:27:03 -030096 * read up to 4 bytes from the em2800 i2c device
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080097 */
Frank Schaefera6bad042012-12-16 14:23:27 -030098static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080099{
Frank Schaefer2fcc82d2013-01-03 14:27:03 -0300100 u8 buf2[4];
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800101 int ret;
Frank Schaefer2fcc82d2013-01-03 14:27:03 -0300102 int read_timeout;
103 int i;
Frank Schaeferf5ae3712013-01-03 14:27:02 -0300104
105 if (len < 1 || len > 4)
106 return -EOPNOTSUPP;
107
Frank Schaefer2fcc82d2013-01-03 14:27:03 -0300108 /* trigger read */
109 buf2[1] = 0x84 + len - 1;
110 buf2[0] = addr;
111 ret = dev->em28xx_write_regs(dev, 0x04, buf2, 2);
112 if (ret != 2) {
113 em28xx_warn("failed to trigger read from i2c address 0x%x "
114 "(error=%i)\n", addr, ret);
115 return (ret < 0) ? ret : -EIO;
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800116 }
Frank Schaefer2fcc82d2013-01-03 14:27:03 -0300117
118 /* wait for completion */
119 for (read_timeout = EM2800_I2C_XFER_TIMEOUT; read_timeout > 0;
120 read_timeout -= 5) {
121 ret = dev->em28xx_read_reg(dev, 0x05);
122 if (ret == 0x84 + len - 1) {
123 break;
124 } else if (ret == 0x94 + len - 1) {
125 return -ENODEV;
126 } else if (ret < 0) {
127 em28xx_warn("failed to get i2c transfer status from "
128 "bridge register (error=%i)\n", ret);
129 return ret;
130 }
131 msleep(5);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800132 }
Frank Schaefer2fcc82d2013-01-03 14:27:03 -0300133 if (ret != 0x84 + len - 1)
134 em28xx_warn("read from i2c device at 0x%x timed out\n", addr);
135
136 /* get the received message */
137 ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len);
138 if (ret != len) {
139 em28xx_warn("reading from i2c device at 0x%x failed: "
140 "couldn't get the received message from the bridge "
141 "(error=%i)\n", addr, ret);
142 return (ret < 0) ? ret : -EIO;
143 }
144 for (i = 0; i < len; i++)
145 buf[i] = buf2[len - 1 - i];
146
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800147 return ret;
148}
149
150/*
Frank Schaefer2fcc82d2013-01-03 14:27:03 -0300151 * em2800_i2c_check_for_device()
152 * check if there is an i2c device at the supplied address
153 */
154static int em2800_i2c_check_for_device(struct em28xx *dev, u8 addr)
155{
156 u8 buf;
157 int ret;
158
159 ret = em2800_i2c_recv_bytes(dev, addr, &buf, 1);
160 if (ret == 1)
161 return 0;
162 return (ret < 0) ? ret : -EIO;
163}
164
165/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800166 * em28xx_i2c_send_bytes()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800167 */
Frank Schaefera6bad042012-12-16 14:23:27 -0300168static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
169 u16 len, int stop)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800170{
171 int wrcount = 0;
Mauro Carvalho Chehabbbc70e62011-07-09 19:36:11 -0300172 int write_timeout, ret;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800173
Frank Schaeferf5ae3712013-01-03 14:27:02 -0300174 if (len < 1 || len > 64)
175 return -EOPNOTSUPP;
176
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800177 wrcount = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800178
Mauro Carvalho Chehabbbc70e62011-07-09 19:36:11 -0300179 /* Seems to be required after a write */
Frank Schaefer2fcc82d2013-01-03 14:27:03 -0300180 for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0;
Mauro Carvalho Chehabbbc70e62011-07-09 19:36:11 -0300181 write_timeout -= 5) {
182 ret = dev->em28xx_read_reg(dev, 0x05);
183 if (!ret)
184 break;
185 msleep(5);
186 }
187
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800188 return wrcount;
189}
190
191/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800192 * em28xx_i2c_recv_bytes()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800193 * read a byte from the i2c device
194 */
Frank Schaefera6bad042012-12-16 14:23:27 -0300195static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800196{
197 int ret;
Frank Schaeferf5ae3712013-01-03 14:27:02 -0300198
199 if (len < 1 || len > 64)
200 return -EOPNOTSUPP;
201
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800202 ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800203 if (ret < 0) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800204 em28xx_warn("reading i2c device failed (error=%i)\n", ret);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800205 return ret;
206 }
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800207 if (dev->em28xx_read_reg(dev, 0x5) != 0)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800208 return -ENODEV;
209 return ret;
210}
211
212/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800213 * em28xx_i2c_check_for_device()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800214 * check if there is a i2c_device at the supplied address
215 */
Frank Schaefera6bad042012-12-16 14:23:27 -0300216static int em28xx_i2c_check_for_device(struct em28xx *dev, u16 addr)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800217{
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800218 int ret;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800219
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800220 ret = dev->em28xx_read_reg_req(dev, 2, addr);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800221 if (ret < 0) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800222 em28xx_warn("reading from i2c device failed (error=%i)\n", ret);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800223 return ret;
224 }
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800225 if (dev->em28xx_read_reg(dev, 0x5) != 0)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800226 return -ENODEV;
227 return 0;
228}
229
230/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800231 * em28xx_i2c_xfer()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800232 * the main i2c transfer function
233 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800234static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800235 struct i2c_msg msgs[], int num)
236{
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800237 struct em28xx *dev = i2c_adap->algo_data;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800238 int addr, rc, i, byte;
239
240 if (num <= 0)
241 return 0;
242 for (i = 0; i < num; i++) {
243 addr = msgs[i].addr << 1;
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300244 dprintk2(2, "%s %s addr=%x len=%d:",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800245 (msgs[i].flags & I2C_M_RD) ? "read" : "write",
246 i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300247 if (!msgs[i].len) { /* no len: check only for device presence */
Mauro Carvalho Chehab505b6d02008-11-25 09:39:50 -0300248 if (dev->board.is_em2800)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800249 rc = em2800_i2c_check_for_device(dev, addr);
250 else
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800251 rc = em28xx_i2c_check_for_device(dev, addr);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800252 if (rc < 0) {
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300253 dprintk2(2, " no device\n");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800254 return rc;
255 }
256
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800257 } else if (msgs[i].flags & I2C_M_RD) {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800258 /* read bytes */
Mauro Carvalho Chehab505b6d02008-11-25 09:39:50 -0300259 if (dev->board.is_em2800)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800260 rc = em2800_i2c_recv_bytes(dev, addr,
261 msgs[i].buf,
262 msgs[i].len);
263 else
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800264 rc = em28xx_i2c_recv_bytes(dev, addr,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800265 msgs[i].buf,
266 msgs[i].len);
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300267 if (i2c_debug >= 2) {
268 for (byte = 0; byte < msgs[i].len; byte++)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800269 printk(" %02x", msgs[i].buf[byte]);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800270 }
271 } else {
272 /* write bytes */
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300273 if (i2c_debug >= 2) {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800274 for (byte = 0; byte < msgs[i].len; byte++)
275 printk(" %02x", msgs[i].buf[byte]);
276 }
Mauro Carvalho Chehab505b6d02008-11-25 09:39:50 -0300277 if (dev->board.is_em2800)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800278 rc = em2800_i2c_send_bytes(dev, addr,
279 msgs[i].buf,
280 msgs[i].len);
281 else
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800282 rc = em28xx_i2c_send_bytes(dev, addr,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800283 msgs[i].buf,
284 msgs[i].len,
285 i == num - 1);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800286 }
Markus Rechbergere8e41da2006-02-07 06:49:11 -0200287 if (rc < 0)
288 goto err;
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300289 if (i2c_debug >= 2)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800290 printk("\n");
291 }
292
293 return num;
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300294err:
295 dprintk2(2, " ERROR: %i\n", rc);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800296 return rc;
297}
298
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -0300299/* based on linux/sunrpc/svcauth.h and linux/hash.h
300 * The original hash function returns a different value, if arch is x86_64
301 * or i386.
302 */
303static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits)
304{
305 unsigned long hash = 0;
306 unsigned long l = 0;
307 int len = 0;
308 unsigned char c;
309 do {
310 if (len == length) {
311 c = (char)len;
312 len = -1;
313 } else
314 c = *buf++;
315 l = (l << 8) | c;
316 len++;
317 if ((len & (32 / 8 - 1)) == 0)
318 hash = ((hash^l) * 0x9e370001UL);
319 } while (len);
320
321 return (hash >> (32 - bits)) & 0xffffffffUL;
322}
323
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800324static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800325{
326 unsigned char buf, *p = eedata;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800327 struct em28xx_eeprom *em_eeprom = (void *)eedata;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800328 int i, err, size = len, block;
329
Mauro Carvalho Chehabfec528b2011-07-03 21:05:06 -0300330 if (dev->chip_id == CHIP_ID_EM2874 ||
331 dev->chip_id == CHIP_ID_EM28174 ||
332 dev->chip_id == CHIP_ID_EM2884) {
Devin Heitmuellera527c9f2008-11-12 02:05:10 -0300333 /* Empia switched to a 16-bit addressable eeprom in newer
334 devices. While we could certainly write a routine to read
335 the eeprom, there is nothing of use in there that cannot be
336 accessed through registers, and there is the risk that we
337 could corrupt the eeprom (since a 16-bit read call is
338 interpreted as a write call by 8-bit eeproms).
339 */
340 return 0;
341 }
342
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800343 dev->i2c_client.addr = 0xa0 >> 1;
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800344
345 /* Check if board has eeprom */
346 err = i2c_master_recv(&dev->i2c_client, &buf, 0);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300347 if (err < 0) {
Mauro Carvalho Chehabc41109f2008-11-15 23:44:14 -0300348 em28xx_errdev("board has no eeprom\n");
349 memset(eedata, 0, len);
350 return -ENODEV;
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300351 }
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800352
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800353 buf = 0;
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300354
355 err = i2c_master_send(&dev->i2c_client, &buf, 1);
356 if (err != 1) {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800357 printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
358 dev->name, err);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300359 return err;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800360 }
361 while (size > 0) {
362 if (size > 16)
363 block = 16;
364 else
365 block = size;
366
367 if (block !=
368 (err = i2c_master_recv(&dev->i2c_client, p, block))) {
369 printk(KERN_WARNING
370 "%s: i2c eeprom read error (err=%d)\n",
371 dev->name, err);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300372 return err;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800373 }
374 size -= block;
375 p += block;
376 }
377 for (i = 0; i < len; i++) {
378 if (0 == (i % 16))
379 printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
380 printk(" %02x", eedata[i]);
381 if (15 == (i % 16))
382 printk("\n");
383 }
384
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -0300385 if (em_eeprom->id == 0x9567eb1a)
386 dev->hash = em28xx_hash_mem(eedata, len, 32);
387
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300388 printk(KERN_INFO "%s: EEPROM ID= 0x%08x, EEPROM hash = 0x%08lx\n",
389 dev->name, em_eeprom->id, dev->hash);
390
391 printk(KERN_INFO "%s: EEPROM info:\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800392
393 switch (em_eeprom->chip_conf >> 4 & 0x3) {
394 case 0:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300395 printk(KERN_INFO "%s:\tNo audio on board.\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800396 break;
397 case 1:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300398 printk(KERN_INFO "%s:\tAC97 audio (5 sample rates)\n",
399 dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800400 break;
401 case 2:
Nicola Soranzoa1a6ee72009-02-10 23:28:24 -0300402 printk(KERN_INFO "%s:\tI2S audio, sample rate=32k\n",
403 dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800404 break;
405 case 3:
Nicola Soranzoa1a6ee72009-02-10 23:28:24 -0300406 printk(KERN_INFO "%s:\tI2S audio, 3 sample rates\n",
407 dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800408 break;
409 }
410
411 if (em_eeprom->chip_conf & 1 << 3)
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300412 printk(KERN_INFO "%s:\tUSB Remote wakeup capable\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800413
414 if (em_eeprom->chip_conf & 1 << 2)
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300415 printk(KERN_INFO "%s:\tUSB Self power capable\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800416
417 switch (em_eeprom->chip_conf & 0x3) {
418 case 0:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300419 printk(KERN_INFO "%s:\t500mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800420 break;
421 case 1:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300422 printk(KERN_INFO "%s:\t400mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800423 break;
424 case 2:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300425 printk(KERN_INFO "%s:\t300mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800426 break;
427 case 3:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300428 printk(KERN_INFO "%s:\t200mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800429 break;
430 }
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300431 printk(KERN_INFO "%s:\tTable at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
432 dev->name,
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300433 em_eeprom->string_idx_table,
434 em_eeprom->string1,
435 em_eeprom->string2,
436 em_eeprom->string3);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800437
438 return 0;
439}
440
441/* ----------------------------------------------------------- */
442
443/*
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800444 * functionality()
445 */
446static u32 functionality(struct i2c_adapter *adap)
447{
Frank Schaefereaf33c42013-01-03 14:27:04 -0300448 struct em28xx *dev = adap->algo_data;
449 u32 func_flags = I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
450 if (dev->board.is_em2800)
451 func_flags &= ~I2C_FUNC_SMBUS_WRITE_BLOCK_DATA;
452 return func_flags;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800453}
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}