1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28#include <linux/module.h>
29#include <linux/init.h>
30#include <linux/types.h>
31#include <linux/delay.h>
32#include <linux/slab.h>
33#include <linux/wait.h>
34#include <asm/io.h>
35#include <asm/uaccess.h>
36
37MODULE_DESCRIPTION("Philips SAA7110 video decoder driver");
38MODULE_AUTHOR("Pauline Middelink");
39MODULE_LICENSE("GPL");
40
41#include <linux/i2c.h>
42
43#define I2C_NAME(s) (s)->name
44
45#include <linux/videodev.h>
46#include <media/v4l2-common.h>
47#include <linux/video_decoder.h>
48
49static int debug = 0;
50module_param(debug, int, 0);
51MODULE_PARM_DESC(debug, "Debug level (0-1)");
52
53#define dprintk(num, format, args...) \
54 do { \
55 if (debug >= num) \
56 printk(format, ##args); \
57 } while (0)
58
59#define SAA7110_MAX_INPUT 9
60#define SAA7110_MAX_OUTPUT 0
61
62#define I2C_SAA7110 0x9C
63
64#define SAA7110_NR_REG 0x35
65
66struct saa7110 {
67 u8 reg[SAA7110_NR_REG];
68
69 int norm;
70 int input;
71 int enable;
72 int bright;
73 int contrast;
74 int hue;
75 int sat;
76
77 wait_queue_head_t wq;
78};
79
80
81
82
83
84static int
85saa7110_write (struct i2c_client *client,
86 u8 reg,
87 u8 value)
88{
89 struct saa7110 *decoder = i2c_get_clientdata(client);
90
91 decoder->reg[reg] = value;
92 return i2c_smbus_write_byte_data(client, reg, value);
93}
94
95static int
96saa7110_write_block (struct i2c_client *client,
97 const u8 *data,
98 unsigned int len)
99{
100 int ret = -1;
101 u8 reg = *data;
102
103
104 if (reg + (len - 1) > SAA7110_NR_REG)
105 return ret;
106
107
108
109 if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
110 struct saa7110 *decoder = i2c_get_clientdata(client);
111
112 ret = i2c_master_send(client, data, len);
113
114
115 memcpy(decoder->reg + reg, data + 1, len - 1);
116 } else {
117 for (++data, --len; len; len--) {
118 if ((ret = saa7110_write(client, reg++,
119 *data++)) < 0)
120 break;
121 }
122 }
123
124 return ret;
125}
126
127static inline int
128saa7110_read (struct i2c_client *client)
129{
130 return i2c_smbus_read_byte(client);
131}
132
133
134
135
136
137#define FRESP_06H_COMPST 0x03
138#define FRESP_06H_SVIDEO 0x83
139
140
141static int
142saa7110_selmux (struct i2c_client *client,
143 int chan)
144{
145 static const unsigned char modes[9][8] = {
146
147 {FRESP_06H_COMPST, 0xD9, 0x17, 0x40, 0x03,
148 0x44, 0x75, 0x16},
149
150 {FRESP_06H_COMPST, 0xD8, 0x17, 0x40, 0x03,
151 0x44, 0x75, 0x16},
152
153 {FRESP_06H_COMPST, 0xBA, 0x07, 0x91, 0x03,
154 0x60, 0xB5, 0x05},
155
156 {FRESP_06H_COMPST, 0xB8, 0x07, 0x91, 0x03,
157 0x60, 0xB5, 0x05},
158
159 {FRESP_06H_COMPST, 0x7C, 0x07, 0xD2, 0x83,
160 0x60, 0xB5, 0x03},
161
162 {FRESP_06H_COMPST, 0x78, 0x07, 0xD2, 0x83,
163 0x60, 0xB5, 0x03},
164
165 {FRESP_06H_SVIDEO, 0x59, 0x17, 0x42, 0xA3,
166 0x44, 0x75, 0x12},
167
168 {FRESP_06H_SVIDEO, 0x9A, 0x17, 0xB1, 0x13,
169 0x60, 0xB5, 0x14},
170
171 {FRESP_06H_SVIDEO, 0x3C, 0x27, 0xC1, 0x23,
172 0x44, 0x75, 0x21}
173 };
174 struct saa7110 *decoder = i2c_get_clientdata(client);
175 const unsigned char *ptr = modes[chan];
176
177 saa7110_write(client, 0x06, ptr[0]);
178 saa7110_write(client, 0x20, ptr[1]);
179 saa7110_write(client, 0x21, ptr[2]);
180 saa7110_write(client, 0x22, ptr[3]);
181 saa7110_write(client, 0x2C, ptr[4]);
182 saa7110_write(client, 0x30, ptr[5]);
183 saa7110_write(client, 0x31, ptr[6]);
184 saa7110_write(client, 0x21, ptr[7]);
185 decoder->input = chan;
186
187 return 0;
188}
189
190static const unsigned char initseq[1 + SAA7110_NR_REG] = {
191 0, 0x4C, 0x3C, 0x0D, 0xEF, 0xBD, 0xF2, 0x03, 0x00,
192 0xF8, 0xF8, 0x60, 0x60, 0x00, 0x86, 0x18, 0x90,
193 0x00, 0x59, 0x40, 0x46, 0x42, 0x1A, 0xFF, 0xDA,
194 0xF2, 0x8B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
195 0xD9, 0x16, 0x40, 0x41, 0x80, 0x41, 0x80, 0x4F,
196 0xFE, 0x01, 0xCF, 0x0F, 0x03, 0x01, 0x03, 0x0C,
197 0x44, 0x71, 0x02, 0x8C, 0x02
198};
199
200static int
201determine_norm (struct i2c_client *client)
202{
203 DEFINE_WAIT(wait);
204 struct saa7110 *decoder = i2c_get_clientdata(client);
205 int status;
206
207
208 saa7110_write_block(client, initseq, sizeof(initseq));
209 saa7110_selmux(client, decoder->input);
210 prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
211 schedule_timeout(msecs_to_jiffies(250));
212 finish_wait(&decoder->wq, &wait);
213 status = saa7110_read(client);
214 if (status & 0x40) {
215 dprintk(1, KERN_INFO "%s: status=0x%02x (no signal)\n",
216 I2C_NAME(client), status);
217 return decoder->norm;
218 }
219 if ((status & 3) == 0) {
220 saa7110_write(client, 0x06, 0x83);
221 if (status & 0x20) {
222 dprintk(1,
223 KERN_INFO
224 "%s: status=0x%02x (NTSC/no color)\n",
225 I2C_NAME(client), status);
226
227 return VIDEO_MODE_NTSC;
228 }
229 dprintk(1, KERN_INFO "%s: status=0x%02x (PAL/no color)\n",
230 I2C_NAME(client), status);
231
232 return VIDEO_MODE_PAL;
233 }
234
235 if (status & 0x20) {
236 dprintk(1, KERN_INFO "%s: status=0x%02x (NTSC)\n",
237 I2C_NAME(client), status);
238 saa7110_write(client, 0x0D, 0x86);
239 saa7110_write(client, 0x0F, 0x50);
240 saa7110_write(client, 0x11, 0x2C);
241
242 return VIDEO_MODE_NTSC;
243 }
244
245
246 saa7110_write(client, 0x0D, 0x86);
247 saa7110_write(client, 0x0F, 0x10);
248 saa7110_write(client, 0x11, 0x59);
249
250
251 prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
252 schedule_timeout(msecs_to_jiffies(250));
253 finish_wait(&decoder->wq, &wait);
254
255 status = saa7110_read(client);
256 if ((status & 0x03) == 0x01) {
257 dprintk(1, KERN_INFO "%s: status=0x%02x (SECAM)\n",
258 I2C_NAME(client), status);
259 saa7110_write(client, 0x0D, 0x87);
260 return VIDEO_MODE_SECAM;
261 }
262 dprintk(1, KERN_INFO "%s: status=0x%02x (PAL)\n", I2C_NAME(client),
263 status);
264 return VIDEO_MODE_PAL;
265}
266
267static int
268saa7110_command (struct i2c_client *client,
269 unsigned int cmd,
270 void *arg)
271{
272 struct saa7110 *decoder = i2c_get_clientdata(client);
273 int v;
274
275 switch (cmd) {
276 case 0:
277
278 break;
279
280 case DECODER_GET_CAPABILITIES:
281 {
282 struct video_decoder_capability *dc = arg;
283
284 dc->flags =
285 VIDEO_DECODER_PAL | VIDEO_DECODER_NTSC |
286 VIDEO_DECODER_SECAM | VIDEO_DECODER_AUTO;
287 dc->inputs = SAA7110_MAX_INPUT;
288 dc->outputs = SAA7110_MAX_OUTPUT;
289 }
290 break;
291
292 case DECODER_GET_STATUS:
293 {
294 int status;
295 int res = 0;
296
297 status = saa7110_read(client);
298 dprintk(1, KERN_INFO "%s: status=0x%02x norm=%d\n",
299 I2C_NAME(client), status, decoder->norm);
300 if (!(status & 0x40))
301 res |= DECODER_STATUS_GOOD;
302 if (status & 0x03)
303 res |= DECODER_STATUS_COLOR;
304
305 switch (decoder->norm) {
306 case VIDEO_MODE_NTSC:
307 res |= DECODER_STATUS_NTSC;
308 break;
309 case VIDEO_MODE_PAL:
310 res |= DECODER_STATUS_PAL;
311 break;
312 case VIDEO_MODE_SECAM:
313 res |= DECODER_STATUS_SECAM;
314 break;
315 }
316 *(int *) arg = res;
317 }
318 break;
319
320 case DECODER_SET_NORM:
321 v = *(int *) arg;
322 if (decoder->norm != v) {
323 decoder->norm = v;
324
325 switch (v) {
326 case VIDEO_MODE_NTSC:
327 saa7110_write(client, 0x0D, 0x86);
328 saa7110_write(client, 0x0F, 0x50);
329 saa7110_write(client, 0x11, 0x2C);
330
331 dprintk(1,
332 KERN_INFO "%s: switched to NTSC\n",
333 I2C_NAME(client));
334 break;
335 case VIDEO_MODE_PAL:
336 saa7110_write(client, 0x0D, 0x86);
337 saa7110_write(client, 0x0F, 0x10);
338 saa7110_write(client, 0x11, 0x59);
339
340 dprintk(1,
341 KERN_INFO "%s: switched to PAL\n",
342 I2C_NAME(client));
343 break;
344 case VIDEO_MODE_SECAM:
345 saa7110_write(client, 0x0D, 0x87);
346 saa7110_write(client, 0x0F, 0x10);
347 saa7110_write(client, 0x11, 0x59);
348
349 dprintk(1,
350 KERN_INFO
351 "%s: switched to SECAM\n",
352 I2C_NAME(client));
353 break;
354 case VIDEO_MODE_AUTO:
355 dprintk(1,
356 KERN_INFO
357 "%s: TV standard detection...\n",
358 I2C_NAME(client));
359 decoder->norm = determine_norm(client);
360 *(int *) arg = decoder->norm;
361 break;
362 default:
363 return -EPERM;
364 }
365 }
366 break;
367
368 case DECODER_SET_INPUT:
369 v = *(int *) arg;
370 if (v < 0 || v > SAA7110_MAX_INPUT) {
371 dprintk(1,
372 KERN_INFO "%s: input=%d not available\n",
373 I2C_NAME(client), v);
374 return -EINVAL;
375 }
376 if (decoder->input != v) {
377 saa7110_selmux(client, v);
378 dprintk(1, KERN_INFO "%s: switched to input=%d\n",
379 I2C_NAME(client), v);
380 }
381 break;
382
383 case DECODER_SET_OUTPUT:
384 v = *(int *) arg;
385
386 if (v != 0)
387 return -EINVAL;
388 break;
389
390 case DECODER_ENABLE_OUTPUT:
391 v = *(int *) arg;
392 if (decoder->enable != v) {
393 decoder->enable = v;
394 saa7110_write(client, 0x0E, v ? 0x18 : 0x80);
395 dprintk(1, KERN_INFO "%s: YUV %s\n", I2C_NAME(client),
396 v ? "on" : "off");
397 }
398 break;
399
400 case DECODER_SET_PICTURE:
401 {
402 struct video_picture *pic = arg;
403
404 if (decoder->bright != pic->brightness) {
405
406 decoder->bright = pic->brightness;
407 saa7110_write(client, 0x19, decoder->bright >> 8);
408 }
409 if (decoder->contrast != pic->contrast) {
410
411 decoder->contrast = pic->contrast;
412 saa7110_write(client, 0x13,
413 decoder->contrast >> 9);
414 }
415 if (decoder->sat != pic->colour) {
416
417 decoder->sat = pic->colour;
418 saa7110_write(client, 0x12, decoder->sat >> 9);
419 }
420 if (decoder->hue != pic->hue) {
421
422 decoder->hue = pic->hue;
423 saa7110_write(client, 0x07,
424 (decoder->hue >> 8) - 128);
425 }
426 }
427 break;
428
429 case DECODER_DUMP:
430 for (v = 0; v < SAA7110_NR_REG; v += 16) {
431 int j;
432 dprintk(1, KERN_DEBUG "%s: %02x:", I2C_NAME(client),
433 v);
434 for (j = 0; j < 16 && v + j < SAA7110_NR_REG; j++)
435 dprintk(1, " %02x", decoder->reg[v + j]);
436 dprintk(1, "\n");
437 }
438 break;
439
440 default:
441 dprintk(1, KERN_INFO "unknown saa7110_command??(%d)\n",
442 cmd);
443 return -EINVAL;
444 }
445 return 0;
446}
447
448
449
450
451
452
453
454static unsigned short normal_i2c[] = {
455 I2C_SAA7110 >> 1,
456 (I2C_SAA7110 >> 1) + 1,
457 I2C_CLIENT_END
458};
459
460static unsigned short ignore = I2C_CLIENT_END;
461
462static struct i2c_client_address_data addr_data = {
463 .normal_i2c = normal_i2c,
464 .probe = &ignore,
465 .ignore = &ignore,
466};
467
468static struct i2c_driver i2c_driver_saa7110;
469
470static int
471saa7110_detect_client (struct i2c_adapter *adapter,
472 int address,
473 int kind)
474{
475 struct i2c_client *client;
476 struct saa7110 *decoder;
477 int rv;
478
479 dprintk(1,
480 KERN_INFO
481 "saa7110.c: detecting saa7110 client on address 0x%x\n",
482 address << 1);
483
484
485 if (!i2c_check_functionality
486 (adapter,
487 I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
488 return 0;
489
490 client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
491 if (client == 0)
492 return -ENOMEM;
493 client->addr = address;
494 client->adapter = adapter;
495 client->driver = &i2c_driver_saa7110;
496 strlcpy(I2C_NAME(client), "saa7110", sizeof(I2C_NAME(client)));
497
498 decoder = kzalloc(sizeof(struct saa7110), GFP_KERNEL);
499 if (decoder == 0) {
500 kfree(client);
501 return -ENOMEM;
502 }
503 decoder->norm = VIDEO_MODE_PAL;
504 decoder->input = 0;
505 decoder->enable = 1;
506 decoder->bright = 32768;
507 decoder->contrast = 32768;
508 decoder->hue = 32768;
509 decoder->sat = 32768;
510 init_waitqueue_head(&decoder->wq);
511 i2c_set_clientdata(client, decoder);
512
513 rv = i2c_attach_client(client);
514 if (rv) {
515 kfree(client);
516 kfree(decoder);
517 return rv;
518 }
519
520 rv = saa7110_write_block(client, initseq, sizeof(initseq));
521 if (rv < 0)
522 dprintk(1, KERN_ERR "%s_attach: init status %d\n",
523 I2C_NAME(client), rv);
524 else {
525 int ver, status;
526 saa7110_write(client, 0x21, 0x10);
527 saa7110_write(client, 0x0e, 0x18);
528 saa7110_write(client, 0x0D, 0x04);
529 ver = saa7110_read(client);
530 saa7110_write(client, 0x0D, 0x06);
531
532 status = saa7110_read(client);
533 dprintk(1,
534 KERN_INFO
535 "%s_attach: SAA7110A version %x at 0x%02x, status=0x%02x\n",
536 I2C_NAME(client), ver, client->addr << 1, status);
537 saa7110_write(client, 0x0D, 0x86);
538 saa7110_write(client, 0x0F, 0x10);
539 saa7110_write(client, 0x11, 0x59);
540
541 }
542
543
544
545
546
547 return 0;
548}
549
550static int
551saa7110_attach_adapter (struct i2c_adapter *adapter)
552{
553 dprintk(1,
554 KERN_INFO
555 "saa7110.c: starting probe for adapter %s (0x%x)\n",
556 I2C_NAME(adapter), adapter->id);
557 return i2c_probe(adapter, &addr_data, &saa7110_detect_client);
558}
559
560static int
561saa7110_detach_client (struct i2c_client *client)
562{
563 struct saa7110 *decoder = i2c_get_clientdata(client);
564 int err;
565
566 err = i2c_detach_client(client);
567 if (err) {
568 return err;
569 }
570
571 kfree(decoder);
572 kfree(client);
573
574 return 0;
575}
576
577
578
579static struct i2c_driver i2c_driver_saa7110 = {
580 .driver = {
581 .name = "saa7110",
582 },
583
584 .id = I2C_DRIVERID_SAA7110,
585
586 .attach_adapter = saa7110_attach_adapter,
587 .detach_client = saa7110_detach_client,
588 .command = saa7110_command,
589};
590
591static int __init
592saa7110_init (void)
593{
594 return i2c_add_driver(&i2c_driver_saa7110);
595}
596
597static void __exit
598saa7110_exit (void)
599{
600 i2c_del_driver(&i2c_driver_saa7110);
601}
602
603module_init(saa7110_init);
604module_exit(saa7110_exit);
605