2 * saa7191.c - Philips SAA7191 video decoder driver
4 * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
5 * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
12 #include <linux/delay.h>
13 #include <linux/errno.h>
15 #include <linux/init.h>
16 #include <linux/kernel.h>
17 #include <linux/major.h>
18 #include <linux/module.h>
20 #include <linux/sched.h>
21 #include <linux/slab.h>
23 #include <linux/videodev.h>
24 #include <linux/video_decoder.h>
25 #include <linux/i2c.h>
29 #define SAA7191_MODULE_VERSION "0.0.3"
31 MODULE_DESCRIPTION("Philips SAA7191 video decoder driver");
32 MODULE_VERSION(SAA7191_MODULE_VERSION);
33 MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
34 MODULE_LICENSE("GPL");
37 struct i2c_client *client;
39 /* the register values are stored here as the actual
40 * I2C-registers are write-only */
41 unsigned char reg[25];
47 static struct i2c_driver i2c_driver_saa7191;
49 static const unsigned char initseq[] = {
51 0x50, /* SAA7191_REG_IDEL */
52 0x30, /* SAA7191_REG_HSYB */
53 0x00, /* SAA7191_REG_HSYS */
54 0xe8, /* SAA7191_REG_HCLB */
55 0xb6, /* SAA7191_REG_HCLS */
56 0xf4, /* SAA7191_REG_HPHI */
57 0x01, /* SAA7191_REG_LUMA - chrominance trap active (CVBS) */
58 0x00, /* SAA7191_REG_HUEC */
59 0xf8, /* SAA7191_REG_CKTQ */
60 0xf8, /* SAA7191_REG_CKTS */
61 0x90, /* SAA7191_REG_PLSE */
62 0x90, /* SAA7191_REG_SESE */
63 0x00, /* SAA7191_REG_GAIN */
64 0x0c, /* SAA7191_REG_STDC - not SECAM, slow time constant */
65 0x78, /* SAA7191_REG_IOCK - chrominance from CVBS, GPSW1 & 2 off */
66 0x99, /* SAA7191_REG_CTL3 - automatic field detection */
67 0x00, /* SAA7191_REG_CTL4 */
68 0x2c, /* SAA7191_REG_CHCV */
71 0x34, /* SAA7191_REG_HS6B */
72 0x0a, /* SAA7191_REG_HS6S */
73 0xf4, /* SAA7191_REG_HC6B */
74 0xce, /* SAA7191_REG_HC6S */
75 0xf4, /* SAA7191_REG_HP6I */
78 /* SAA7191 register handling */
80 static unsigned char saa7191_read_reg(struct i2c_client *client,
83 return ((struct saa7191 *)i2c_get_clientdata(client))->reg[reg];
86 static int saa7191_read_status(struct i2c_client *client,
91 ret = i2c_master_recv(client, value, 1);
93 printk(KERN_ERR "SAA7191: saa7191_read_status(): read failed");
101 static int saa7191_write_reg(struct i2c_client *client, unsigned char reg,
105 ((struct saa7191 *)i2c_get_clientdata(client))->reg[reg] = value;
106 return i2c_smbus_write_byte_data(client, reg, value);
109 /* the first byte of data must be the first subaddress number (register) */
110 static int saa7191_write_block(struct i2c_client *client,
111 unsigned char length, unsigned char *data)
116 struct saa7191 *decoder = (struct saa7191 *)i2c_get_clientdata(client);
117 for (i = 0; i < (length - 1); i++) {
118 decoder->reg[data[0] + i] = data[i + 1];
121 ret = i2c_master_send(client, data, length);
123 printk(KERN_ERR "SAA7191: saa7191_write_block(): "
131 /* Helper functions */
133 static int saa7191_set_input(struct i2c_client *client, int input)
135 unsigned char luma = saa7191_read_reg(client, SAA7191_REG_LUMA);
136 unsigned char iock = saa7191_read_reg(client, SAA7191_REG_IOCK);
140 case SAA7191_INPUT_COMPOSITE: /* Set Composite input */
141 iock &= ~(SAA7191_IOCK_CHRS | SAA7191_IOCK_GPSW1
142 | SAA7191_IOCK_GPSW2);
143 /* Chrominance trap active */
144 luma &= ~SAA7191_LUMA_BYPS;
146 case SAA7191_INPUT_SVIDEO: /* Set S-Video input */
147 iock |= SAA7191_IOCK_CHRS | SAA7191_IOCK_GPSW2;
148 /* Chrominance trap bypassed */
149 luma |= SAA7191_LUMA_BYPS;
155 err = saa7191_write_reg(client, SAA7191_REG_LUMA, luma);
158 err = saa7191_write_reg(client, SAA7191_REG_IOCK, iock);
165 static int saa7191_set_norm(struct i2c_client *client, int norm)
167 struct saa7191 *decoder = i2c_get_clientdata(client);
168 unsigned char stdc = saa7191_read_reg(client, SAA7191_REG_STDC);
169 unsigned char ctl3 = saa7191_read_reg(client, SAA7191_REG_CTL3);
170 unsigned char chcv = saa7191_read_reg(client, SAA7191_REG_CHCV);
174 case SAA7191_NORM_AUTO: {
175 unsigned char status;
177 // does status depend on current norm ?
178 if (saa7191_read_status(client, &status))
181 stdc &= ~SAA7191_STDC_SECS;
182 ctl3 &= ~SAA7191_CTL3_FSEL;
183 ctl3 |= SAA7191_CTL3_AUFD;
184 chcv = (status & SAA7191_STATUS_FIDT)
185 ? SAA7191_CHCV_NTSC : SAA7191_CHCV_PAL;
188 case SAA7191_NORM_PAL:
189 stdc &= ~SAA7191_STDC_SECS;
190 ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL);
191 chcv = SAA7191_CHCV_PAL;
193 case SAA7191_NORM_NTSC:
194 stdc &= ~SAA7191_STDC_SECS;
195 ctl3 &= ~SAA7191_CTL3_AUFD;
196 ctl3 |= SAA7191_CTL3_FSEL;
197 chcv = SAA7191_CHCV_NTSC;
199 case SAA7191_NORM_SECAM:
200 stdc |= SAA7191_STDC_SECS;
201 ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL);
202 chcv = SAA7191_CHCV_PAL;
208 err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3);
211 err = saa7191_write_reg(client, SAA7191_REG_STDC, stdc);
214 err = saa7191_write_reg(client, SAA7191_REG_CHCV, chcv);
218 decoder->norm = norm;
223 static int saa7191_get_controls(struct i2c_client *client,
224 struct saa7191_control *ctrl)
226 unsigned char hue = saa7191_read_reg(client, SAA7191_REG_HUEC);
227 unsigned char stdc = saa7191_read_reg(client, SAA7191_REG_STDC);
236 ctrl->vtrc = (stdc & SAA7191_STDC_VTRC)
237 ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED;
242 static int saa7191_set_controls(struct i2c_client *client,
243 struct saa7191_control *ctrl)
247 if (ctrl->hue >= 0) {
248 unsigned char hue = ctrl->hue & 0xff;
254 err = saa7191_write_reg(client, SAA7191_REG_HUEC, hue);
258 if (ctrl->vtrc >= 0) {
260 saa7191_read_reg(client, SAA7191_REG_STDC);
263 stdc |= SAA7191_STDC_VTRC;
265 stdc &= ~SAA7191_STDC_VTRC;
268 err = saa7191_write_reg(client, SAA7191_REG_STDC, stdc);
278 static int saa7191_attach(struct i2c_adapter *adap, int addr, int kind)
281 struct saa7191 *decoder;
282 struct i2c_client *client;
284 printk(KERN_INFO "Philips SAA7191 driver version %s\n",
285 SAA7191_MODULE_VERSION);
287 client = kmalloc(sizeof(*client), GFP_KERNEL);
290 decoder = kmalloc(sizeof(*decoder), GFP_KERNEL);
293 goto out_free_client;
296 memset(client, 0, sizeof(struct i2c_client));
297 memset(decoder, 0, sizeof(struct saa7191));
300 client->adapter = adap;
301 client->driver = &i2c_driver_saa7191;
303 strcpy(client->name, "saa7191 client");
304 i2c_set_clientdata(client, decoder);
306 decoder->client = client;
308 err = i2c_attach_client(client);
310 goto out_free_decoder;
312 decoder->input = SAA7191_INPUT_COMPOSITE;
313 decoder->norm = SAA7191_NORM_AUTO;
315 err = saa7191_write_block(client, sizeof(initseq),
316 (unsigned char *)initseq);
318 printk(KERN_ERR "SAA7191 initialization failed\n");
319 goto out_detach_client;
322 printk(KERN_INFO "SAA7191 initialized\n");
327 i2c_detach_client(client);
335 static int saa7191_probe(struct i2c_adapter *adap)
337 /* Always connected to VINO */
338 if (adap->id == I2C_HW_SGI_VINO)
339 return saa7191_attach(adap, SAA7191_ADDR, 0);
340 /* Feel free to add probe here :-) */
344 static int saa7191_detach(struct i2c_client *client)
346 struct saa7191 *decoder = i2c_get_clientdata(client);
348 i2c_detach_client(client);
354 static int saa7191_command(struct i2c_client *client, unsigned int cmd,
357 struct saa7191 *decoder = i2c_get_clientdata(client);
360 case DECODER_GET_CAPABILITIES: {
361 struct video_decoder_capability *cap = arg;
363 cap->flags = VIDEO_DECODER_PAL | VIDEO_DECODER_NTSC |
364 VIDEO_DECODER_SECAM | VIDEO_DECODER_AUTO;
365 cap->inputs = (client->adapter->id == I2C_HW_SGI_VINO) ? 2 : 1;
369 case DECODER_GET_STATUS: {
371 unsigned char status;
374 if (saa7191_read_status(client, &status)) {
377 if ((status & SAA7191_STATUS_HLCK) == 0)
378 res |= DECODER_STATUS_GOOD;
379 if (status & SAA7191_STATUS_CODE)
380 res |= DECODER_STATUS_COLOR;
381 switch (decoder->norm) {
382 case SAA7191_NORM_NTSC:
383 res |= DECODER_STATUS_NTSC;
385 case SAA7191_NORM_PAL:
386 res |= DECODER_STATUS_PAL;
388 case SAA7191_NORM_SECAM:
389 res |= DECODER_STATUS_SECAM;
391 case SAA7191_NORM_AUTO:
393 if (status & SAA7191_STATUS_FIDT)
394 res |= DECODER_STATUS_NTSC;
396 res |= DECODER_STATUS_PAL;
402 case DECODER_SET_NORM: {
406 case VIDEO_MODE_AUTO:
407 return saa7191_set_norm(client, SAA7191_NORM_AUTO);
409 return saa7191_set_norm(client, SAA7191_NORM_PAL);
410 case VIDEO_MODE_NTSC:
411 return saa7191_set_norm(client, SAA7191_NORM_NTSC);
412 case VIDEO_MODE_SECAM:
413 return saa7191_set_norm(client, SAA7191_NORM_SECAM);
419 case DECODER_SET_INPUT: {
422 switch (client->adapter->id) {
423 case I2C_HW_SGI_VINO:
424 return saa7191_set_input(client, *iarg);
431 case DECODER_SET_OUTPUT: {
434 /* not much choice of outputs */
439 case DECODER_ENABLE_OUTPUT: {
443 case DECODER_SET_PICTURE: {
444 struct video_picture *pic = arg;
448 val = (pic->hue >> 8) - 0x80;
449 err = saa7191_write_reg(client, SAA7191_REG_HUEC, val);
454 case DECODER_SAA7191_GET_STATUS: {
455 struct saa7191_status *status = arg;
456 unsigned char status_reg;
458 if (saa7191_read_status(client, &status_reg))
460 status->signal = ((status_reg & SAA7191_STATUS_HLCK) == 0)
461 ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED;
462 status->ntsc = (status_reg & SAA7191_STATUS_FIDT)
463 ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED;
464 status->color = (status_reg & SAA7191_STATUS_CODE)
465 ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED;
467 status->input = decoder->input;
468 status->norm = decoder->norm;
470 case DECODER_SAA7191_SET_NORM: {
472 return saa7191_set_norm(client, *norm);
474 case DECODER_SAA7191_GET_CONTROLS: {
475 struct saa7191_control *ctrl = arg;
476 return saa7191_get_controls(client, ctrl);
478 case DECODER_SAA7191_SET_CONTROLS: {
479 struct saa7191_control *ctrl = arg;
480 return saa7191_set_controls(client, ctrl);
489 static struct i2c_driver i2c_driver_saa7191 = {
490 .owner = THIS_MODULE,
492 .id = I2C_DRIVERID_SAA7191,
493 .flags = I2C_DF_NOTIFY,
494 .attach_adapter = saa7191_probe,
495 .detach_client = saa7191_detach,
496 .command = saa7191_command
499 static int saa7191_init(void)
501 return i2c_add_driver(&i2c_driver_saa7191);
504 static void saa7191_exit(void)
506 i2c_del_driver(&i2c_driver_saa7191);
509 module_init(saa7191_init);
510 module_exit(saa7191_exit);