blob: 4ffcafb6ac9a41482c776ff00b56e452cc7a8304 [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
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080044/*
Frank Schaeferf5ae3712013-01-03 14:27:02 -030045 * em2800_i2c_send_bytes()
46 * send up to 4 bytes to the em2800 i2c device
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080047 */
Frank Schaeferf5ae3712013-01-03 14:27:02 -030048static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080049{
50 int ret;
51 int write_timeout;
Frank Schaefera6bad042012-12-16 14:23:27 -030052 u8 b2[6];
Frank Schaeferf5ae3712013-01-03 14:27:02 -030053
54 if (len < 1 || len > 4)
55 return -EOPNOTSUPP;
56
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080057 BUG_ON(len < 1 || len > 4);
58 b2[5] = 0x80 + len - 1;
59 b2[4] = addr;
60 b2[3] = buf[0];
61 if (len > 1)
62 b2[2] = buf[1];
63 if (len > 2)
64 b2[1] = buf[2];
65 if (len > 3)
66 b2[0] = buf[3];
67
Frank Schaefer2fcc82d2013-01-03 14:27:03 -030068 /* trigger write */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080069 ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080070 if (ret != 2 + len) {
Frank Schaefer45f04e82013-01-03 14:27:05 -030071 em28xx_warn("failed to trigger write to i2c address 0x%x "
72 "(error=%i)\n", addr, ret);
73 return (ret < 0) ? ret : -EIO;
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080074 }
Frank Schaefer2fcc82d2013-01-03 14:27:03 -030075 /* wait for completion */
76 for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0;
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080077 write_timeout -= 5) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080078 ret = dev->em28xx_read_reg(dev, 0x05);
Frank Schaefer45f04e82013-01-03 14:27:05 -030079 if (ret == 0x80 + len - 1) {
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080080 return len;
Frank Schaefer45f04e82013-01-03 14:27:05 -030081 } else if (ret == 0x94 + len - 1) {
82 return -ENODEV;
83 } else if (ret < 0) {
84 em28xx_warn("failed to get i2c transfer status from "
85 "bridge register (error=%i)\n", ret);
86 return ret;
87 }
Markus Rechbergere8e41da2006-02-07 06:49:11 -020088 msleep(5);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080089 }
Frank Schaefer45f04e82013-01-03 14:27:05 -030090 em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
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{
Mauro Carvalho Chehabbbc70e62011-07-09 19:36:11 -0300171 int write_timeout, ret;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800172
Frank Schaeferf5ae3712013-01-03 14:27:02 -0300173 if (len < 1 || len > 64)
174 return -EOPNOTSUPP;
Frank Schaefer45f04e82013-01-03 14:27:05 -0300175 /* NOTE: limited by the USB ctrl message constraints
176 * Zero length reads always succeed, even if no device is connected */
Frank Schaeferf5ae3712013-01-03 14:27:02 -0300177
Frank Schaefer45f04e82013-01-03 14:27:05 -0300178 /* Write to i2c device */
179 ret = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len);
180 if (ret != len) {
181 if (ret < 0) {
182 em28xx_warn("writing to i2c device at 0x%x failed "
183 "(error=%i)\n", addr, ret);
184 return ret;
185 } else {
186 em28xx_warn("%i bytes write to i2c device at 0x%x "
187 "requested, but %i bytes written\n",
188 len, addr, ret);
189 return -EIO;
190 }
191 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800192
Frank Schaefer45f04e82013-01-03 14:27:05 -0300193 /* Check success of the i2c operation */
Frank Schaefer2fcc82d2013-01-03 14:27:03 -0300194 for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0;
Mauro Carvalho Chehabbbc70e62011-07-09 19:36:11 -0300195 write_timeout -= 5) {
196 ret = dev->em28xx_read_reg(dev, 0x05);
Frank Schaefer45f04e82013-01-03 14:27:05 -0300197 if (ret == 0) { /* success */
198 return len;
199 } else if (ret == 0x10) {
200 return -ENODEV;
201 } else if (ret < 0) {
202 em28xx_warn("failed to read i2c transfer status from "
203 "bridge (error=%i)\n", ret);
204 return ret;
205 }
Mauro Carvalho Chehabbbc70e62011-07-09 19:36:11 -0300206 msleep(5);
Frank Schaefer45f04e82013-01-03 14:27:05 -0300207 /* NOTE: do we really have to wait for success ?
208 Never seen anything else than 0x00 or 0x10
209 (even with high payload) ... */
Mauro Carvalho Chehabbbc70e62011-07-09 19:36:11 -0300210 }
Frank Schaefer45f04e82013-01-03 14:27:05 -0300211 em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
212 return -EIO;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800213}
214
215/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800216 * em28xx_i2c_recv_bytes()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800217 * read a byte from the i2c device
218 */
Frank Schaefera6bad042012-12-16 14:23:27 -0300219static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800220{
221 int ret;
Frank Schaeferf5ae3712013-01-03 14:27:02 -0300222
223 if (len < 1 || len > 64)
224 return -EOPNOTSUPP;
Frank Schaefer45f04e82013-01-03 14:27:05 -0300225 /* NOTE: limited by the USB ctrl message constraints
226 * Zero length reads always succeed, even if no device is connected */
Frank Schaeferf5ae3712013-01-03 14:27:02 -0300227
Frank Schaefer45f04e82013-01-03 14:27:05 -0300228 /* Read data from i2c device */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800229 ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
Frank Schaefer45f04e82013-01-03 14:27:05 -0300230 if (ret != len) {
231 if (ret < 0) {
232 em28xx_warn("reading from i2c device at 0x%x failed "
233 "(error=%i)\n", addr, ret);
234 return ret;
235 } else {
236 em28xx_warn("%i bytes requested from i2c device at "
237 "0x%x, but %i bytes received\n",
238 len, addr, ret);
239 return -EIO;
240 }
241 }
242
243 /* Check success of the i2c operation */
244 ret = dev->em28xx_read_reg(dev, 0x05);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800245 if (ret < 0) {
Frank Schaefer45f04e82013-01-03 14:27:05 -0300246 em28xx_warn("failed to read i2c transfer status from "
247 "bridge (error=%i)\n", ret);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800248 return ret;
249 }
Frank Schaefer45f04e82013-01-03 14:27:05 -0300250 if (ret > 0) {
251 if (ret == 0x10) {
252 return -ENODEV;
253 } else {
254 em28xx_warn("unknown i2c error (status=%i)\n", ret);
255 return -EIO;
256 }
257 }
258 return len;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800259}
260
261/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800262 * em28xx_i2c_check_for_device()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800263 * check if there is a i2c_device at the supplied address
264 */
Frank Schaefera6bad042012-12-16 14:23:27 -0300265static int em28xx_i2c_check_for_device(struct em28xx *dev, u16 addr)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800266{
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800267 int ret;
Frank Schaefer45f04e82013-01-03 14:27:05 -0300268 u8 buf;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800269
Frank Schaefer45f04e82013-01-03 14:27:05 -0300270 ret = em28xx_i2c_recv_bytes(dev, addr, &buf, 1);
271 if (ret == 1)
272 return 0;
273 return (ret < 0) ? ret : -EIO;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800274}
275
276/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800277 * em28xx_i2c_xfer()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800278 * the main i2c transfer function
279 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800280static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800281 struct i2c_msg msgs[], int num)
282{
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800283 struct em28xx *dev = i2c_adap->algo_data;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800284 int addr, rc, i, byte;
285
286 if (num <= 0)
287 return 0;
288 for (i = 0; i < num; i++) {
289 addr = msgs[i].addr << 1;
Frank Schaeferd7a80ea2013-03-03 15:37:35 -0300290 if (i2c_debug >= 2)
291 printk(KERN_DEBUG "%s at %s: %s %s addr=%02x len=%d:",
292 dev->name, __func__ ,
293 (msgs[i].flags & I2C_M_RD) ? "read" : "write",
294 i == num - 1 ? "stop" : "nonstop",
295 addr, msgs[i].len);
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300296 if (!msgs[i].len) { /* no len: check only for device presence */
Mauro Carvalho Chehab505b6d02008-11-25 09:39:50 -0300297 if (dev->board.is_em2800)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800298 rc = em2800_i2c_check_for_device(dev, addr);
299 else
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800300 rc = em28xx_i2c_check_for_device(dev, addr);
Frank Schaefer45f04e82013-01-03 14:27:05 -0300301 if (rc == -ENODEV) {
302 if (i2c_debug >= 2)
303 printk(" no device\n");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800304 return rc;
305 }
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800306 } else if (msgs[i].flags & I2C_M_RD) {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800307 /* read bytes */
Mauro Carvalho Chehab505b6d02008-11-25 09:39:50 -0300308 if (dev->board.is_em2800)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800309 rc = em2800_i2c_recv_bytes(dev, addr,
310 msgs[i].buf,
311 msgs[i].len);
312 else
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800313 rc = em28xx_i2c_recv_bytes(dev, addr,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800314 msgs[i].buf,
315 msgs[i].len);
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300316 if (i2c_debug >= 2) {
317 for (byte = 0; byte < msgs[i].len; byte++)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800318 printk(" %02x", msgs[i].buf[byte]);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800319 }
320 } else {
321 /* write bytes */
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300322 if (i2c_debug >= 2) {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800323 for (byte = 0; byte < msgs[i].len; byte++)
324 printk(" %02x", msgs[i].buf[byte]);
325 }
Mauro Carvalho Chehab505b6d02008-11-25 09:39:50 -0300326 if (dev->board.is_em2800)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800327 rc = em2800_i2c_send_bytes(dev, addr,
328 msgs[i].buf,
329 msgs[i].len);
330 else
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800331 rc = em28xx_i2c_send_bytes(dev, addr,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800332 msgs[i].buf,
333 msgs[i].len,
334 i == num - 1);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800335 }
Frank Schaefer45f04e82013-01-03 14:27:05 -0300336 if (rc < 0) {
337 if (i2c_debug >= 2)
338 printk(" ERROR: %i\n", rc);
339 return rc;
340 }
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300341 if (i2c_debug >= 2)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800342 printk("\n");
343 }
344
345 return num;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800346}
347
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -0300348/* based on linux/sunrpc/svcauth.h and linux/hash.h
349 * The original hash function returns a different value, if arch is x86_64
350 * or i386.
351 */
352static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits)
353{
354 unsigned long hash = 0;
355 unsigned long l = 0;
356 int len = 0;
357 unsigned char c;
358 do {
359 if (len == length) {
360 c = (char)len;
361 len = -1;
362 } else
363 c = *buf++;
364 l = (l << 8) | c;
365 len++;
366 if ((len & (32 / 8 - 1)) == 0)
367 hash = ((hash^l) * 0x9e370001UL);
368 } while (len);
369
370 return (hash >> (32 - bits)) & 0xffffffffUL;
371}
372
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800373static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800374{
375 unsigned char buf, *p = eedata;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800376 struct em28xx_eeprom *em_eeprom = (void *)eedata;
Frank Schaefer90271962013-01-03 14:27:06 -0300377 int i, err, size = len, block, block_max;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800378
Mauro Carvalho Chehabfec528b2011-07-03 21:05:06 -0300379 if (dev->chip_id == CHIP_ID_EM2874 ||
380 dev->chip_id == CHIP_ID_EM28174 ||
381 dev->chip_id == CHIP_ID_EM2884) {
Devin Heitmuellera527c9f2008-11-12 02:05:10 -0300382 /* Empia switched to a 16-bit addressable eeprom in newer
383 devices. While we could certainly write a routine to read
384 the eeprom, there is nothing of use in there that cannot be
385 accessed through registers, and there is the risk that we
386 could corrupt the eeprom (since a 16-bit read call is
387 interpreted as a write call by 8-bit eeproms).
388 */
389 return 0;
390 }
391
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800392 dev->i2c_client.addr = 0xa0 >> 1;
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800393
394 /* Check if board has eeprom */
395 err = i2c_master_recv(&dev->i2c_client, &buf, 0);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300396 if (err < 0) {
Mauro Carvalho Chehabc41109f2008-11-15 23:44:14 -0300397 em28xx_errdev("board has no eeprom\n");
398 memset(eedata, 0, len);
399 return -ENODEV;
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300400 }
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800401
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800402 buf = 0;
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300403
404 err = i2c_master_send(&dev->i2c_client, &buf, 1);
405 if (err != 1) {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800406 printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
407 dev->name, err);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300408 return err;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800409 }
Frank Schaefer90271962013-01-03 14:27:06 -0300410
411 if (dev->board.is_em2800)
412 block_max = 4;
413 else
414 block_max = 64;
415
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800416 while (size > 0) {
Frank Schaefer90271962013-01-03 14:27:06 -0300417 if (size > block_max)
418 block = block_max;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800419 else
420 block = size;
421
422 if (block !=
423 (err = i2c_master_recv(&dev->i2c_client, p, block))) {
424 printk(KERN_WARNING
425 "%s: i2c eeprom read error (err=%d)\n",
426 dev->name, err);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300427 return err;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800428 }
429 size -= block;
430 p += block;
431 }
432 for (i = 0; i < len; i++) {
433 if (0 == (i % 16))
434 printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
435 printk(" %02x", eedata[i]);
436 if (15 == (i % 16))
437 printk("\n");
438 }
439
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -0300440 if (em_eeprom->id == 0x9567eb1a)
441 dev->hash = em28xx_hash_mem(eedata, len, 32);
442
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300443 printk(KERN_INFO "%s: EEPROM ID= 0x%08x, EEPROM hash = 0x%08lx\n",
444 dev->name, em_eeprom->id, dev->hash);
445
446 printk(KERN_INFO "%s: EEPROM info:\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800447
448 switch (em_eeprom->chip_conf >> 4 & 0x3) {
449 case 0:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300450 printk(KERN_INFO "%s:\tNo audio on board.\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800451 break;
452 case 1:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300453 printk(KERN_INFO "%s:\tAC97 audio (5 sample rates)\n",
454 dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800455 break;
456 case 2:
Nicola Soranzoa1a6ee72009-02-10 23:28:24 -0300457 printk(KERN_INFO "%s:\tI2S audio, sample rate=32k\n",
458 dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800459 break;
460 case 3:
Nicola Soranzoa1a6ee72009-02-10 23:28:24 -0300461 printk(KERN_INFO "%s:\tI2S audio, 3 sample rates\n",
462 dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800463 break;
464 }
465
466 if (em_eeprom->chip_conf & 1 << 3)
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300467 printk(KERN_INFO "%s:\tUSB Remote wakeup capable\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800468
469 if (em_eeprom->chip_conf & 1 << 2)
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300470 printk(KERN_INFO "%s:\tUSB Self power capable\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800471
472 switch (em_eeprom->chip_conf & 0x3) {
473 case 0:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300474 printk(KERN_INFO "%s:\t500mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800475 break;
476 case 1:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300477 printk(KERN_INFO "%s:\t400mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800478 break;
479 case 2:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300480 printk(KERN_INFO "%s:\t300mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800481 break;
482 case 3:
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300483 printk(KERN_INFO "%s:\t200mA max power\n", dev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800484 break;
485 }
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300486 printk(KERN_INFO "%s:\tTable at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
487 dev->name,
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300488 em_eeprom->string_idx_table,
489 em_eeprom->string1,
490 em_eeprom->string2,
491 em_eeprom->string3);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800492
493 return 0;
494}
495
496/* ----------------------------------------------------------- */
497
498/*
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800499 * functionality()
500 */
501static u32 functionality(struct i2c_adapter *adap)
502{
Frank Schaefereaf33c42013-01-03 14:27:04 -0300503 struct em28xx *dev = adap->algo_data;
504 u32 func_flags = I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
505 if (dev->board.is_em2800)
506 func_flags &= ~I2C_FUNC_SMBUS_WRITE_BLOCK_DATA;
507 return func_flags;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800508}
509
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800510static struct i2c_algorithm em28xx_algo = {
511 .master_xfer = em28xx_i2c_xfer,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800512 .functionality = functionality,
513};
514
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800515static struct i2c_adapter em28xx_adap_template = {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800516 .owner = THIS_MODULE,
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800517 .name = "em28xx",
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800518 .algo = &em28xx_algo,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800519};
520
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800521static struct i2c_client em28xx_client_template = {
522 .name = "em28xx internal",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800523};
524
525/* ----------------------------------------------------------- */
526
527/*
528 * i2c_devs
529 * incomplete list of known devices
530 */
531static char *i2c_devs[128] = {
Frank Schaefer0b3966e2013-01-13 10:15:08 -0300532 [0x3e >> 1] = "remote IR sensor",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800533 [0x4a >> 1] = "saa7113h",
Martin Blumenstingl729841e2012-06-12 18:19:27 -0300534 [0x52 >> 1] = "drxk",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800535 [0x60 >> 1] = "remote IR sensor",
Markus Rechbergerda45a2a2005-11-08 21:37:31 -0800536 [0x8e >> 1] = "remote IR sensor",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800537 [0x86 >> 1] = "tda9887",
538 [0x80 >> 1] = "msp34xx",
539 [0x88 >> 1] = "msp34xx",
540 [0xa0 >> 1] = "eeprom",
Vitaly Wool2bd1d9e2009-03-04 08:27:52 -0300541 [0xb0 >> 1] = "tda9874",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800542 [0xb8 >> 1] = "tvp5150a",
Mauro Carvalho Chehab791a08f2009-07-03 15:36:18 -0300543 [0xba >> 1] = "webcam sensor or tvp5150a",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800544 [0xc0 >> 1] = "tuner (analog)",
545 [0xc2 >> 1] = "tuner (analog)",
546 [0xc4 >> 1] = "tuner (analog)",
547 [0xc6 >> 1] = "tuner (analog)",
548};
549
550/*
551 * do_i2c_scan()
552 * check i2c address range for devices
553 */
Sascha Sommerfad7b952007-11-04 08:06:48 -0300554void em28xx_do_i2c_scan(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800555{
Sascha Sommerfad7b952007-11-04 08:06:48 -0300556 u8 i2c_devicelist[128];
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800557 unsigned char buf;
558 int i, rc;
559
Sascha Sommerfad7b952007-11-04 08:06:48 -0300560 memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist));
561
Mauro Carvalho Chehab53c4e952007-03-29 08:42:30 -0300562 for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
Sascha Sommerfad7b952007-11-04 08:06:48 -0300563 dev->i2c_client.addr = i;
564 rc = i2c_master_recv(&dev->i2c_client, &buf, 0);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800565 if (rc < 0)
566 continue;
Sascha Sommerfad7b952007-11-04 08:06:48 -0300567 i2c_devicelist[i] = i;
568 printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n",
569 dev->name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800570 }
Sascha Sommerfad7b952007-11-04 08:06:48 -0300571
572 dev->i2c_hash = em28xx_hash_mem(i2c_devicelist,
573 ARRAY_SIZE(i2c_devicelist), 32);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800574}
575
576/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800577 * em28xx_i2c_register()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800578 * register i2c bus
579 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800580int em28xx_i2c_register(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800581{
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300582 int retval;
583
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800584 BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg);
585 BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req);
586 dev->i2c_adap = em28xx_adap_template;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800587 dev->i2c_adap.dev.parent = &dev->udev->dev;
588 strcpy(dev->i2c_adap.name, dev->name);
589 dev->i2c_adap.algo_data = dev;
Douglas Schilling Landgraff2cf2502009-03-31 17:10:58 -0300590 i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300591
592 retval = i2c_add_adapter(&dev->i2c_adap);
593 if (retval < 0) {
594 em28xx_errdev("%s: i2c_add_adapter failed! retval [%d]\n",
595 __func__, retval);
596 return retval;
597 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800598
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800599 dev->i2c_client = em28xx_client_template;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800600 dev->i2c_client.adapter = &dev->i2c_adap;
601
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300602 retval = em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata));
Mauro Carvalho Chehabc41109f2008-11-15 23:44:14 -0300603 if ((retval < 0) && (retval != -ENODEV)) {
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300604 em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n",
605 __func__, retval);
Mauro Carvalho Chehabc41109f2008-11-15 23:44:14 -0300606
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300607 return retval;
608 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800609
610 if (i2c_scan)
Sascha Sommerfad7b952007-11-04 08:06:48 -0300611 em28xx_do_i2c_scan(dev);
Mauro Carvalho Chehabc41109f2008-11-15 23:44:14 -0300612
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800613 return 0;
614}
615
616/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800617 * em28xx_i2c_unregister()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800618 * unregister i2c_bus
619 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800620int em28xx_i2c_unregister(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800621{
622 i2c_del_adapter(&dev->i2c_adap);
623 return 0;
624}