blob: 8532c1d4fd4618869aad24be2d49711d7b8c7378 [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) {
Frank Schaefer45f04e82013-01-03 14:27:05 -030079 em28xx_warn("failed to trigger write to i2c address 0x%x "
80 "(error=%i)\n", addr, ret);
81 return (ret < 0) ? ret : -EIO;
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080082 }
Frank Schaefer2fcc82d2013-01-03 14:27:03 -030083 /* wait for completion */
84 for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0;
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080085 write_timeout -= 5) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080086 ret = dev->em28xx_read_reg(dev, 0x05);
Frank Schaefer45f04e82013-01-03 14:27:05 -030087 if (ret == 0x80 + len - 1) {
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080088 return len;
Frank Schaefer45f04e82013-01-03 14:27:05 -030089 } else if (ret == 0x94 + len - 1) {
90 return -ENODEV;
91 } else if (ret < 0) {
92 em28xx_warn("failed to get i2c transfer status from "
93 "bridge register (error=%i)\n", ret);
94 return ret;
95 }
Markus Rechbergere8e41da2006-02-07 06:49:11 -020096 msleep(5);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080097 }
Frank Schaefer45f04e82013-01-03 14:27:05 -030098 em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080099 return -EIO;
100}
101
102/*
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800103 * em2800_i2c_recv_bytes()
Frank Schaefer2fcc82d2013-01-03 14:27:03 -0300104 * read up to 4 bytes from the em2800 i2c device
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800105 */
Frank Schaefera6bad042012-12-16 14:23:27 -0300106static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800107{
Frank Schaefer2fcc82d2013-01-03 14:27:03 -0300108 u8 buf2[4];
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800109 int ret;
Frank Schaefer2fcc82d2013-01-03 14:27:03 -0300110 int read_timeout;
111 int i;
Frank Schaeferf5ae3712013-01-03 14:27:02 -0300112
113 if (len < 1 || len > 4)
114 return -EOPNOTSUPP;
115
Frank Schaefer2fcc82d2013-01-03 14:27:03 -0300116 /* trigger read */
117 buf2[1] = 0x84 + len - 1;
118 buf2[0] = addr;
119 ret = dev->em28xx_write_regs(dev, 0x04, buf2, 2);
120 if (ret != 2) {
121 em28xx_warn("failed to trigger read from i2c address 0x%x "
122 "(error=%i)\n", addr, ret);
123 return (ret < 0) ? ret : -EIO;
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800124 }
Frank Schaefer2fcc82d2013-01-03 14:27:03 -0300125
126 /* wait for completion */
127 for (read_timeout = EM2800_I2C_XFER_TIMEOUT; read_timeout > 0;
128 read_timeout -= 5) {
129 ret = dev->em28xx_read_reg(dev, 0x05);
130 if (ret == 0x84 + len - 1) {
131 break;
132 } else if (ret == 0x94 + len - 1) {
133 return -ENODEV;
134 } else if (ret < 0) {
135 em28xx_warn("failed to get i2c transfer status from "
136 "bridge register (error=%i)\n", ret);
137 return ret;
138 }
139 msleep(5);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800140 }
Frank Schaefer2fcc82d2013-01-03 14:27:03 -0300141 if (ret != 0x84 + len - 1)
142 em28xx_warn("read from i2c device at 0x%x timed out\n", addr);
143
144 /* get the received message */
145 ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len);
146 if (ret != len) {
147 em28xx_warn("reading from i2c device at 0x%x failed: "
148 "couldn't get the received message from the bridge "
149 "(error=%i)\n", addr, ret);
150 return (ret < 0) ? ret : -EIO;
151 }
152 for (i = 0; i < len; i++)
153 buf[i] = buf2[len - 1 - i];
154
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800155 return ret;
156}
157
158/*
Frank Schaefer2fcc82d2013-01-03 14:27:03 -0300159 * em2800_i2c_check_for_device()
160 * check if there is an i2c device at the supplied address
161 */
162static int em2800_i2c_check_for_device(struct em28xx *dev, u8 addr)
163{
164 u8 buf;
165 int ret;
166
167 ret = em2800_i2c_recv_bytes(dev, addr, &buf, 1);
168 if (ret == 1)
169 return 0;
170 return (ret < 0) ? ret : -EIO;
171}
172
173/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800174 * em28xx_i2c_send_bytes()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800175 */
Frank Schaefera6bad042012-12-16 14:23:27 -0300176static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
177 u16 len, int stop)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800178{
Mauro Carvalho Chehabbbc70e62011-07-09 19:36:11 -0300179 int write_timeout, ret;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800180
Frank Schaeferf5ae3712013-01-03 14:27:02 -0300181 if (len < 1 || len > 64)
182 return -EOPNOTSUPP;
Frank Schaefer45f04e82013-01-03 14:27:05 -0300183 /* NOTE: limited by the USB ctrl message constraints
184 * Zero length reads always succeed, even if no device is connected */
Frank Schaeferf5ae3712013-01-03 14:27:02 -0300185
Frank Schaefer45f04e82013-01-03 14:27:05 -0300186 /* Write to i2c device */
187 ret = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len);
188 if (ret != len) {
189 if (ret < 0) {
190 em28xx_warn("writing to i2c device at 0x%x failed "
191 "(error=%i)\n", addr, ret);
192 return ret;
193 } else {
194 em28xx_warn("%i bytes write to i2c device at 0x%x "
195 "requested, but %i bytes written\n",
196 len, addr, ret);
197 return -EIO;
198 }
199 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800200
Frank Schaefer45f04e82013-01-03 14:27:05 -0300201 /* Check success of the i2c operation */
Frank Schaefer2fcc82d2013-01-03 14:27:03 -0300202 for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0;
Mauro Carvalho Chehabbbc70e62011-07-09 19:36:11 -0300203 write_timeout -= 5) {
204 ret = dev->em28xx_read_reg(dev, 0x05);
Frank Schaefer45f04e82013-01-03 14:27:05 -0300205 if (ret == 0) { /* success */
206 return len;
207 } else if (ret == 0x10) {
208 return -ENODEV;
209 } else if (ret < 0) {
210 em28xx_warn("failed to read i2c transfer status from "
211 "bridge (error=%i)\n", ret);
212 return ret;
213 }
Mauro Carvalho Chehabbbc70e62011-07-09 19:36:11 -0300214 msleep(5);
Frank Schaefer45f04e82013-01-03 14:27:05 -0300215 /* NOTE: do we really have to wait for success ?
216 Never seen anything else than 0x00 or 0x10
217 (even with high payload) ... */
Mauro Carvalho Chehabbbc70e62011-07-09 19:36:11 -0300218 }
Frank Schaefer45f04e82013-01-03 14:27:05 -0300219 em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
220 return -EIO;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800221}
222
223/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800224 * em28xx_i2c_recv_bytes()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800225 * read a byte from the i2c device
226 */
Frank Schaefera6bad042012-12-16 14:23:27 -0300227static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800228{
229 int ret;
Frank Schaeferf5ae3712013-01-03 14:27:02 -0300230
231 if (len < 1 || len > 64)
232 return -EOPNOTSUPP;
Frank Schaefer45f04e82013-01-03 14:27:05 -0300233 /* NOTE: limited by the USB ctrl message constraints
234 * Zero length reads always succeed, even if no device is connected */
Frank Schaeferf5ae3712013-01-03 14:27:02 -0300235
Frank Schaefer45f04e82013-01-03 14:27:05 -0300236 /* Read data from i2c device */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800237 ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
Frank Schaefer45f04e82013-01-03 14:27:05 -0300238 if (ret != len) {
239 if (ret < 0) {
240 em28xx_warn("reading from i2c device at 0x%x failed "
241 "(error=%i)\n", addr, ret);
242 return ret;
243 } else {
244 em28xx_warn("%i bytes requested from i2c device at "
245 "0x%x, but %i bytes received\n",
246 len, addr, ret);
247 return -EIO;
248 }
249 }
250
251 /* Check success of the i2c operation */
252 ret = dev->em28xx_read_reg(dev, 0x05);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800253 if (ret < 0) {
Frank Schaefer45f04e82013-01-03 14:27:05 -0300254 em28xx_warn("failed to read i2c transfer status from "
255 "bridge (error=%i)\n", ret);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800256 return ret;
257 }
Frank Schaefer45f04e82013-01-03 14:27:05 -0300258 if (ret > 0) {
259 if (ret == 0x10) {
260 return -ENODEV;
261 } else {
262 em28xx_warn("unknown i2c error (status=%i)\n", ret);
263 return -EIO;
264 }
265 }
266 return len;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800267}
268
269/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800270 * em28xx_i2c_check_for_device()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800271 * check if there is a i2c_device at the supplied address
272 */
Frank Schaefera6bad042012-12-16 14:23:27 -0300273static int em28xx_i2c_check_for_device(struct em28xx *dev, u16 addr)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800274{
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800275 int ret;
Frank Schaefer45f04e82013-01-03 14:27:05 -0300276 u8 buf;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800277
Frank Schaefer45f04e82013-01-03 14:27:05 -0300278 ret = em28xx_i2c_recv_bytes(dev, addr, &buf, 1);
279 if (ret == 1)
280 return 0;
281 return (ret < 0) ? ret : -EIO;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800282}
283
284/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800285 * em28xx_i2c_xfer()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800286 * the main i2c transfer function
287 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800288static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800289 struct i2c_msg msgs[], int num)
290{
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800291 struct em28xx *dev = i2c_adap->algo_data;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800292 int addr, rc, i, byte;
293
294 if (num <= 0)
295 return 0;
296 for (i = 0; i < num; i++) {
297 addr = msgs[i].addr << 1;
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300298 dprintk2(2, "%s %s addr=%x len=%d:",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800299 (msgs[i].flags & I2C_M_RD) ? "read" : "write",
300 i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300301 if (!msgs[i].len) { /* no len: check only for device presence */
Mauro Carvalho Chehab505b6d02008-11-25 09:39:50 -0300302 if (dev->board.is_em2800)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800303 rc = em2800_i2c_check_for_device(dev, addr);
304 else
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800305 rc = em28xx_i2c_check_for_device(dev, addr);
Frank Schaefer45f04e82013-01-03 14:27:05 -0300306 if (rc == -ENODEV) {
307 if (i2c_debug >= 2)
308 printk(" no device\n");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800309 return rc;
310 }
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800311 } else if (msgs[i].flags & I2C_M_RD) {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800312 /* read bytes */
Mauro Carvalho Chehab505b6d02008-11-25 09:39:50 -0300313 if (dev->board.is_em2800)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800314 rc = em2800_i2c_recv_bytes(dev, addr,
315 msgs[i].buf,
316 msgs[i].len);
317 else
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800318 rc = em28xx_i2c_recv_bytes(dev, addr,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800319 msgs[i].buf,
320 msgs[i].len);
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300321 if (i2c_debug >= 2) {
322 for (byte = 0; byte < msgs[i].len; byte++)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800323 printk(" %02x", msgs[i].buf[byte]);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800324 }
325 } else {
326 /* write bytes */
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300327 if (i2c_debug >= 2) {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800328 for (byte = 0; byte < msgs[i].len; byte++)
329 printk(" %02x", msgs[i].buf[byte]);
330 }
Mauro Carvalho Chehab505b6d02008-11-25 09:39:50 -0300331 if (dev->board.is_em2800)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800332 rc = em2800_i2c_send_bytes(dev, addr,
333 msgs[i].buf,
334 msgs[i].len);
335 else
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800336 rc = em28xx_i2c_send_bytes(dev, addr,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800337 msgs[i].buf,
338 msgs[i].len,
339 i == num - 1);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800340 }
Frank Schaefer45f04e82013-01-03 14:27:05 -0300341 if (rc < 0) {
342 if (i2c_debug >= 2)
343 printk(" ERROR: %i\n", rc);
344 return rc;
345 }
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300346 if (i2c_debug >= 2)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800347 printk("\n");
348 }
349
350 return num;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800351}
352
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -0300353/* based on linux/sunrpc/svcauth.h and linux/hash.h
354 * The original hash function returns a different value, if arch is x86_64
355 * or i386.
356 */
357static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits)
358{
359 unsigned long hash = 0;
360 unsigned long l = 0;
361 int len = 0;
362 unsigned char c;
363 do {
364 if (len == length) {
365 c = (char)len;
366 len = -1;
367 } else
368 c = *buf++;
369 l = (l << 8) | c;
370 len++;
371 if ((len & (32 / 8 - 1)) == 0)
372 hash = ((hash^l) * 0x9e370001UL);
373 } while (len);
374
375 return (hash >> (32 - bits)) & 0xffffffffUL;
376}
377
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800378static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800379{
380 unsigned char buf, *p = eedata;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800381 struct em28xx_eeprom *em_eeprom = (void *)eedata;
Frank Schaefer90271962013-01-03 14:27:06 -0300382 int i, err, size = len, block, block_max;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800383
Mauro Carvalho Chehabfec528b2011-07-03 21:05:06 -0300384 if (dev->chip_id == CHIP_ID_EM2874 ||
385 dev->chip_id == CHIP_ID_EM28174 ||
386 dev->chip_id == CHIP_ID_EM2884) {
Devin Heitmuellera527c9f2008-11-12 02:05:10 -0300387 /* Empia switched to a 16-bit addressable eeprom in newer
388 devices. While we could certainly write a routine to read
389 the eeprom, there is nothing of use in there that cannot be
390 accessed through registers, and there is the risk that we
391 could corrupt the eeprom (since a 16-bit read call is
392 interpreted as a write call by 8-bit eeproms).
393 */
394 return 0;
395 }
396
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800397 dev->i2c_client.addr = 0xa0 >> 1;
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800398
399 /* Check if board has eeprom */
400 err = i2c_master_recv(&dev->i2c_client, &buf, 0);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300401 if (err < 0) {
Mauro Carvalho Chehabc41109f2008-11-15 23:44:14 -0300402 em28xx_errdev("board has no eeprom\n");
403 memset(eedata, 0, len);
404 return -ENODEV;
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300405 }
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800406
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800407 buf = 0;
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300408
409 err = i2c_master_send(&dev->i2c_client, &buf, 1);
410 if (err != 1) {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800411 printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
412 dev->name, err);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300413 return err;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800414 }
Frank Schaefer90271962013-01-03 14:27:06 -0300415
416 if (dev->board.is_em2800)
417 block_max = 4;
418 else
419 block_max = 64;
420
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800421 while (size > 0) {
Frank Schaefer90271962013-01-03 14:27:06 -0300422 if (size > block_max)
423 block = block_max;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800424 else
425 block = size;
426
427 if (block !=
428 (err = i2c_master_recv(&dev->i2c_client, p, block))) {
429 printk(KERN_WARNING
430 "%s: i2c eeprom read error (err=%d)\n",
431 dev->name, err);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300432 return err;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800433 }
434 size -= block;
435 p += block;
436 }
437 for (i = 0; i < len; i++) {
438 if (0 == (i % 16))
439 printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
440 printk(" %02x", eedata[i]);
441 if (15 == (i % 16))
442 printk("\n");
443 }
444
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -0300445 if (em_eeprom->id == 0x9567eb1a)
446 dev->hash = em28xx_hash_mem(eedata, len, 32);
447
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300448 printk(KERN_INFO "%s: EEPROM ID= 0x%08x, EEPROM hash = 0x%08lx\n",
449 dev->name, em_eeprom->id, dev->hash);
450
451 printk(KERN_INFO "%s: EEPROM info:\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800452
453 switch (em_eeprom->chip_conf >> 4 & 0x3) {
454 case 0:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300455 printk(KERN_INFO "%s:\tNo audio on board.\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800456 break;
457 case 1:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300458 printk(KERN_INFO "%s:\tAC97 audio (5 sample rates)\n",
459 dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800460 break;
461 case 2:
Nicola Soranzoa1a6ee72009-02-10 23:28:24 -0300462 printk(KERN_INFO "%s:\tI2S audio, sample rate=32k\n",
463 dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800464 break;
465 case 3:
Nicola Soranzoa1a6ee72009-02-10 23:28:24 -0300466 printk(KERN_INFO "%s:\tI2S audio, 3 sample rates\n",
467 dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800468 break;
469 }
470
471 if (em_eeprom->chip_conf & 1 << 3)
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300472 printk(KERN_INFO "%s:\tUSB Remote wakeup capable\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800473
474 if (em_eeprom->chip_conf & 1 << 2)
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300475 printk(KERN_INFO "%s:\tUSB Self power capable\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800476
477 switch (em_eeprom->chip_conf & 0x3) {
478 case 0:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300479 printk(KERN_INFO "%s:\t500mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800480 break;
481 case 1:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300482 printk(KERN_INFO "%s:\t400mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800483 break;
484 case 2:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300485 printk(KERN_INFO "%s:\t300mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800486 break;
487 case 3:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300488 printk(KERN_INFO "%s:\t200mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800489 break;
490 }
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300491 printk(KERN_INFO "%s:\tTable at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
492 dev->name,
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300493 em_eeprom->string_idx_table,
494 em_eeprom->string1,
495 em_eeprom->string2,
496 em_eeprom->string3);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800497
498 return 0;
499}
500
501/* ----------------------------------------------------------- */
502
503/*
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800504 * functionality()
505 */
506static u32 functionality(struct i2c_adapter *adap)
507{
Frank Schaefereaf33c42013-01-03 14:27:04 -0300508 struct em28xx *dev = adap->algo_data;
509 u32 func_flags = I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
510 if (dev->board.is_em2800)
511 func_flags &= ~I2C_FUNC_SMBUS_WRITE_BLOCK_DATA;
512 return func_flags;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800513}
514
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800515static struct i2c_algorithm em28xx_algo = {
516 .master_xfer = em28xx_i2c_xfer,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800517 .functionality = functionality,
518};
519
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800520static struct i2c_adapter em28xx_adap_template = {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800521 .owner = THIS_MODULE,
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800522 .name = "em28xx",
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800523 .algo = &em28xx_algo,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800524};
525
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800526static struct i2c_client em28xx_client_template = {
527 .name = "em28xx internal",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800528};
529
530/* ----------------------------------------------------------- */
531
532/*
533 * i2c_devs
534 * incomplete list of known devices
535 */
536static char *i2c_devs[128] = {
Frank Schaefer0b3966e2013-01-13 10:15:08 -0300537 [0x3e >> 1] = "remote IR sensor",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800538 [0x4a >> 1] = "saa7113h",
Martin Blumenstingl729841e2012-06-12 18:19:27 -0300539 [0x52 >> 1] = "drxk",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800540 [0x60 >> 1] = "remote IR sensor",
Markus Rechbergerda45a2a2005-11-08 21:37:31 -0800541 [0x8e >> 1] = "remote IR sensor",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800542 [0x86 >> 1] = "tda9887",
543 [0x80 >> 1] = "msp34xx",
544 [0x88 >> 1] = "msp34xx",
545 [0xa0 >> 1] = "eeprom",
Vitaly Wool2bd1d9eb2009-03-04 08:27:52 -0300546 [0xb0 >> 1] = "tda9874",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800547 [0xb8 >> 1] = "tvp5150a",
Mauro Carvalho Chehab791a08f2009-07-03 15:36:18 -0300548 [0xba >> 1] = "webcam sensor or tvp5150a",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800549 [0xc0 >> 1] = "tuner (analog)",
550 [0xc2 >> 1] = "tuner (analog)",
551 [0xc4 >> 1] = "tuner (analog)",
552 [0xc6 >> 1] = "tuner (analog)",
553};
554
555/*
556 * do_i2c_scan()
557 * check i2c address range for devices
558 */
Sascha Sommerfad7b952007-11-04 08:06:48 -0300559void em28xx_do_i2c_scan(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800560{
Sascha Sommerfad7b952007-11-04 08:06:48 -0300561 u8 i2c_devicelist[128];
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800562 unsigned char buf;
563 int i, rc;
564
Sascha Sommerfad7b952007-11-04 08:06:48 -0300565 memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist));
566
Mauro Carvalho Chehab53c4e952007-03-29 08:42:30 -0300567 for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
Sascha Sommerfad7b952007-11-04 08:06:48 -0300568 dev->i2c_client.addr = i;
569 rc = i2c_master_recv(&dev->i2c_client, &buf, 0);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800570 if (rc < 0)
571 continue;
Sascha Sommerfad7b952007-11-04 08:06:48 -0300572 i2c_devicelist[i] = i;
573 printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n",
574 dev->name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800575 }
Sascha Sommerfad7b952007-11-04 08:06:48 -0300576
577 dev->i2c_hash = em28xx_hash_mem(i2c_devicelist,
578 ARRAY_SIZE(i2c_devicelist), 32);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800579}
580
581/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800582 * em28xx_i2c_register()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800583 * register i2c bus
584 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800585int em28xx_i2c_register(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800586{
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300587 int retval;
588
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800589 BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg);
590 BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req);
591 dev->i2c_adap = em28xx_adap_template;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800592 dev->i2c_adap.dev.parent = &dev->udev->dev;
593 strcpy(dev->i2c_adap.name, dev->name);
594 dev->i2c_adap.algo_data = dev;
Douglas Schilling Landgraff2cf2502009-03-31 17:10:58 -0300595 i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300596
597 retval = i2c_add_adapter(&dev->i2c_adap);
598 if (retval < 0) {
599 em28xx_errdev("%s: i2c_add_adapter failed! retval [%d]\n",
600 __func__, retval);
601 return retval;
602 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800603
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800604 dev->i2c_client = em28xx_client_template;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800605 dev->i2c_client.adapter = &dev->i2c_adap;
606
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300607 retval = em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata));
Mauro Carvalho Chehabc41109f2008-11-15 23:44:14 -0300608 if ((retval < 0) && (retval != -ENODEV)) {
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300609 em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n",
610 __func__, retval);
Mauro Carvalho Chehabc41109f2008-11-15 23:44:14 -0300611
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300612 return retval;
613 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800614
615 if (i2c_scan)
Sascha Sommerfad7b952007-11-04 08:06:48 -0300616 em28xx_do_i2c_scan(dev);
Mauro Carvalho Chehabc41109f2008-11-15 23:44:14 -0300617
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800618 return 0;
619}
620
621/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800622 * em28xx_i2c_unregister()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800623 * unregister i2c_bus
624 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800625int em28xx_i2c_unregister(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800626{
627 i2c_del_adapter(&dev->i2c_adap);
628 return 0;
629}