blob: 02c12fe6361be60834745e8e76c1b87e1f42873e [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 * untested for more than 4 bytes
185 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800186static int em28xx_i2c_send_bytes(void *data, unsigned char addr, char *buf,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800187 short len, int stop)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800188{
189 int wrcount = 0;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800190 struct em28xx *dev = (struct em28xx *)data;
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
194 return wrcount;
195}
196
197/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800198 * em28xx_i2c_recv_bytes()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800199 * read a byte from the i2c device
200 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800201static int em28xx_i2c_recv_bytes(struct em28xx *dev, unsigned char addr,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800202 char *buf, int len)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800203{
204 int ret;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800205 ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800206 if (ret < 0) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800207 em28xx_warn("reading i2c device failed (error=%i)\n", ret);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800208 return ret;
209 }
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800210 if (dev->em28xx_read_reg(dev, 0x5) != 0)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800211 return -ENODEV;
212 return ret;
213}
214
215/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800216 * em28xx_i2c_check_for_device()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800217 * check if there is a i2c_device at the supplied address
218 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800219static int em28xx_i2c_check_for_device(struct em28xx *dev, unsigned char addr)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800220{
221 char msg;
222 int ret;
223 msg = addr;
224
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800225 ret = dev->em28xx_read_reg_req(dev, 2, addr);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800226 if (ret < 0) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800227 em28xx_warn("reading from i2c device failed (error=%i)\n", ret);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800228 return ret;
229 }
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800230 if (dev->em28xx_read_reg(dev, 0x5) != 0)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800231 return -ENODEV;
232 return 0;
233}
234
235/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800236 * em28xx_i2c_xfer()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800237 * the main i2c transfer function
238 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800239static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800240 struct i2c_msg msgs[], int num)
241{
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800242 struct em28xx *dev = i2c_adap->algo_data;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800243 int addr, rc, i, byte;
244
245 if (num <= 0)
246 return 0;
247 for (i = 0; i < num; i++) {
248 addr = msgs[i].addr << 1;
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300249 dprintk2(2, "%s %s addr=%x len=%d:",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800250 (msgs[i].flags & I2C_M_RD) ? "read" : "write",
251 i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300252 if (!msgs[i].len) { /* no len: check only for device presence */
Mauro Carvalho Chehab505b6d02008-11-25 09:39:50 -0300253 if (dev->board.is_em2800)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800254 rc = em2800_i2c_check_for_device(dev, addr);
255 else
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800256 rc = em28xx_i2c_check_for_device(dev, addr);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800257 if (rc < 0) {
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300258 dprintk2(2, " no device\n");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800259 return rc;
260 }
261
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800262 } else if (msgs[i].flags & I2C_M_RD) {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800263 /* read bytes */
Mauro Carvalho Chehab505b6d02008-11-25 09:39:50 -0300264 if (dev->board.is_em2800)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800265 rc = em2800_i2c_recv_bytes(dev, addr,
266 msgs[i].buf,
267 msgs[i].len);
268 else
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800269 rc = em28xx_i2c_recv_bytes(dev, addr,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800270 msgs[i].buf,
271 msgs[i].len);
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300272 if (i2c_debug >= 2) {
273 for (byte = 0; byte < msgs[i].len; byte++)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800274 printk(" %02x", msgs[i].buf[byte]);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800275 }
276 } else {
277 /* write bytes */
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300278 if (i2c_debug >= 2) {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800279 for (byte = 0; byte < msgs[i].len; byte++)
280 printk(" %02x", msgs[i].buf[byte]);
281 }
Mauro Carvalho Chehab505b6d02008-11-25 09:39:50 -0300282 if (dev->board.is_em2800)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800283 rc = em2800_i2c_send_bytes(dev, addr,
284 msgs[i].buf,
285 msgs[i].len);
286 else
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800287 rc = em28xx_i2c_send_bytes(dev, addr,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800288 msgs[i].buf,
289 msgs[i].len,
290 i == num - 1);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800291 }
Markus Rechbergere8e41da2006-02-07 06:49:11 -0200292 if (rc < 0)
293 goto err;
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300294 if (i2c_debug >= 2)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800295 printk("\n");
296 }
297
298 return num;
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300299err:
300 dprintk2(2, " ERROR: %i\n", rc);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800301 return rc;
302}
303
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -0300304/* based on linux/sunrpc/svcauth.h and linux/hash.h
305 * The original hash function returns a different value, if arch is x86_64
306 * or i386.
307 */
308static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits)
309{
310 unsigned long hash = 0;
311 unsigned long l = 0;
312 int len = 0;
313 unsigned char c;
314 do {
315 if (len == length) {
316 c = (char)len;
317 len = -1;
318 } else
319 c = *buf++;
320 l = (l << 8) | c;
321 len++;
322 if ((len & (32 / 8 - 1)) == 0)
323 hash = ((hash^l) * 0x9e370001UL);
324 } while (len);
325
326 return (hash >> (32 - bits)) & 0xffffffffUL;
327}
328
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800329static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800330{
331 unsigned char buf, *p = eedata;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800332 struct em28xx_eeprom *em_eeprom = (void *)eedata;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800333 int i, err, size = len, block;
334
Devin Heitmuellera527c9f2008-11-12 02:05:10 -0300335 if (dev->chip_id == CHIP_ID_EM2874) {
336 /* Empia switched to a 16-bit addressable eeprom in newer
337 devices. While we could certainly write a routine to read
338 the eeprom, there is nothing of use in there that cannot be
339 accessed through registers, and there is the risk that we
340 could corrupt the eeprom (since a 16-bit read call is
341 interpreted as a write call by 8-bit eeproms).
342 */
343 return 0;
344 }
345
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800346 dev->i2c_client.addr = 0xa0 >> 1;
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800347
348 /* Check if board has eeprom */
349 err = i2c_master_recv(&dev->i2c_client, &buf, 0);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300350 if (err < 0) {
Mauro Carvalho Chehabc41109fc92008-11-15 23:44:14 -0300351 em28xx_errdev("board has no eeprom\n");
352 memset(eedata, 0, len);
353 return -ENODEV;
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300354 }
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800355
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800356 buf = 0;
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300357
358 err = i2c_master_send(&dev->i2c_client, &buf, 1);
359 if (err != 1) {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800360 printk(KERN_INFO "%s: Huh, no eeprom present (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 while (size > 0) {
365 if (size > 16)
366 block = 16;
367 else
368 block = size;
369
370 if (block !=
371 (err = i2c_master_recv(&dev->i2c_client, p, block))) {
372 printk(KERN_WARNING
373 "%s: i2c eeprom read error (err=%d)\n",
374 dev->name, err);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300375 return err;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800376 }
377 size -= block;
378 p += block;
379 }
380 for (i = 0; i < len; i++) {
381 if (0 == (i % 16))
382 printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
383 printk(" %02x", eedata[i]);
384 if (15 == (i % 16))
385 printk("\n");
386 }
387
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -0300388 if (em_eeprom->id == 0x9567eb1a)
389 dev->hash = em28xx_hash_mem(eedata, len, 32);
390
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300391 printk(KERN_INFO "%s: EEPROM ID= 0x%08x, EEPROM hash = 0x%08lx\n",
392 dev->name, em_eeprom->id, dev->hash);
393
394 printk(KERN_INFO "%s: EEPROM info:\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800395
396 switch (em_eeprom->chip_conf >> 4 & 0x3) {
397 case 0:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300398 printk(KERN_INFO "%s:\tNo audio on board.\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800399 break;
400 case 1:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300401 printk(KERN_INFO "%s:\tAC97 audio (5 sample rates)\n",
402 dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800403 break;
404 case 2:
Nicola Soranzoa1a6ee72009-02-10 23:28:24 -0300405 printk(KERN_INFO "%s:\tI2S audio, sample rate=32k\n",
406 dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800407 break;
408 case 3:
Nicola Soranzoa1a6ee72009-02-10 23:28:24 -0300409 printk(KERN_INFO "%s:\tI2S audio, 3 sample rates\n",
410 dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800411 break;
412 }
413
414 if (em_eeprom->chip_conf & 1 << 3)
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300415 printk(KERN_INFO "%s:\tUSB Remote wakeup capable\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800416
417 if (em_eeprom->chip_conf & 1 << 2)
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300418 printk(KERN_INFO "%s:\tUSB Self power capable\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800419
420 switch (em_eeprom->chip_conf & 0x3) {
421 case 0:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300422 printk(KERN_INFO "%s:\t500mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800423 break;
424 case 1:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300425 printk(KERN_INFO "%s:\t400mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800426 break;
427 case 2:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300428 printk(KERN_INFO "%s:\t300mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800429 break;
430 case 3:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300431 printk(KERN_INFO "%s:\t200mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800432 break;
433 }
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300434 printk(KERN_INFO "%s:\tTable at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
435 dev->name,
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300436 em_eeprom->string_idx_table,
437 em_eeprom->string1,
438 em_eeprom->string2,
439 em_eeprom->string3);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800440
441 return 0;
442}
443
444/* ----------------------------------------------------------- */
445
446/*
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800447 * functionality()
448 */
449static u32 functionality(struct i2c_adapter *adap)
450{
451 return I2C_FUNC_SMBUS_EMUL;
452}
453
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800454/*
455 * attach_inform()
456 * gets called when a device attaches to the i2c bus
457 * does some basic configuration
458 */
459static int attach_inform(struct i2c_client *client)
460{
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800461 struct em28xx *dev = client->adapter->algo_data;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800462
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800463 switch (client->addr << 1) {
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300464 case 0x86:
465 case 0x84:
466 case 0x96:
467 case 0x94:
468 {
469 struct v4l2_priv_tun_config tda9887_cfg;
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300470
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300471 struct tuner_setup tun_setup;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300472
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300473 tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
474 tun_setup.type = TUNER_TDA9887;
475 tun_setup.addr = client->addr;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300476
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300477 em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR,
478 &tun_setup);
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300479
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300480 tda9887_cfg.tuner = TUNER_TDA9887;
481 tda9887_cfg.priv = &dev->tda9887_conf;
482 em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG,
483 &tda9887_cfg);
484 break;
485 }
486 case 0x42:
487 dprintk1(1, "attach_inform: saa7114 detected.\n");
488 break;
489 case 0x4a:
490 dprintk1(1, "attach_inform: saa7113 detected.\n");
491 break;
492 case 0xa0:
493 dprintk1(1, "attach_inform: eeprom detected.\n");
494 break;
495 case 0x60:
496 case 0x8e:
497 {
498 struct IR_i2c *ir = i2c_get_clientdata(client);
499 dprintk1(1, "attach_inform: IR detected (%s).\n",
500 ir->phys);
501 em28xx_set_ir(dev, ir);
502 break;
503 }
504 case 0x80:
505 case 0x88:
506 dprintk1(1, "attach_inform: msp34xx detected.\n");
507 break;
508 case 0xb8:
509 case 0xba:
510 dprintk1(1, "attach_inform: tvp5150 detected.\n");
511 break;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300512
Vitaly Wool2bd1d9eb2009-03-04 08:27:52 -0300513 case 0xb0:
514 dprintk1(1, "attach_inform: tda9874 detected\n");
515 break;
516
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300517 default:
518 if (!dev->tuner_addr)
519 dev->tuner_addr = client->addr;
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -0300520
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300521 dprintk1(1, "attach inform: detected I2C address %x\n",
522 client->addr << 1);
Vitaly Wool2bd1d9eb2009-03-04 08:27:52 -0300523 dprintk1(1, "driver id %d\n", client->driver->id);
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -0300524
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800525 }
526
527 return 0;
528}
529
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800530static struct i2c_algorithm em28xx_algo = {
531 .master_xfer = em28xx_i2c_xfer,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800532 .functionality = functionality,
533};
534
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800535static struct i2c_adapter em28xx_adap_template = {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800536 .owner = THIS_MODULE,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800537 .class = I2C_CLASS_TV_ANALOG,
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800538 .name = "em28xx",
539 .id = I2C_HW_B_EM28XX,
540 .algo = &em28xx_algo,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800541 .client_register = attach_inform,
542};
543
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800544static struct i2c_client em28xx_client_template = {
545 .name = "em28xx internal",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800546};
547
548/* ----------------------------------------------------------- */
549
550/*
551 * i2c_devs
552 * incomplete list of known devices
553 */
554static char *i2c_devs[128] = {
555 [0x4a >> 1] = "saa7113h",
556 [0x60 >> 1] = "remote IR sensor",
Markus Rechbergerda45a2a2005-11-08 21:37:31 -0800557 [0x8e >> 1] = "remote IR sensor",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800558 [0x86 >> 1] = "tda9887",
559 [0x80 >> 1] = "msp34xx",
560 [0x88 >> 1] = "msp34xx",
561 [0xa0 >> 1] = "eeprom",
Vitaly Wool2bd1d9eb2009-03-04 08:27:52 -0300562 [0xb0 >> 1] = "tda9874",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800563 [0xb8 >> 1] = "tvp5150a",
564 [0xba >> 1] = "tvp5150a",
565 [0xc0 >> 1] = "tuner (analog)",
566 [0xc2 >> 1] = "tuner (analog)",
567 [0xc4 >> 1] = "tuner (analog)",
568 [0xc6 >> 1] = "tuner (analog)",
569};
570
571/*
572 * do_i2c_scan()
573 * check i2c address range for devices
574 */
Sascha Sommerfad7b952007-11-04 08:06:48 -0300575void em28xx_do_i2c_scan(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800576{
Sascha Sommerfad7b952007-11-04 08:06:48 -0300577 u8 i2c_devicelist[128];
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800578 unsigned char buf;
579 int i, rc;
580
Sascha Sommerfad7b952007-11-04 08:06:48 -0300581 memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist));
582
Mauro Carvalho Chehab53c4e952007-03-29 08:42:30 -0300583 for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
Sascha Sommerfad7b952007-11-04 08:06:48 -0300584 dev->i2c_client.addr = i;
585 rc = i2c_master_recv(&dev->i2c_client, &buf, 0);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800586 if (rc < 0)
587 continue;
Sascha Sommerfad7b952007-11-04 08:06:48 -0300588 i2c_devicelist[i] = i;
589 printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n",
590 dev->name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800591 }
Sascha Sommerfad7b952007-11-04 08:06:48 -0300592
593 dev->i2c_hash = em28xx_hash_mem(i2c_devicelist,
594 ARRAY_SIZE(i2c_devicelist), 32);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800595}
596
597/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800598 * em28xx_i2c_call_clients()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800599 * send commands to all attached i2c devices
600 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800601void em28xx_i2c_call_clients(struct em28xx *dev, unsigned int cmd, void *arg)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800602{
603 BUG_ON(NULL == dev->i2c_adap.algo_data);
604 i2c_clients_command(&dev->i2c_adap, cmd, arg);
605}
606
607/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800608 * em28xx_i2c_register()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800609 * register i2c bus
610 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800611int em28xx_i2c_register(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800612{
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300613 int retval;
614
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800615 BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg);
616 BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req);
617 dev->i2c_adap = em28xx_adap_template;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800618 dev->i2c_adap.dev.parent = &dev->udev->dev;
619 strcpy(dev->i2c_adap.name, dev->name);
620 dev->i2c_adap.algo_data = dev;
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300621
622 retval = i2c_add_adapter(&dev->i2c_adap);
623 if (retval < 0) {
624 em28xx_errdev("%s: i2c_add_adapter failed! retval [%d]\n",
625 __func__, retval);
626 return retval;
627 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800628
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800629 dev->i2c_client = em28xx_client_template;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800630 dev->i2c_client.adapter = &dev->i2c_adap;
631
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300632 retval = em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata));
Mauro Carvalho Chehabc41109fc92008-11-15 23:44:14 -0300633 if ((retval < 0) && (retval != -ENODEV)) {
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300634 em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n",
635 __func__, retval);
Mauro Carvalho Chehabc41109fc92008-11-15 23:44:14 -0300636
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300637 return retval;
638 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800639
640 if (i2c_scan)
Sascha Sommerfad7b952007-11-04 08:06:48 -0300641 em28xx_do_i2c_scan(dev);
Mauro Carvalho Chehabc41109fc92008-11-15 23:44:14 -0300642
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800643 return 0;
644}
645
646/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800647 * em28xx_i2c_unregister()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800648 * unregister i2c_bus
649 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800650int em28xx_i2c_unregister(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800651{
652 i2c_del_adapter(&dev->i2c_adap);
653 return 0;
654}