aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/bt819.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/bt819.c')
-rw-r--r--drivers/media/video/bt819.c660
1 files changed, 660 insertions, 0 deletions
diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c
new file mode 100644
index 000000000000..cf0db2554a80
--- /dev/null
+++ b/drivers/media/video/bt819.c
@@ -0,0 +1,660 @@
1/*
2 * bt819 - BT819A VideoStream Decoder (Rockwell Part)
3 *
4 * Copyright (C) 1999 Mike Bernson <mike@mlb.org>
5 * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
6 *
7 * Modifications for LML33/DC10plus unified driver
8 * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
9 *
10 * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
11 * - moved over to linux>=2.4.x i2c protocol (9/9/2002)
12 *
13 * This code was modify/ported from the saa7111 driver written
14 * by Dave Perks.
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 */
30
31#include <linux/module.h>
32#include <linux/init.h>
33#include <linux/delay.h>
34#include <linux/errno.h>
35#include <linux/fs.h>
36#include <linux/kernel.h>
37#include <linux/major.h>
38#include <linux/slab.h>
39#include <linux/mm.h>
40#include <linux/pci.h>
41#include <linux/signal.h>
42#include <asm/io.h>
43#include <asm/pgtable.h>
44#include <asm/page.h>
45#include <linux/sched.h>
46#include <asm/segment.h>
47#include <linux/types.h>
48
49#include <linux/videodev.h>
50#include <asm/uaccess.h>
51
52MODULE_DESCRIPTION("Brooktree-819 video decoder driver");
53MODULE_AUTHOR("Mike Bernson & Dave Perks");
54MODULE_LICENSE("GPL");
55
56#include <linux/i2c.h>
57#include <linux/i2c-dev.h>
58
59#define I2C_NAME(s) (s)->name
60
61#include <linux/video_decoder.h>
62
63static int debug = 0;
64module_param(debug, int, 0);
65MODULE_PARM_DESC(debug, "Debug level (0-1)");
66
67#define dprintk(num, format, args...) \
68 do { \
69 if (debug >= num) \
70 printk(format, ##args); \
71 } while (0)
72
73/* ----------------------------------------------------------------------- */
74
75struct bt819 {
76 unsigned char reg[32];
77
78 int initialized;
79 int norm;
80 int input;
81 int enable;
82 int bright;
83 int contrast;
84 int hue;
85 int sat;
86};
87
88struct timing {
89 int hactive;
90 int hdelay;
91 int vactive;
92 int vdelay;
93 int hscale;
94 int vscale;
95};
96
97/* for values, see the bt819 datasheet */
98static struct timing timing_data[] = {
99 {864 - 24, 20, 625 - 2, 1, 0x0504, 0x0000},
100 {858 - 24, 20, 525 - 2, 1, 0x00f8, 0x0000},
101};
102
103#define I2C_BT819 0x8a
104
105/* ----------------------------------------------------------------------- */
106
107static inline int
108bt819_write (struct i2c_client *client,
109 u8 reg,
110 u8 value)
111{
112 struct bt819 *decoder = i2c_get_clientdata(client);
113
114 decoder->reg[reg] = value;
115 return i2c_smbus_write_byte_data(client, reg, value);
116}
117
118static inline int
119bt819_setbit (struct i2c_client *client,
120 u8 reg,
121 u8 bit,
122 u8 value)
123{
124 struct bt819 *decoder = i2c_get_clientdata(client);
125
126 return bt819_write(client, reg,
127 (decoder->
128 reg[reg] & ~(1 << bit)) |
129 (value ? (1 << bit) : 0));
130}
131
132static int
133bt819_write_block (struct i2c_client *client,
134 const u8 *data,
135 unsigned int len)
136{
137 int ret = -1;
138 u8 reg;
139
140 /* the bt819 has an autoincrement function, use it if
141 * the adapter understands raw I2C */
142 if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
143 /* do raw I2C, not smbus compatible */
144 struct bt819 *decoder = i2c_get_clientdata(client);
145 struct i2c_msg msg;
146 u8 block_data[32];
147
148 msg.addr = client->addr;
149 msg.flags = 0;
150 while (len >= 2) {
151 msg.buf = (char *) block_data;
152 msg.len = 0;
153 block_data[msg.len++] = reg = data[0];
154 do {
155 block_data[msg.len++] =
156 decoder->reg[reg++] = data[1];
157 len -= 2;
158 data += 2;
159 } while (len >= 2 && data[0] == reg &&
160 msg.len < 32);
161 if ((ret = i2c_transfer(client->adapter,
162 &msg, 1)) < 0)
163 break;
164 }
165 } else {
166 /* do some slow I2C emulation kind of thing */
167 while (len >= 2) {
168 reg = *data++;
169 if ((ret = bt819_write(client, reg, *data++)) < 0)
170 break;
171 len -= 2;
172 }
173 }
174
175 return ret;
176}
177
178static inline int
179bt819_read (struct i2c_client *client,
180 u8 reg)
181{
182 return i2c_smbus_read_byte_data(client, reg);
183}
184
185static int
186bt819_init (struct i2c_client *client)
187{
188 struct bt819 *decoder = i2c_get_clientdata(client);
189
190 static unsigned char init[] = {
191 //0x1f, 0x00, /* Reset */
192 0x01, 0x59, /* 0x01 input format */
193 0x02, 0x00, /* 0x02 temporal decimation */
194 0x03, 0x12, /* 0x03 Cropping msb */
195 0x04, 0x16, /* 0x04 Vertical Delay, lsb */
196 0x05, 0xe0, /* 0x05 Vertical Active lsb */
197 0x06, 0x80, /* 0x06 Horizontal Delay lsb */
198 0x07, 0xd0, /* 0x07 Horizontal Active lsb */
199 0x08, 0x00, /* 0x08 Horizontal Scaling msb */
200 0x09, 0xf8, /* 0x09 Horizontal Scaling lsb */
201 0x0a, 0x00, /* 0x0a Brightness control */
202 0x0b, 0x30, /* 0x0b Miscellaneous control */
203 0x0c, 0xd8, /* 0x0c Luma Gain lsb */
204 0x0d, 0xfe, /* 0x0d Chroma Gain (U) lsb */
205 0x0e, 0xb4, /* 0x0e Chroma Gain (V) msb */
206 0x0f, 0x00, /* 0x0f Hue control */
207 0x12, 0x04, /* 0x12 Output Format */
208 0x13, 0x20, /* 0x13 Vertial Scaling msb 0x00
209 chroma comb OFF, line drop scaling, interlace scaling
210 BUG? Why does turning the chroma comb on fuck up color?
211 Bug in the bt819 stepping on my board?
212 */
213 0x14, 0x00, /* 0x14 Vertial Scaling lsb */
214 0x16, 0x07, /* 0x16 Video Timing Polarity
215 ACTIVE=active low
216 FIELD: high=odd,
217 vreset=active high,
218 hreset=active high */
219 0x18, 0x68, /* 0x18 AGC Delay */
220 0x19, 0x5d, /* 0x19 Burst Gate Delay */
221 0x1a, 0x80, /* 0x1a ADC Interface */
222 };
223
224 struct timing *timing = &timing_data[decoder->norm];
225
226 init[0x03 * 2 - 1] =
227 (((timing->vdelay >> 8) & 0x03) << 6) | (((timing->
228 vactive >> 8) &
229 0x03) << 4) |
230 (((timing->hdelay >> 8) & 0x03) << 2) | ((timing->
231 hactive >> 8) &
232 0x03);
233 init[0x04 * 2 - 1] = timing->vdelay & 0xff;
234 init[0x05 * 2 - 1] = timing->vactive & 0xff;
235 init[0x06 * 2 - 1] = timing->hdelay & 0xff;
236 init[0x07 * 2 - 1] = timing->hactive & 0xff;
237 init[0x08 * 2 - 1] = timing->hscale >> 8;
238 init[0x09 * 2 - 1] = timing->hscale & 0xff;
239 /* 0x15 in array is address 0x19 */
240 init[0x15 * 2 - 1] = (decoder->norm == 0) ? 115 : 93; /* Chroma burst delay */
241 /* reset */
242 bt819_write(client, 0x1f, 0x00);
243 mdelay(1);
244
245 /* init */
246 return bt819_write_block(client, init, sizeof(init));
247
248}
249
250/* ----------------------------------------------------------------------- */
251
252static int
253bt819_command (struct i2c_client *client,
254 unsigned int cmd,
255 void *arg)
256{
257 int temp;
258
259 struct bt819 *decoder = i2c_get_clientdata(client);
260
261 if (!decoder->initialized) { // First call to bt819_init could be
262 bt819_init(client); // without #FRST = 0
263 decoder->initialized = 1;
264 }
265
266 switch (cmd) {
267
268 case 0:
269 /* This is just for testing!!! */
270 bt819_init(client);
271 break;
272
273 case DECODER_GET_CAPABILITIES:
274 {
275 struct video_decoder_capability *cap = arg;
276
277 cap->flags = VIDEO_DECODER_PAL |
278 VIDEO_DECODER_NTSC |
279 VIDEO_DECODER_AUTO |
280 VIDEO_DECODER_CCIR;
281 cap->inputs = 8;
282 cap->outputs = 1;
283 }
284 break;
285
286 case DECODER_GET_STATUS:
287 {
288 int *iarg = arg;
289 int status;
290 int res;
291
292 status = bt819_read(client, 0x00);
293 res = 0;
294 if ((status & 0x80)) {
295 res |= DECODER_STATUS_GOOD;
296 }
297 switch (decoder->norm) {
298 case VIDEO_MODE_NTSC:
299 res |= DECODER_STATUS_NTSC;
300 break;
301 case VIDEO_MODE_PAL:
302 res |= DECODER_STATUS_PAL;
303 break;
304 default:
305 case VIDEO_MODE_AUTO:
306 if ((status & 0x10)) {
307 res |= DECODER_STATUS_PAL;
308 } else {
309 res |= DECODER_STATUS_NTSC;
310 }
311 break;
312 }
313 res |= DECODER_STATUS_COLOR;
314 *iarg = res;
315
316 dprintk(1, KERN_INFO "%s: get status %x\n", I2C_NAME(client),
317 *iarg);
318 }
319 break;
320
321 case DECODER_SET_NORM:
322 {
323 int *iarg = arg;
324 struct timing *timing = NULL;
325
326 dprintk(1, KERN_INFO "%s: set norm %x\n", I2C_NAME(client),
327 *iarg);
328
329 switch (*iarg) {
330 case VIDEO_MODE_NTSC:
331 bt819_setbit(client, 0x01, 0, 1);
332 bt819_setbit(client, 0x01, 1, 0);
333 bt819_setbit(client, 0x01, 5, 0);
334 bt819_write(client, 0x18, 0x68);
335 bt819_write(client, 0x19, 0x5d);
336 //bt819_setbit(client, 0x1a, 5, 1);
337 timing = &timing_data[VIDEO_MODE_NTSC];
338 break;
339 case VIDEO_MODE_PAL:
340 bt819_setbit(client, 0x01, 0, 1);
341 bt819_setbit(client, 0x01, 1, 1);
342 bt819_setbit(client, 0x01, 5, 1);
343 bt819_write(client, 0x18, 0x7f);
344 bt819_write(client, 0x19, 0x72);
345 //bt819_setbit(client, 0x1a, 5, 0);
346 timing = &timing_data[VIDEO_MODE_PAL];
347 break;
348 case VIDEO_MODE_AUTO:
349 bt819_setbit(client, 0x01, 0, 0);
350 bt819_setbit(client, 0x01, 1, 0);
351 break;
352 default:
353 dprintk(1,
354 KERN_ERR
355 "%s: unsupported norm %d\n",
356 I2C_NAME(client), *iarg);
357 return -EINVAL;
358 }
359
360 if (timing) {
361 bt819_write(client, 0x03,
362 (((timing->vdelay >> 8) & 0x03) << 6) |
363 (((timing->vactive >> 8) & 0x03) << 4) |
364 (((timing->hdelay >> 8) & 0x03) << 2) |
365 ((timing->hactive >> 8) & 0x03) );
366 bt819_write(client, 0x04, timing->vdelay & 0xff);
367 bt819_write(client, 0x05, timing->vactive & 0xff);
368 bt819_write(client, 0x06, timing->hdelay & 0xff);
369 bt819_write(client, 0x07, timing->hactive & 0xff);
370 bt819_write(client, 0x08, (timing->hscale >> 8) & 0xff);
371 bt819_write(client, 0x09, timing->hscale & 0xff);
372 }
373
374 decoder->norm = *iarg;
375 }
376 break;
377
378 case DECODER_SET_INPUT:
379 {
380 int *iarg = arg;
381
382 dprintk(1, KERN_INFO "%s: set input %x\n", I2C_NAME(client),
383 *iarg);
384
385 if (*iarg < 0 || *iarg > 7) {
386 return -EINVAL;
387 }
388
389 if (decoder->input != *iarg) {
390 decoder->input = *iarg;
391 /* select mode */
392 if (decoder->input == 0) {
393 bt819_setbit(client, 0x0b, 6, 0);
394 bt819_setbit(client, 0x1a, 1, 1);
395 } else {
396 bt819_setbit(client, 0x0b, 6, 1);
397 bt819_setbit(client, 0x1a, 1, 0);
398 }
399 }
400 }
401 break;
402
403 case DECODER_SET_OUTPUT:
404 {
405 int *iarg = arg;
406
407 dprintk(1, KERN_INFO "%s: set output %x\n", I2C_NAME(client),
408 *iarg);
409
410 /* not much choice of outputs */
411 if (*iarg != 0) {
412 return -EINVAL;
413 }
414 }
415 break;
416
417 case DECODER_ENABLE_OUTPUT:
418 {
419 int *iarg = arg;
420 int enable = (*iarg != 0);
421
422 dprintk(1, KERN_INFO "%s: enable output %x\n",
423 I2C_NAME(client), *iarg);
424
425 if (decoder->enable != enable) {
426 decoder->enable = enable;
427
428 if (decoder->enable) {
429 bt819_setbit(client, 0x16, 7, 0);
430 } else {
431 bt819_setbit(client, 0x16, 7, 1);
432 }
433 }
434 }
435 break;
436
437 case DECODER_SET_PICTURE:
438 {
439 struct video_picture *pic = arg;
440
441 dprintk(1,
442 KERN_INFO
443 "%s: set picture brightness %d contrast %d colour %d\n",
444 I2C_NAME(client), pic->brightness, pic->contrast,
445 pic->colour);
446
447
448 if (decoder->bright != pic->brightness) {
449 /* We want -128 to 127 we get 0-65535 */
450 decoder->bright = pic->brightness;
451 bt819_write(client, 0x0a,
452 (decoder->bright >> 8) - 128);
453 }
454
455 if (decoder->contrast != pic->contrast) {
456 /* We want 0 to 511 we get 0-65535 */
457 decoder->contrast = pic->contrast;
458 bt819_write(client, 0x0c,
459 (decoder->contrast >> 7) & 0xff);
460 bt819_setbit(client, 0x0b, 2,
461 ((decoder->contrast >> 15) & 0x01));
462 }
463
464 if (decoder->sat != pic->colour) {
465 /* We want 0 to 511 we get 0-65535 */
466 decoder->sat = pic->colour;
467 bt819_write(client, 0x0d,
468 (decoder->sat >> 7) & 0xff);
469 bt819_setbit(client, 0x0b, 1,
470 ((decoder->sat >> 15) & 0x01));
471
472 temp = (decoder->sat * 201) / 237;
473 bt819_write(client, 0x0e, (temp >> 7) & 0xff);
474 bt819_setbit(client, 0x0b, 0, (temp >> 15) & 0x01);
475 }
476
477 if (decoder->hue != pic->hue) {
478 /* We want -128 to 127 we get 0-65535 */
479 decoder->hue = pic->hue;
480 bt819_write(client, 0x0f,
481 128 - (decoder->hue >> 8));
482 }
483 }
484 break;
485
486 default:
487 return -EINVAL;
488 }
489
490 return 0;
491}
492
493/* ----------------------------------------------------------------------- */
494
495/*
496 * Generic i2c probe
497 * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
498 */
499static unsigned short normal_i2c[] = {
500 I2C_BT819 >> 1,
501 I2C_CLIENT_END,
502};
503static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
504
505static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
506static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
507static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
508static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
509static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
510
511static struct i2c_client_address_data addr_data = {
512 .normal_i2c = normal_i2c,
513 .normal_i2c_range = normal_i2c_range,
514 .probe = probe,
515 .probe_range = probe_range,
516 .ignore = ignore,
517 .ignore_range = ignore_range,
518 .force = force
519};
520
521static struct i2c_driver i2c_driver_bt819;
522
523static int
524bt819_detect_client (struct i2c_adapter *adapter,
525 int address,
526 int kind)
527{
528 int i, id;
529 struct bt819 *decoder;
530 struct i2c_client *client;
531
532 dprintk(1,
533 KERN_INFO
534 "saa7111.c: detecting bt819 client on address 0x%x\n",
535 address << 1);
536
537 /* Check if the adapter supports the needed features */
538 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
539 return 0;
540
541 client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
542 if (client == 0)
543 return -ENOMEM;
544 memset(client, 0, sizeof(struct i2c_client));
545 client->addr = address;
546 client->adapter = adapter;
547 client->driver = &i2c_driver_bt819;
548 client->flags = I2C_CLIENT_ALLOW_USE;
549
550 decoder = kmalloc(sizeof(struct bt819), GFP_KERNEL);
551 if (decoder == NULL) {
552 kfree(client);
553 return -ENOMEM;
554 }
555
556 memset(decoder, 0, sizeof(struct bt819));
557 decoder->norm = VIDEO_MODE_NTSC;
558 decoder->input = 0;
559 decoder->enable = 1;
560 decoder->bright = 32768;
561 decoder->contrast = 32768;
562 decoder->hue = 32768;
563 decoder->sat = 32768;
564 decoder->initialized = 0;
565 i2c_set_clientdata(client, decoder);
566
567 id = bt819_read(client, 0x17);
568 switch (id & 0xf0) {
569 case 0x70:
570 strlcpy(I2C_NAME(client), "bt819a", sizeof(I2C_NAME(client)));
571 break;
572 case 0x60:
573 strlcpy(I2C_NAME(client), "bt817a", sizeof(I2C_NAME(client)));
574 break;
575 case 0x20:
576 strlcpy(I2C_NAME(client), "bt815a", sizeof(I2C_NAME(client)));
577 break;
578 default:
579 dprintk(1,
580 KERN_ERR
581 "bt819: unknown chip version 0x%x (ver 0x%x)\n",
582 id & 0xf0, id & 0x0f);
583 kfree(decoder);
584 kfree(client);
585 return 0;
586 }
587
588 i = i2c_attach_client(client);
589 if (i) {
590 kfree(client);
591 kfree(decoder);
592 return i;
593 }
594
595 i = bt819_init(client);
596 if (i < 0) {
597 dprintk(1, KERN_ERR "%s_attach: init status %d\n",
598 I2C_NAME(client), i);
599 } else {
600 dprintk(1,
601 KERN_INFO
602 "%s_attach: chip version 0x%x at address 0x%x\n",
603 I2C_NAME(client), id & 0x0f,
604 client->addr << 1);
605 }
606
607 return 0;
608}
609
610static int
611bt819_attach_adapter (struct i2c_adapter *adapter)
612{
613 return i2c_probe(adapter, &addr_data, &bt819_detect_client);
614}
615
616static int
617bt819_detach_client (struct i2c_client *client)
618{
619 struct bt819 *decoder = i2c_get_clientdata(client);
620 int err;
621
622 err = i2c_detach_client(client);
623 if (err) {
624 return err;
625 }
626
627 kfree(decoder);
628 kfree(client);
629
630 return 0;
631}
632
633/* ----------------------------------------------------------------------- */
634
635static struct i2c_driver i2c_driver_bt819 = {
636 .owner = THIS_MODULE,
637 .name = "bt819",
638
639 .id = I2C_DRIVERID_BT819,
640 .flags = I2C_DF_NOTIFY,
641
642 .attach_adapter = bt819_attach_adapter,
643 .detach_client = bt819_detach_client,
644 .command = bt819_command,
645};
646
647static int __init
648bt819_init_module (void)
649{
650 return i2c_add_driver(&i2c_driver_bt819);
651}
652
653static void __exit
654bt819_exit (void)
655{
656 i2c_del_driver(&i2c_driver_bt819);
657}
658
659module_init(bt819_init_module);
660module_exit(bt819_exit);