blob: b8a9bee836fafbfc1c8255c104ca4d82ea291271 [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 Schaeferd90f0672013-03-03 15:37:36 -0300290 if (i2c_debug)
Frank Schaeferd7a80ea2013-03-03 15:37:35 -0300291 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) {
Frank Schaeferd90f0672013-03-03 15:37:36 -0300302 if (i2c_debug)
Frank Schaefer45f04e82013-01-03 14:27:05 -0300303 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);
Frank Schaeferd90f0672013-03-03 15:37:36 -0300316 if (i2c_debug) {
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300317 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 */
Frank Schaeferd90f0672013-03-03 15:37:36 -0300322 if (i2c_debug) {
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) {
Frank Schaeferd90f0672013-03-03 15:37:36 -0300337 if (i2c_debug)
Frank Schaefer45f04e82013-01-03 14:27:05 -0300338 printk(" ERROR: %i\n", rc);
339 return rc;
340 }
Frank Schaeferd90f0672013-03-03 15:37:36 -0300341 if (i2c_debug)
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) {
Frank Schaefer12d7ce12013-03-03 15:37:34 -0300397 em28xx_info("board has no eeprom\n");
Mauro Carvalho Chehabc41109f2008-11-15 23:44:14 -0300398 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) {
Frank Schaefer12d7ce12013-03-03 15:37:34 -0300406 em28xx_errdev("failed to read eeprom (err=%d)\n", err);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300407 return err;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800408 }
Frank Schaefer90271962013-01-03 14:27:06 -0300409
410 if (dev->board.is_em2800)
411 block_max = 4;
412 else
413 block_max = 64;
414
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800415 while (size > 0) {
Frank Schaefer90271962013-01-03 14:27:06 -0300416 if (size > block_max)
417 block = block_max;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800418 else
419 block = size;
420
421 if (block !=
422 (err = i2c_master_recv(&dev->i2c_client, p, block))) {
Frank Schaefer12d7ce12013-03-03 15:37:34 -0300423 em28xx_errdev("i2c eeprom read error (err=%d)\n", err);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300424 return err;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800425 }
426 size -= block;
427 p += block;
428 }
429 for (i = 0; i < len; i++) {
430 if (0 == (i % 16))
Frank Schaefer12d7ce12013-03-03 15:37:34 -0300431 em28xx_info("i2c eeprom %02x:", i);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800432 printk(" %02x", eedata[i]);
433 if (15 == (i % 16))
434 printk("\n");
435 }
436
Frank Schaeferf55eacb2013-03-03 15:37:37 -0300437 if (em_eeprom->id != 0x9567eb1a) {
438 em28xx_errdev("Unknown eeprom type or eeprom corrupted !");
439 return -ENODEV;
440 }
441
442 dev->hash = em28xx_hash_mem(eedata, len, 32);
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -0300443
Frank Schaefer12d7ce12013-03-03 15:37:34 -0300444 em28xx_info("EEPROM ID = 0x%08x, EEPROM hash = 0x%08lx\n",
445 em_eeprom->id, dev->hash);
Mauro Carvalho Chehab1bee0182008-11-25 10:06:21 -0300446
Frank Schaefer12d7ce12013-03-03 15:37:34 -0300447 em28xx_info("EEPROM info:\n");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800448
449 switch (em_eeprom->chip_conf >> 4 & 0x3) {
450 case 0:
Frank Schaefer12d7ce12013-03-03 15:37:34 -0300451 em28xx_info("\tNo audio on board.\n");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800452 break;
453 case 1:
Frank Schaefer12d7ce12013-03-03 15:37:34 -0300454 em28xx_info("\tAC97 audio (5 sample rates)\n");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800455 break;
456 case 2:
Frank Schaefer12d7ce12013-03-03 15:37:34 -0300457 em28xx_info("\tI2S audio, sample rate=32k\n");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800458 break;
459 case 3:
Frank Schaefer12d7ce12013-03-03 15:37:34 -0300460 em28xx_info("\tI2S audio, 3 sample rates\n");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800461 break;
462 }
463
464 if (em_eeprom->chip_conf & 1 << 3)
Frank Schaefer12d7ce12013-03-03 15:37:34 -0300465 em28xx_info("\tUSB Remote wakeup capable\n");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800466
467 if (em_eeprom->chip_conf & 1 << 2)
Frank Schaefer12d7ce12013-03-03 15:37:34 -0300468 em28xx_info("\tUSB Self power capable\n");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800469
470 switch (em_eeprom->chip_conf & 0x3) {
471 case 0:
Frank Schaefer12d7ce12013-03-03 15:37:34 -0300472 em28xx_info("\t500mA max power\n");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800473 break;
474 case 1:
Frank Schaefer12d7ce12013-03-03 15:37:34 -0300475 em28xx_info("\t400mA max power\n");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800476 break;
477 case 2:
Frank Schaefer12d7ce12013-03-03 15:37:34 -0300478 em28xx_info("\t300mA max power\n");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800479 break;
480 case 3:
Frank Schaefer12d7ce12013-03-03 15:37:34 -0300481 em28xx_info("\t200mA max power\n");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800482 break;
483 }
Frank Schaefer12d7ce12013-03-03 15:37:34 -0300484 em28xx_info("\tTable at offset 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
485 em_eeprom->string_idx_table,
486 em_eeprom->string1,
487 em_eeprom->string2,
488 em_eeprom->string3);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800489
490 return 0;
491}
492
493/* ----------------------------------------------------------- */
494
495/*
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800496 * functionality()
497 */
498static u32 functionality(struct i2c_adapter *adap)
499{
Frank Schaefereaf33c42013-01-03 14:27:04 -0300500 struct em28xx *dev = adap->algo_data;
501 u32 func_flags = I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
502 if (dev->board.is_em2800)
503 func_flags &= ~I2C_FUNC_SMBUS_WRITE_BLOCK_DATA;
504 return func_flags;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800505}
506
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800507static struct i2c_algorithm em28xx_algo = {
508 .master_xfer = em28xx_i2c_xfer,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800509 .functionality = functionality,
510};
511
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800512static struct i2c_adapter em28xx_adap_template = {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800513 .owner = THIS_MODULE,
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800514 .name = "em28xx",
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800515 .algo = &em28xx_algo,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800516};
517
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800518static struct i2c_client em28xx_client_template = {
519 .name = "em28xx internal",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800520};
521
522/* ----------------------------------------------------------- */
523
524/*
525 * i2c_devs
526 * incomplete list of known devices
527 */
528static char *i2c_devs[128] = {
Frank Schaefer0b3966e2013-01-13 10:15:08 -0300529 [0x3e >> 1] = "remote IR sensor",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800530 [0x4a >> 1] = "saa7113h",
Martin Blumenstingl729841e2012-06-12 18:19:27 -0300531 [0x52 >> 1] = "drxk",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800532 [0x60 >> 1] = "remote IR sensor",
Markus Rechbergerda45a2a2005-11-08 21:37:31 -0800533 [0x8e >> 1] = "remote IR sensor",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800534 [0x86 >> 1] = "tda9887",
535 [0x80 >> 1] = "msp34xx",
536 [0x88 >> 1] = "msp34xx",
537 [0xa0 >> 1] = "eeprom",
Vitaly Wool2bd1d9eb2009-03-04 08:27:52 -0300538 [0xb0 >> 1] = "tda9874",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800539 [0xb8 >> 1] = "tvp5150a",
Mauro Carvalho Chehab791a08f2009-07-03 15:36:18 -0300540 [0xba >> 1] = "webcam sensor or tvp5150a",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800541 [0xc0 >> 1] = "tuner (analog)",
542 [0xc2 >> 1] = "tuner (analog)",
543 [0xc4 >> 1] = "tuner (analog)",
544 [0xc6 >> 1] = "tuner (analog)",
545};
546
547/*
548 * do_i2c_scan()
549 * check i2c address range for devices
550 */
Sascha Sommerfad7b952007-11-04 08:06:48 -0300551void em28xx_do_i2c_scan(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800552{
Sascha Sommerfad7b952007-11-04 08:06:48 -0300553 u8 i2c_devicelist[128];
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800554 unsigned char buf;
555 int i, rc;
556
Sascha Sommerfad7b952007-11-04 08:06:48 -0300557 memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist));
558
Mauro Carvalho Chehab53c4e952007-03-29 08:42:30 -0300559 for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
Sascha Sommerfad7b952007-11-04 08:06:48 -0300560 dev->i2c_client.addr = i;
561 rc = i2c_master_recv(&dev->i2c_client, &buf, 0);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800562 if (rc < 0)
563 continue;
Sascha Sommerfad7b952007-11-04 08:06:48 -0300564 i2c_devicelist[i] = i;
Frank Schaefer12d7ce12013-03-03 15:37:34 -0300565 em28xx_info("found i2c device @ 0x%x [%s]\n",
566 i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800567 }
Sascha Sommerfad7b952007-11-04 08:06:48 -0300568
569 dev->i2c_hash = em28xx_hash_mem(i2c_devicelist,
570 ARRAY_SIZE(i2c_devicelist), 32);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800571}
572
573/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800574 * em28xx_i2c_register()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800575 * register i2c bus
576 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800577int em28xx_i2c_register(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800578{
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300579 int retval;
580
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800581 BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg);
582 BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req);
583 dev->i2c_adap = em28xx_adap_template;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800584 dev->i2c_adap.dev.parent = &dev->udev->dev;
585 strcpy(dev->i2c_adap.name, dev->name);
586 dev->i2c_adap.algo_data = dev;
Douglas Schilling Landgraff2cf2502009-03-31 17:10:58 -0300587 i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300588
589 retval = i2c_add_adapter(&dev->i2c_adap);
590 if (retval < 0) {
591 em28xx_errdev("%s: i2c_add_adapter failed! retval [%d]\n",
592 __func__, retval);
593 return retval;
594 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800595
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800596 dev->i2c_client = em28xx_client_template;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800597 dev->i2c_client.adapter = &dev->i2c_adap;
598
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300599 retval = em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata));
Mauro Carvalho Chehabc41109f2008-11-15 23:44:14 -0300600 if ((retval < 0) && (retval != -ENODEV)) {
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300601 em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n",
602 __func__, retval);
Mauro Carvalho Chehabc41109f2008-11-15 23:44:14 -0300603
Douglas Schilling Landgraff2a01a02008-09-08 03:27:20 -0300604 return retval;
605 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800606
607 if (i2c_scan)
Sascha Sommerfad7b952007-11-04 08:06:48 -0300608 em28xx_do_i2c_scan(dev);
Mauro Carvalho Chehabc41109f2008-11-15 23:44:14 -0300609
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800610 return 0;
611}
612
613/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800614 * em28xx_i2c_unregister()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800615 * unregister i2c_bus
616 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800617int em28xx_i2c_unregister(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800618{
619 i2c_del_adapter(&dev->i2c_adap);
620 return 0;
621}