diff options
author | akpm@osdl.org <akpm@osdl.org> | 2005-11-09 00:37:07 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-09 10:56:15 -0500 |
commit | a6c2ba283565dbc9f055dcb2ecba1971460bb535 (patch) | |
tree | fd262f8af5bffc99753ff861be85574616113467 /drivers/media/video/em28xx/em28xx-i2c.c | |
parent | 4b017415fc9ab63f7c0e49aced5e403c18d55659 (diff) |
[PATCH] v4l: 716: support for em28xx board family
- Added support for em28xx board family
Signed-off-by: Ludovico Cavedon <cavedon@sssup.it>
Signed-off-by: Markus Rechberger <mrechberger@gmail.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/media/video/em28xx/em28xx-i2c.c')
-rw-r--r-- | drivers/media/video/em28xx/em28xx-i2c.c | 443 |
1 files changed, 443 insertions, 0 deletions
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c new file mode 100644 index 000000000000..95f80a7615bd --- /dev/null +++ b/drivers/media/video/em28xx/em28xx-i2c.c | |||
@@ -0,0 +1,443 @@ | |||
1 | /* | ||
2 | em2820-i2c.c - driver for Empia EM2820/2840 USB video capture devices | ||
3 | |||
4 | Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com> | ||
5 | Ludovico Cavedon <cavedon@sssup.it> | ||
6 | Mauro Carvalho Chehab <mchehab@brturbo.com.br> | ||
7 | |||
8 | Based on the em2800 driver from Sascha Sommer <saschasommer@freenet.de> | ||
9 | |||
10 | This program is free software; you can redistribute it and/or modify | ||
11 | it under the terms of the GNU General Public License as published by | ||
12 | the Free Software Foundation; either version 2 of the License, or | ||
13 | (at your option) any later version. | ||
14 | |||
15 | This program is distributed in the hope that it will be useful, | ||
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | GNU General Public License for more details. | ||
19 | |||
20 | You should have received a copy of the GNU General Public License | ||
21 | along with this program; if not, write to the Free Software | ||
22 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
23 | */ | ||
24 | |||
25 | #include <linux/module.h> | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/usb.h> | ||
28 | #include <linux/i2c.h> | ||
29 | #include <linux/videodev.h> | ||
30 | #include <media/tuner.h> | ||
31 | #include <linux/video_decoder.h> | ||
32 | |||
33 | /* To be moved to compat.h */ | ||
34 | #if !defined(I2C_HW_B_EM2820) | ||
35 | #define I2C_HW_B_EM2820 I2C_HW_B_BT848 | ||
36 | #endif | ||
37 | |||
38 | #include "em2820.h" | ||
39 | |||
40 | /* ----------------------------------------------------------- */ | ||
41 | |||
42 | static unsigned int i2c_scan = 0; | ||
43 | module_param(i2c_scan, int, 0444); | ||
44 | MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); | ||
45 | |||
46 | static unsigned int i2c_debug = 0; | ||
47 | module_param(i2c_debug, int, 0644); | ||
48 | MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); | ||
49 | |||
50 | #define dprintk(fmt, args...) if (i2c_debug) do {\ | ||
51 | printk(KERN_DEBUG "%s: %s: " fmt "\n",\ | ||
52 | dev->name, __FUNCTION__ , ##args); } while (0) | ||
53 | #define dprintk1(fmt, args...) if (i2c_debug) do{ \ | ||
54 | printk(KERN_DEBUG "%s: %s: " fmt, \ | ||
55 | dev->name, __FUNCTION__ , ##args); } while (0) | ||
56 | #define dprintk2(fmt, args...) if (i2c_debug) do {\ | ||
57 | printk(fmt , ##args); } while (0) | ||
58 | |||
59 | /* | ||
60 | * i2c_send_bytes() | ||
61 | * untested for more than 4 bytes | ||
62 | */ | ||
63 | static int i2c_send_bytes(void *data, unsigned char addr, char *buf, short len, | ||
64 | int stop) | ||
65 | { | ||
66 | int wrcount = 0; | ||
67 | struct em2820 *dev = (struct em2820 *)data; | ||
68 | |||
69 | wrcount = dev->em2820_write_regs_req(dev, stop ? 2 : 3, addr, buf, len); | ||
70 | |||
71 | return wrcount; | ||
72 | } | ||
73 | |||
74 | /* | ||
75 | * i2c_recv_byte() | ||
76 | * read a byte from the i2c device | ||
77 | */ | ||
78 | static int i2c_recv_bytes(struct em2820 *dev, unsigned char addr, char *buf, | ||
79 | int len) | ||
80 | { | ||
81 | int ret; | ||
82 | ret = dev->em2820_read_reg_req_len(dev, 2, addr, buf, len); | ||
83 | if (ret < 0) { | ||
84 | em2820_warn("reading i2c device failed (error=%i)\n", ret); | ||
85 | return ret; | ||
86 | } | ||
87 | if (dev->em2820_read_reg(dev, 0x5) != 0) | ||
88 | return -ENODEV; | ||
89 | return ret; | ||
90 | } | ||
91 | |||
92 | /* | ||
93 | * i2c_check_for_device() | ||
94 | * check if there is a i2c_device at the supplied address | ||
95 | */ | ||
96 | static int i2c_check_for_device(struct em2820 *dev, unsigned char addr) | ||
97 | { | ||
98 | char msg; | ||
99 | int ret; | ||
100 | msg = addr; | ||
101 | |||
102 | ret = dev->em2820_read_reg_req(dev, 2, addr); | ||
103 | if (ret < 0) { | ||
104 | em2820_warn("reading from i2c device failed (error=%i)\n", ret); | ||
105 | return ret; | ||
106 | } | ||
107 | if (dev->em2820_read_reg(dev, 0x5) != 0) | ||
108 | return -ENODEV; | ||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | /* | ||
113 | * em2820_i2c_xfer() | ||
114 | * the main i2c transfer function | ||
115 | */ | ||
116 | static int em2820_i2c_xfer(struct i2c_adapter *i2c_adap, | ||
117 | struct i2c_msg msgs[], int num) | ||
118 | { | ||
119 | struct em2820 *dev = i2c_adap->algo_data; | ||
120 | int addr, rc, i, byte; | ||
121 | |||
122 | if (num <= 0) | ||
123 | return 0; | ||
124 | for (i = 0; i < num; i++) { | ||
125 | addr = msgs[i].addr << 1; | ||
126 | dprintk1("%s %s addr=%x len=%d:", | ||
127 | (msgs[i].flags & I2C_M_RD) ? "read" : "write", | ||
128 | i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len); | ||
129 | if (!msgs[i].len) { /* no len: check only for device presence */ | ||
130 | rc = i2c_check_for_device(dev, addr); | ||
131 | if (rc < 0) { | ||
132 | dprintk2(" no device\n"); | ||
133 | return rc; | ||
134 | } | ||
135 | |||
136 | } | ||
137 | if (msgs[i].flags & I2C_M_RD) { | ||
138 | /* read bytes */ | ||
139 | |||
140 | rc = i2c_recv_bytes(dev, addr, msgs[i].buf, | ||
141 | msgs[i].len); | ||
142 | if (i2c_debug) { | ||
143 | for (byte = 0; byte < msgs[i].len; byte++) { | ||
144 | printk(" %02x", msgs[i].buf[byte]); | ||
145 | } | ||
146 | } | ||
147 | } else { | ||
148 | /* write bytes */ | ||
149 | if (i2c_debug) { | ||
150 | for (byte = 0; byte < msgs[i].len; byte++) | ||
151 | printk(" %02x", msgs[i].buf[byte]); | ||
152 | } | ||
153 | rc = i2c_send_bytes(dev, addr, msgs[i].buf, msgs[i].len, | ||
154 | i == num - 1); | ||
155 | if (rc < 0) | ||
156 | goto err; | ||
157 | } | ||
158 | if (i2c_debug) | ||
159 | printk("\n"); | ||
160 | } | ||
161 | |||
162 | return num; | ||
163 | err: | ||
164 | dprintk2(" ERROR: %i\n", rc); | ||
165 | return rc; | ||
166 | } | ||
167 | |||
168 | static int em2820_i2c_eeprom(struct em2820 *dev, unsigned char *eedata, int len) | ||
169 | { | ||
170 | unsigned char buf, *p = eedata; | ||
171 | struct em2820_eeprom *em_eeprom = (void *)eedata; | ||
172 | int i, err, size = len, block; | ||
173 | |||
174 | dev->i2c_client.addr = 0xa0 >> 1; | ||
175 | buf = 0; | ||
176 | if (1 != (err = i2c_master_send(&dev->i2c_client, &buf, 1))) { | ||
177 | printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n", | ||
178 | dev->name, err); | ||
179 | return -1; | ||
180 | } | ||
181 | while (size > 0) { | ||
182 | if (size > 16) | ||
183 | block = 16; | ||
184 | else | ||
185 | block = size; | ||
186 | |||
187 | if (block != | ||
188 | (err = i2c_master_recv(&dev->i2c_client, p, block))) { | ||
189 | printk(KERN_WARNING | ||
190 | "%s: i2c eeprom read error (err=%d)\n", | ||
191 | dev->name, err); | ||
192 | return -1; | ||
193 | } | ||
194 | size -= block; | ||
195 | p += block; | ||
196 | } | ||
197 | for (i = 0; i < len; i++) { | ||
198 | if (0 == (i % 16)) | ||
199 | printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i); | ||
200 | printk(" %02x", eedata[i]); | ||
201 | if (15 == (i % 16)) | ||
202 | printk("\n"); | ||
203 | } | ||
204 | |||
205 | printk(KERN_INFO "EEPROM ID= 0x%08x\n", em_eeprom->id); | ||
206 | printk(KERN_INFO "Vendor/Product ID= %04x:%04x\n", em_eeprom->vendor_ID, | ||
207 | em_eeprom->product_ID); | ||
208 | |||
209 | switch (em_eeprom->chip_conf >> 4 & 0x3) { | ||
210 | case 0: | ||
211 | printk(KERN_INFO "No audio on board.\n"); | ||
212 | break; | ||
213 | case 1: | ||
214 | printk(KERN_INFO "AC97 audio (5 sample rates)\n"); | ||
215 | break; | ||
216 | case 2: | ||
217 | printk(KERN_INFO "I2S audio, sample rate=32k\n"); | ||
218 | break; | ||
219 | case 3: | ||
220 | printk(KERN_INFO "I2S audio, 3 sample rates\n"); | ||
221 | break; | ||
222 | } | ||
223 | |||
224 | if (em_eeprom->chip_conf & 1 << 3) | ||
225 | printk(KERN_INFO "USB Remote wakeup capable\n"); | ||
226 | |||
227 | if (em_eeprom->chip_conf & 1 << 2) | ||
228 | printk(KERN_INFO "USB Self power capable\n"); | ||
229 | |||
230 | switch (em_eeprom->chip_conf & 0x3) { | ||
231 | case 0: | ||
232 | printk(KERN_INFO "500mA max power\n"); | ||
233 | break; | ||
234 | case 1: | ||
235 | printk(KERN_INFO "400mA max power\n"); | ||
236 | break; | ||
237 | case 2: | ||
238 | printk(KERN_INFO "300mA max power\n"); | ||
239 | break; | ||
240 | case 3: | ||
241 | printk(KERN_INFO "200mA max power\n"); | ||
242 | break; | ||
243 | } | ||
244 | |||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | /* ----------------------------------------------------------- */ | ||
249 | |||
250 | /* | ||
251 | * algo_control() | ||
252 | */ | ||
253 | static int algo_control(struct i2c_adapter *adapter, | ||
254 | unsigned int cmd, unsigned long arg) | ||
255 | { | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | /* | ||
260 | * functionality() | ||
261 | */ | ||
262 | static u32 functionality(struct i2c_adapter *adap) | ||
263 | { | ||
264 | return I2C_FUNC_SMBUS_EMUL; | ||
265 | } | ||
266 | |||
267 | #ifndef I2C_PEC | ||
268 | static void inc_use(struct i2c_adapter *adap) | ||
269 | { | ||
270 | MOD_INC_USE_COUNT; | ||
271 | } | ||
272 | |||
273 | static void dec_use(struct i2c_adapter *adap) | ||
274 | { | ||
275 | MOD_DEC_USE_COUNT; | ||
276 | } | ||
277 | #endif | ||
278 | |||
279 | static int em2820_set_tuner(int check_eeprom, struct i2c_client *client) | ||
280 | { | ||
281 | struct em2820 *dev = client->adapter->algo_data; | ||
282 | |||
283 | struct tuner_setup tun_setup; | ||
284 | |||
285 | /* tuner */ | ||
286 | if (dev->has_tuner) { | ||
287 | tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; | ||
288 | tun_setup.type = dev->tuner_type; | ||
289 | tun_setup.addr = dev->tuner_addr; | ||
290 | |||
291 | em2820_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); | ||
292 | } | ||
293 | return (0); | ||
294 | } | ||
295 | |||
296 | /* | ||
297 | * attach_inform() | ||
298 | * gets called when a device attaches to the i2c bus | ||
299 | * does some basic configuration | ||
300 | */ | ||
301 | static int attach_inform(struct i2c_client *client) | ||
302 | { | ||
303 | struct em2820 *dev = client->adapter->algo_data; | ||
304 | |||
305 | dprintk("address %x", client->addr << 1); | ||
306 | switch (client->addr << 1) { | ||
307 | case 0x68: | ||
308 | em2820_i2c_call_clients(dev, TDA9887_SET_CONFIG, &dev->tda9887_conf); | ||
309 | break; | ||
310 | case 0x4a: | ||
311 | dprintk1("attach_inform: saa7113 detected.\n"); | ||
312 | break; | ||
313 | case 0xa0: | ||
314 | dprintk1("attach_inform: eeprom detected.\n"); | ||
315 | break; | ||
316 | case 0x80: | ||
317 | case 0x88: | ||
318 | dprintk1("attach_inform: msp34xx detected.\n"); | ||
319 | break; | ||
320 | case 0xb8: | ||
321 | case 0xba: | ||
322 | dprintk1("attach_inform: tvp5150 detected.\n"); | ||
323 | break; | ||
324 | default: | ||
325 | dev->tuner_addr = client->addr; | ||
326 | em2820_set_tuner(-1, client); | ||
327 | } | ||
328 | |||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | static struct i2c_algorithm em2820_algo = { | ||
333 | .name = "em2820", | ||
334 | .id = I2C_HW_B_EM2820, | ||
335 | .master_xfer = em2820_i2c_xfer, | ||
336 | .algo_control = algo_control, | ||
337 | .functionality = functionality, | ||
338 | }; | ||
339 | |||
340 | static struct i2c_adapter em2820_adap_template = { | ||
341 | #ifdef I2C_PEC | ||
342 | .owner = THIS_MODULE, | ||
343 | #else | ||
344 | .inc_use = inc_use, | ||
345 | .dec_use = dec_use, | ||
346 | #endif | ||
347 | #ifdef I2C_CLASS_TV_ANALOG | ||
348 | .class = I2C_CLASS_TV_ANALOG, | ||
349 | #endif | ||
350 | .name = "em2820", | ||
351 | .id = I2C_HW_B_EM2820, | ||
352 | .algo = &em2820_algo, | ||
353 | .client_register = attach_inform, | ||
354 | }; | ||
355 | |||
356 | static struct i2c_client em2820_client_template = { | ||
357 | .name = "em2820 internal", | ||
358 | .flags = I2C_CLIENT_ALLOW_USE, | ||
359 | }; | ||
360 | |||
361 | /* ----------------------------------------------------------- */ | ||
362 | |||
363 | /* | ||
364 | * i2c_devs | ||
365 | * incomplete list of known devices | ||
366 | */ | ||
367 | static char *i2c_devs[128] = { | ||
368 | [0x4a >> 1] = "saa7113h", | ||
369 | [0x60 >> 1] = "remote IR sensor", | ||
370 | [0x86 >> 1] = "tda9887", | ||
371 | [0x80 >> 1] = "msp34xx", | ||
372 | [0x88 >> 1] = "msp34xx", | ||
373 | [0xa0 >> 1] = "eeprom", | ||
374 | [0xb8 >> 1] = "tvp5150a", | ||
375 | [0xba >> 1] = "tvp5150a", | ||
376 | [0xc0 >> 1] = "tuner (analog)", | ||
377 | [0xc2 >> 1] = "tuner (analog)", | ||
378 | [0xc4 >> 1] = "tuner (analog)", | ||
379 | [0xc6 >> 1] = "tuner (analog)", | ||
380 | }; | ||
381 | |||
382 | /* | ||
383 | * do_i2c_scan() | ||
384 | * check i2c address range for devices | ||
385 | */ | ||
386 | static void do_i2c_scan(char *name, struct i2c_client *c) | ||
387 | { | ||
388 | unsigned char buf; | ||
389 | int i, rc; | ||
390 | |||
391 | for (i = 0; i < 128; i++) { | ||
392 | c->addr = i; | ||
393 | rc = i2c_master_recv(c, &buf, 0); | ||
394 | if (rc < 0) | ||
395 | continue; | ||
396 | printk(KERN_INFO "%s: found device @ 0x%x [%s]", name, | ||
397 | i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); | ||
398 | } | ||
399 | } | ||
400 | |||
401 | /* | ||
402 | * em2820_i2c_call_clients() | ||
403 | * send commands to all attached i2c devices | ||
404 | */ | ||
405 | void em2820_i2c_call_clients(struct em2820 *dev, unsigned int cmd, void *arg) | ||
406 | { | ||
407 | BUG_ON(NULL == dev->i2c_adap.algo_data); | ||
408 | i2c_clients_command(&dev->i2c_adap, cmd, arg); | ||
409 | } | ||
410 | |||
411 | /* | ||
412 | * em2820_i2c_register() | ||
413 | * register i2c bus | ||
414 | */ | ||
415 | int em2820_i2c_register(struct em2820 *dev) | ||
416 | { | ||
417 | BUG_ON(!dev->em2820_write_regs || !dev->em2820_read_reg); | ||
418 | BUG_ON(!dev->em2820_write_regs_req || !dev->em2820_read_reg_req); | ||
419 | dev->i2c_adap = em2820_adap_template; | ||
420 | dev->i2c_adap.dev.parent = &dev->udev->dev; | ||
421 | strcpy(dev->i2c_adap.name, dev->name); | ||
422 | dev->i2c_adap.algo_data = dev; | ||
423 | i2c_add_adapter(&dev->i2c_adap); | ||
424 | |||
425 | dev->i2c_client = em2820_client_template; | ||
426 | dev->i2c_client.adapter = &dev->i2c_adap; | ||
427 | |||
428 | em2820_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata)); | ||
429 | |||
430 | if (i2c_scan) | ||
431 | do_i2c_scan(dev->name, &dev->i2c_client); | ||
432 | return 0; | ||
433 | } | ||
434 | |||
435 | /* | ||
436 | * em2820_i2c_unregister() | ||
437 | * unregister i2c_bus | ||
438 | */ | ||
439 | int em2820_i2c_unregister(struct em2820 *dev) | ||
440 | { | ||
441 | i2c_del_adapter(&dev->i2c_adap); | ||
442 | return 0; | ||
443 | } | ||