blob: ddd2a7964dec25f179fdf7633ffca9ccf690a3cf [file] [log] [blame]
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * 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>
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03009 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 * 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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include <linux/signal.h>
Mauro Carvalho Chehab18f3fa12007-07-02 15:39:57 -030041#include <linux/types.h>
42#include <linux/i2c.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <asm/io.h>
44#include <asm/pgtable.h>
45#include <asm/page.h>
Mauro Carvalho Chehab18f3fa12007-07-02 15:39:57 -030046#include <asm/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
48#include <linux/videodev.h>
Mauro Carvalho Chehab18f3fa12007-07-02 15:39:57 -030049#include <linux/video_decoder.h>
50
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52MODULE_DESCRIPTION("Brooktree-819 video decoder driver");
53MODULE_AUTHOR("Mike Bernson & Dave Perks");
54MODULE_LICENSE("GPL");
55
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
57#define I2C_NAME(s) (s)->name
58
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030060static int debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -070061module_param(debug, int, 0);
62MODULE_PARM_DESC(debug, "Debug level (0-1)");
63
64#define dprintk(num, format, args...) \
65 do { \
66 if (debug >= num) \
67 printk(format, ##args); \
68 } while (0)
69
70/* ----------------------------------------------------------------------- */
71
72struct bt819 {
73 unsigned char reg[32];
74
75 int initialized;
76 int norm;
77 int input;
78 int enable;
79 int bright;
80 int contrast;
81 int hue;
82 int sat;
83};
84
85struct timing {
86 int hactive;
87 int hdelay;
88 int vactive;
89 int vdelay;
90 int hscale;
91 int vscale;
92};
93
94/* for values, see the bt819 datasheet */
95static struct timing timing_data[] = {
96 {864 - 24, 20, 625 - 2, 1, 0x0504, 0x0000},
97 {858 - 24, 20, 525 - 2, 1, 0x00f8, 0x0000},
98};
99
100#define I2C_BT819 0x8a
101
102/* ----------------------------------------------------------------------- */
103
104static inline int
105bt819_write (struct i2c_client *client,
106 u8 reg,
107 u8 value)
108{
109 struct bt819 *decoder = i2c_get_clientdata(client);
110
111 decoder->reg[reg] = value;
112 return i2c_smbus_write_byte_data(client, reg, value);
113}
114
115static inline int
116bt819_setbit (struct i2c_client *client,
117 u8 reg,
118 u8 bit,
119 u8 value)
120{
121 struct bt819 *decoder = i2c_get_clientdata(client);
122
123 return bt819_write(client, reg,
124 (decoder->
125 reg[reg] & ~(1 << bit)) |
126 (value ? (1 << bit) : 0));
127}
128
129static int
130bt819_write_block (struct i2c_client *client,
131 const u8 *data,
132 unsigned int len)
133{
134 int ret = -1;
135 u8 reg;
136
137 /* the bt819 has an autoincrement function, use it if
138 * the adapter understands raw I2C */
139 if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
140 /* do raw I2C, not smbus compatible */
141 struct bt819 *decoder = i2c_get_clientdata(client);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 u8 block_data[32];
Jean Delvare9aa45e32006-03-22 03:48:35 -0300143 int block_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 while (len >= 2) {
Jean Delvare9aa45e32006-03-22 03:48:35 -0300146 block_len = 0;
147 block_data[block_len++] = reg = data[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 do {
Jean Delvare9aa45e32006-03-22 03:48:35 -0300149 block_data[block_len++] =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 decoder->reg[reg++] = data[1];
151 len -= 2;
152 data += 2;
153 } while (len >= 2 && data[0] == reg &&
Jean Delvare9aa45e32006-03-22 03:48:35 -0300154 block_len < 32);
155 if ((ret = i2c_master_send(client, block_data,
156 block_len)) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 break;
158 }
159 } else {
160 /* do some slow I2C emulation kind of thing */
161 while (len >= 2) {
162 reg = *data++;
163 if ((ret = bt819_write(client, reg, *data++)) < 0)
164 break;
165 len -= 2;
166 }
167 }
168
169 return ret;
170}
171
172static inline int
173bt819_read (struct i2c_client *client,
174 u8 reg)
175{
176 return i2c_smbus_read_byte_data(client, reg);
177}
178
179static int
180bt819_init (struct i2c_client *client)
181{
182 struct bt819 *decoder = i2c_get_clientdata(client);
183
184 static unsigned char init[] = {
185 //0x1f, 0x00, /* Reset */
186 0x01, 0x59, /* 0x01 input format */
187 0x02, 0x00, /* 0x02 temporal decimation */
188 0x03, 0x12, /* 0x03 Cropping msb */
189 0x04, 0x16, /* 0x04 Vertical Delay, lsb */
190 0x05, 0xe0, /* 0x05 Vertical Active lsb */
191 0x06, 0x80, /* 0x06 Horizontal Delay lsb */
192 0x07, 0xd0, /* 0x07 Horizontal Active lsb */
193 0x08, 0x00, /* 0x08 Horizontal Scaling msb */
194 0x09, 0xf8, /* 0x09 Horizontal Scaling lsb */
195 0x0a, 0x00, /* 0x0a Brightness control */
196 0x0b, 0x30, /* 0x0b Miscellaneous control */
197 0x0c, 0xd8, /* 0x0c Luma Gain lsb */
198 0x0d, 0xfe, /* 0x0d Chroma Gain (U) lsb */
199 0x0e, 0xb4, /* 0x0e Chroma Gain (V) msb */
200 0x0f, 0x00, /* 0x0f Hue control */
201 0x12, 0x04, /* 0x12 Output Format */
202 0x13, 0x20, /* 0x13 Vertial Scaling msb 0x00
203 chroma comb OFF, line drop scaling, interlace scaling
204 BUG? Why does turning the chroma comb on fuck up color?
205 Bug in the bt819 stepping on my board?
206 */
207 0x14, 0x00, /* 0x14 Vertial Scaling lsb */
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300208 0x16, 0x07, /* 0x16 Video Timing Polarity
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 ACTIVE=active low
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300210 FIELD: high=odd,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 vreset=active high,
212 hreset=active high */
213 0x18, 0x68, /* 0x18 AGC Delay */
214 0x19, 0x5d, /* 0x19 Burst Gate Delay */
215 0x1a, 0x80, /* 0x1a ADC Interface */
216 };
217
218 struct timing *timing = &timing_data[decoder->norm];
219
220 init[0x03 * 2 - 1] =
221 (((timing->vdelay >> 8) & 0x03) << 6) | (((timing->
222 vactive >> 8) &
223 0x03) << 4) |
224 (((timing->hdelay >> 8) & 0x03) << 2) | ((timing->
225 hactive >> 8) &
226 0x03);
227 init[0x04 * 2 - 1] = timing->vdelay & 0xff;
228 init[0x05 * 2 - 1] = timing->vactive & 0xff;
229 init[0x06 * 2 - 1] = timing->hdelay & 0xff;
230 init[0x07 * 2 - 1] = timing->hactive & 0xff;
231 init[0x08 * 2 - 1] = timing->hscale >> 8;
232 init[0x09 * 2 - 1] = timing->hscale & 0xff;
233 /* 0x15 in array is address 0x19 */
234 init[0x15 * 2 - 1] = (decoder->norm == 0) ? 115 : 93; /* Chroma burst delay */
235 /* reset */
236 bt819_write(client, 0x1f, 0x00);
237 mdelay(1);
238
239 /* init */
240 return bt819_write_block(client, init, sizeof(init));
241
242}
243
244/* ----------------------------------------------------------------------- */
245
246static int
247bt819_command (struct i2c_client *client,
248 unsigned int cmd,
249 void *arg)
250{
251 int temp;
252
253 struct bt819 *decoder = i2c_get_clientdata(client);
254
255 if (!decoder->initialized) { // First call to bt819_init could be
256 bt819_init(client); // without #FRST = 0
257 decoder->initialized = 1;
258 }
259
260 switch (cmd) {
261
262 case 0:
263 /* This is just for testing!!! */
264 bt819_init(client);
265 break;
266
267 case DECODER_GET_CAPABILITIES:
268 {
269 struct video_decoder_capability *cap = arg;
270
271 cap->flags = VIDEO_DECODER_PAL |
272 VIDEO_DECODER_NTSC |
273 VIDEO_DECODER_AUTO |
274 VIDEO_DECODER_CCIR;
275 cap->inputs = 8;
276 cap->outputs = 1;
277 }
278 break;
279
280 case DECODER_GET_STATUS:
281 {
282 int *iarg = arg;
283 int status;
284 int res;
285
286 status = bt819_read(client, 0x00);
287 res = 0;
288 if ((status & 0x80)) {
289 res |= DECODER_STATUS_GOOD;
290 }
291 switch (decoder->norm) {
292 case VIDEO_MODE_NTSC:
293 res |= DECODER_STATUS_NTSC;
294 break;
295 case VIDEO_MODE_PAL:
296 res |= DECODER_STATUS_PAL;
297 break;
298 default:
299 case VIDEO_MODE_AUTO:
300 if ((status & 0x10)) {
301 res |= DECODER_STATUS_PAL;
302 } else {
303 res |= DECODER_STATUS_NTSC;
304 }
305 break;
306 }
307 res |= DECODER_STATUS_COLOR;
308 *iarg = res;
309
310 dprintk(1, KERN_INFO "%s: get status %x\n", I2C_NAME(client),
311 *iarg);
312 }
313 break;
314
315 case DECODER_SET_NORM:
316 {
317 int *iarg = arg;
318 struct timing *timing = NULL;
319
320 dprintk(1, KERN_INFO "%s: set norm %x\n", I2C_NAME(client),
321 *iarg);
322
323 switch (*iarg) {
324 case VIDEO_MODE_NTSC:
325 bt819_setbit(client, 0x01, 0, 1);
326 bt819_setbit(client, 0x01, 1, 0);
327 bt819_setbit(client, 0x01, 5, 0);
328 bt819_write(client, 0x18, 0x68);
329 bt819_write(client, 0x19, 0x5d);
330 //bt819_setbit(client, 0x1a, 5, 1);
331 timing = &timing_data[VIDEO_MODE_NTSC];
332 break;
333 case VIDEO_MODE_PAL:
334 bt819_setbit(client, 0x01, 0, 1);
335 bt819_setbit(client, 0x01, 1, 1);
336 bt819_setbit(client, 0x01, 5, 1);
337 bt819_write(client, 0x18, 0x7f);
338 bt819_write(client, 0x19, 0x72);
339 //bt819_setbit(client, 0x1a, 5, 0);
340 timing = &timing_data[VIDEO_MODE_PAL];
341 break;
342 case VIDEO_MODE_AUTO:
343 bt819_setbit(client, 0x01, 0, 0);
344 bt819_setbit(client, 0x01, 1, 0);
345 break;
346 default:
347 dprintk(1,
348 KERN_ERR
349 "%s: unsupported norm %d\n",
350 I2C_NAME(client), *iarg);
351 return -EINVAL;
352 }
353
354 if (timing) {
355 bt819_write(client, 0x03,
356 (((timing->vdelay >> 8) & 0x03) << 6) |
357 (((timing->vactive >> 8) & 0x03) << 4) |
358 (((timing->hdelay >> 8) & 0x03) << 2) |
359 ((timing->hactive >> 8) & 0x03) );
360 bt819_write(client, 0x04, timing->vdelay & 0xff);
361 bt819_write(client, 0x05, timing->vactive & 0xff);
362 bt819_write(client, 0x06, timing->hdelay & 0xff);
363 bt819_write(client, 0x07, timing->hactive & 0xff);
364 bt819_write(client, 0x08, (timing->hscale >> 8) & 0xff);
365 bt819_write(client, 0x09, timing->hscale & 0xff);
366 }
367
368 decoder->norm = *iarg;
369 }
370 break;
371
372 case DECODER_SET_INPUT:
373 {
374 int *iarg = arg;
375
376 dprintk(1, KERN_INFO "%s: set input %x\n", I2C_NAME(client),
377 *iarg);
378
379 if (*iarg < 0 || *iarg > 7) {
380 return -EINVAL;
381 }
382
383 if (decoder->input != *iarg) {
384 decoder->input = *iarg;
385 /* select mode */
386 if (decoder->input == 0) {
387 bt819_setbit(client, 0x0b, 6, 0);
388 bt819_setbit(client, 0x1a, 1, 1);
389 } else {
390 bt819_setbit(client, 0x0b, 6, 1);
391 bt819_setbit(client, 0x1a, 1, 0);
392 }
393 }
394 }
395 break;
396
397 case DECODER_SET_OUTPUT:
398 {
399 int *iarg = arg;
400
401 dprintk(1, KERN_INFO "%s: set output %x\n", I2C_NAME(client),
402 *iarg);
403
404 /* not much choice of outputs */
405 if (*iarg != 0) {
406 return -EINVAL;
407 }
408 }
409 break;
410
411 case DECODER_ENABLE_OUTPUT:
412 {
413 int *iarg = arg;
414 int enable = (*iarg != 0);
415
416 dprintk(1, KERN_INFO "%s: enable output %x\n",
417 I2C_NAME(client), *iarg);
418
419 if (decoder->enable != enable) {
420 decoder->enable = enable;
421
422 if (decoder->enable) {
423 bt819_setbit(client, 0x16, 7, 0);
424 } else {
425 bt819_setbit(client, 0x16, 7, 1);
426 }
427 }
428 }
429 break;
430
431 case DECODER_SET_PICTURE:
432 {
433 struct video_picture *pic = arg;
434
435 dprintk(1,
436 KERN_INFO
437 "%s: set picture brightness %d contrast %d colour %d\n",
438 I2C_NAME(client), pic->brightness, pic->contrast,
439 pic->colour);
440
441
442 if (decoder->bright != pic->brightness) {
443 /* We want -128 to 127 we get 0-65535 */
444 decoder->bright = pic->brightness;
445 bt819_write(client, 0x0a,
446 (decoder->bright >> 8) - 128);
447 }
448
449 if (decoder->contrast != pic->contrast) {
450 /* We want 0 to 511 we get 0-65535 */
451 decoder->contrast = pic->contrast;
452 bt819_write(client, 0x0c,
453 (decoder->contrast >> 7) & 0xff);
454 bt819_setbit(client, 0x0b, 2,
455 ((decoder->contrast >> 15) & 0x01));
456 }
457
458 if (decoder->sat != pic->colour) {
459 /* We want 0 to 511 we get 0-65535 */
460 decoder->sat = pic->colour;
461 bt819_write(client, 0x0d,
462 (decoder->sat >> 7) & 0xff);
463 bt819_setbit(client, 0x0b, 1,
464 ((decoder->sat >> 15) & 0x01));
465
466 temp = (decoder->sat * 201) / 237;
467 bt819_write(client, 0x0e, (temp >> 7) & 0xff);
468 bt819_setbit(client, 0x0b, 0, (temp >> 15) & 0x01);
469 }
470
471 if (decoder->hue != pic->hue) {
472 /* We want -128 to 127 we get 0-65535 */
473 decoder->hue = pic->hue;
474 bt819_write(client, 0x0f,
475 128 - (decoder->hue >> 8));
476 }
477 }
478 break;
479
480 default:
481 return -EINVAL;
482 }
483
484 return 0;
485}
486
487/* ----------------------------------------------------------------------- */
488
489/*
490 * Generic i2c probe
491 * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
492 */
493static unsigned short normal_i2c[] = {
494 I2C_BT819 >> 1,
495 I2C_CLIENT_END,
496};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497
Jean Delvare68cc9d02005-04-02 20:04:41 +0200498static unsigned short ignore = I2C_CLIENT_END;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300499
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500static struct i2c_client_address_data addr_data = {
501 .normal_i2c = normal_i2c,
Jean Delvare68cc9d02005-04-02 20:04:41 +0200502 .probe = &ignore,
503 .ignore = &ignore,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504};
505
506static struct i2c_driver i2c_driver_bt819;
507
508static int
509bt819_detect_client (struct i2c_adapter *adapter,
510 int address,
511 int kind)
512{
513 int i, id;
514 struct bt819 *decoder;
515 struct i2c_client *client;
516
517 dprintk(1,
518 KERN_INFO
Jean Delvare91a1d912008-07-02 16:01:21 -0300519 "bt819: detecting bt819 client on address 0x%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 address << 1);
521
522 /* Check if the adapter supports the needed features */
523 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
524 return 0;
525
Panagiotis Issaris74081872006-01-11 19:40:56 -0200526 client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
Al Viro5fa12472008-03-29 03:07:38 +0000527 if (!client)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 client->addr = address;
530 client->adapter = adapter;
531 client->driver = &i2c_driver_bt819;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532
Panagiotis Issaris74081872006-01-11 19:40:56 -0200533 decoder = kzalloc(sizeof(struct bt819), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 if (decoder == NULL) {
535 kfree(client);
536 return -ENOMEM;
537 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 decoder->norm = VIDEO_MODE_NTSC;
539 decoder->input = 0;
540 decoder->enable = 1;
541 decoder->bright = 32768;
542 decoder->contrast = 32768;
543 decoder->hue = 32768;
544 decoder->sat = 32768;
545 decoder->initialized = 0;
546 i2c_set_clientdata(client, decoder);
547
548 id = bt819_read(client, 0x17);
549 switch (id & 0xf0) {
550 case 0x70:
551 strlcpy(I2C_NAME(client), "bt819a", sizeof(I2C_NAME(client)));
552 break;
553 case 0x60:
554 strlcpy(I2C_NAME(client), "bt817a", sizeof(I2C_NAME(client)));
555 break;
556 case 0x20:
557 strlcpy(I2C_NAME(client), "bt815a", sizeof(I2C_NAME(client)));
558 break;
559 default:
560 dprintk(1,
561 KERN_ERR
562 "bt819: unknown chip version 0x%x (ver 0x%x)\n",
563 id & 0xf0, id & 0x0f);
564 kfree(decoder);
565 kfree(client);
566 return 0;
567 }
568
569 i = i2c_attach_client(client);
570 if (i) {
571 kfree(client);
572 kfree(decoder);
573 return i;
574 }
575
576 i = bt819_init(client);
577 if (i < 0) {
578 dprintk(1, KERN_ERR "%s_attach: init status %d\n",
579 I2C_NAME(client), i);
580 } else {
581 dprintk(1,
582 KERN_INFO
583 "%s_attach: chip version 0x%x at address 0x%x\n",
584 I2C_NAME(client), id & 0x0f,
585 client->addr << 1);
586 }
587
588 return 0;
589}
590
591static int
592bt819_attach_adapter (struct i2c_adapter *adapter)
593{
594 return i2c_probe(adapter, &addr_data, &bt819_detect_client);
595}
596
597static int
598bt819_detach_client (struct i2c_client *client)
599{
600 struct bt819 *decoder = i2c_get_clientdata(client);
601 int err;
602
603 err = i2c_detach_client(client);
604 if (err) {
605 return err;
606 }
607
608 kfree(decoder);
609 kfree(client);
610
611 return 0;
612}
613
614/* ----------------------------------------------------------------------- */
615
616static struct i2c_driver i2c_driver_bt819 = {
Laurent Riffard604f28e2005-11-26 20:43:39 +0100617 .driver = {
Laurent Riffard604f28e2005-11-26 20:43:39 +0100618 .name = "bt819",
619 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620
621 .id = I2C_DRIVERID_BT819,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622
623 .attach_adapter = bt819_attach_adapter,
624 .detach_client = bt819_detach_client,
625 .command = bt819_command,
626};
627
628static int __init
629bt819_init_module (void)
630{
631 return i2c_add_driver(&i2c_driver_bt819);
632}
633
634static void __exit
635bt819_exit (void)
636{
637 i2c_del_driver(&i2c_driver_bt819);
638}
639
640module_init(bt819_init_module);
641module_exit(bt819_exit);