2 saa7110 - Philips SAA7110(A) video decoder driver
4 Copyright (C) 1998 Pauline Middelink <middelin@polyware.nl>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include <linux/module.h>
22 #include <linux/init.h>
23 #include <linux/types.h>
24 #include <linux/delay.h>
25 #include <linux/slab.h>
27 #include <asm/uaccess.h>
29 #include <linux/i2c-old.h>
30 #include <linux/videodev.h>
31 #include "linux/video_decoder.h"
33 #define DEBUG(x...) /* remove when no long debugging */
35 #define SAA7110_MAX_INPUT 9 /* 6 CVBS, 3 SVHS */
36 #define SAA7110_MAX_OUTPUT 0 /* its a decoder only */
38 #define I2C_SAA7110 0x9C /* or 0x9E */
40 #define I2C_DELAY 10 /* 10 us or 100khz */
45 unsigned char reg[36];
56 /* ----------------------------------------------------------------------- */
57 /* I2C support functions */
58 /* ----------------------------------------------------------------------- */
60 int saa7110_write(struct saa7110 *decoder, unsigned char subaddr, unsigned char data)
64 LOCK_I2C_BUS(decoder->bus);
65 i2c_start(decoder->bus);
66 i2c_sendbyte(decoder->bus, decoder->addr, I2C_DELAY);
67 i2c_sendbyte(decoder->bus, subaddr, I2C_DELAY);
68 ack = i2c_sendbyte(decoder->bus, data, I2C_DELAY);
69 i2c_stop(decoder->bus);
70 decoder->reg[subaddr] = data;
71 UNLOCK_I2C_BUS(decoder->bus);
76 int saa7110_write_block(struct saa7110* decoder, unsigned const char *data, unsigned int len)
78 unsigned subaddr = *data;
80 LOCK_I2C_BUS(decoder->bus);
81 i2c_start(decoder->bus);
82 i2c_sendbyte(decoder->bus,decoder->addr,I2C_DELAY);
84 if (i2c_sendbyte(decoder->bus,*data,0)) {
85 i2c_stop(decoder->bus);
86 UNLOCK_I2C_BUS(decoder->bus);
89 decoder->reg[subaddr++] = *data++;
91 i2c_stop(decoder->bus);
92 UNLOCK_I2C_BUS(decoder->bus);
98 int saa7110_read(struct saa7110* decoder)
102 LOCK_I2C_BUS(decoder->bus);
103 i2c_start(decoder->bus);
104 i2c_sendbyte(decoder->bus, decoder->addr, I2C_DELAY);
105 i2c_start(decoder->bus);
106 i2c_sendbyte(decoder->bus, decoder->addr | 1, I2C_DELAY);
107 data = i2c_readbyte(decoder->bus, 1);
108 i2c_stop(decoder->bus);
109 UNLOCK_I2C_BUS(decoder->bus);
113 /* ----------------------------------------------------------------------- */
114 /* SAA7110 functions */
115 /* ----------------------------------------------------------------------- */
117 int saa7110_selmux(struct i2c_device *device, int chan)
119 static const unsigned char modes[9][8] = {
120 /* mode 0 */ { 0x00, 0xD9, 0x17, 0x40, 0x03, 0x44, 0x75, 0x16 },
121 /* mode 1 */ { 0x00, 0xD8, 0x17, 0x40, 0x03, 0x44, 0x75, 0x16 },
122 /* mode 2 */ { 0x00, 0xBA, 0x07, 0x91, 0x03, 0x60, 0xB5, 0x05 },
123 /* mode 3 */ { 0x00, 0xB8, 0x07, 0x91, 0x03, 0x60, 0xB5, 0x05 },
124 /* mode 4 */ { 0x00, 0x7C, 0x07, 0xD2, 0x83, 0x60, 0xB5, 0x03 },
125 /* mode 5 */ { 0x00, 0x78, 0x07, 0xD2, 0x83, 0x60, 0xB5, 0x03 },
126 /* mode 6 */ { 0x80, 0x59, 0x17, 0x42, 0xA3, 0x44, 0x75, 0x12 },
127 /* mode 7 */ { 0x80, 0x9A, 0x17, 0xB1, 0x13, 0x60, 0xB5, 0x14 },
128 /* mode 8 */ { 0x80, 0x3C, 0x27, 0xC1, 0x23, 0x44, 0x75, 0x21 } };
129 struct saa7110* decoder = device->data;
130 const unsigned char* ptr = modes[chan];
132 saa7110_write(decoder,0x06,ptr[0]); /* Luminance control */
133 saa7110_write(decoder,0x20,ptr[1]); /* Analog Control #1 */
134 saa7110_write(decoder,0x21,ptr[2]); /* Analog Control #2 */
135 saa7110_write(decoder,0x22,ptr[3]); /* Mixer Control #1 */
136 saa7110_write(decoder,0x2C,ptr[4]); /* Mixer Control #2 */
137 saa7110_write(decoder,0x30,ptr[5]); /* ADCs gain control */
138 saa7110_write(decoder,0x31,ptr[6]); /* Mixer Control #3 */
139 saa7110_write(decoder,0x21,ptr[7]); /* Analog Control #2 */
145 int determine_norm(struct i2c_device* dev)
147 struct saa7110* decoder = dev->data;
150 /* mode changed, start automatic detection */
151 status = saa7110_read(decoder);
152 if ((status & 3) == 0) {
153 saa7110_write(decoder,0x06,0x80);
155 DEBUG(printk(KERN_INFO "%s: norm=bw60\n",dev->name));
156 saa7110_write(decoder,0x2E,0x81);
157 return VIDEO_MODE_NTSC;
159 DEBUG(printk(KERN_INFO "%s: norm=bw50\n",dev->name));
160 saa7110_write(decoder,0x2E,0x9A);
161 return VIDEO_MODE_PAL;
164 saa7110_write(decoder,0x06,0x00);
165 if (status & 0x20) { /* 60Hz */
166 DEBUG(printk(KERN_INFO "%s: norm=ntsc\n",dev->name));
167 saa7110_write(decoder,0x0D,0x06);
168 saa7110_write(decoder,0x11,0x2C);
169 saa7110_write(decoder,0x2E,0x81);
170 return VIDEO_MODE_NTSC;
173 /* 50Hz -> PAL/SECAM */
174 saa7110_write(decoder,0x0D,0x06);
175 saa7110_write(decoder,0x11,0x59);
176 saa7110_write(decoder,0x2E,0x9A);
178 mdelay(150); /* pause 150 ms */
180 status = saa7110_read(decoder);
181 if ((status & 0x03) == 0x01) {
182 DEBUG(printk(KERN_INFO "%s: norm=secam\n",dev->name));
183 saa7110_write(decoder,0x0D,0x07);
184 return VIDEO_MODE_SECAM;
186 DEBUG(printk(KERN_INFO "%s: norm=pal\n",dev->name));
187 return VIDEO_MODE_PAL;
191 int saa7110_attach(struct i2c_device *device)
193 static const unsigned char initseq[] = {
194 0, 0x4C, 0x3C, 0x0D, 0xEF, 0xBD, 0xF0, 0x00, 0x00,
195 0xF8, 0xF8, 0x60, 0x60, 0x00, 0x06, 0x18, 0x90,
196 0x00, 0x2C, 0x40, 0x46, 0x42, 0x1A, 0xFF, 0xDA,
197 0xF0, 0x8B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
198 0xD9, 0x17, 0x40, 0x41, 0x80, 0x41, 0x80, 0x4F,
199 0xFE, 0x01, 0xCF, 0x0F, 0x03, 0x01, 0x81, 0x03,
200 0x40, 0x75, 0x01, 0x8C, 0x03};
201 struct saa7110* decoder;
204 device->data = decoder = kmalloc(sizeof(struct saa7110), GFP_KERNEL);
205 if (device->data == 0)
210 /* clear our private data */
211 memset(decoder, 0, sizeof(struct saa7110));
212 strcpy(device->name, "saa7110");
213 decoder->bus = device->bus;
214 decoder->addr = device->addr;
215 decoder->norm = VIDEO_MODE_PAL;
218 decoder->bright = 32768;
219 decoder->contrast = 32768;
220 decoder->hue = 32768;
221 decoder->sat = 32768;
223 rv = saa7110_write_block(decoder, initseq, sizeof(initseq));
225 printk(KERN_ERR "%s_attach: init status %d\n", device->name, rv);
227 saa7110_write(decoder,0x21,0x16);
228 saa7110_write(decoder,0x0D,0x04);
229 DEBUG(printk(KERN_INFO "%s_attach: chip version %x\n", device->name, saa7110_read(decoder)));
230 saa7110_write(decoder,0x0D,0x06);
233 /* setup and implicit mode 0 select has been performed */
238 int saa7110_detach(struct i2c_device *device)
240 struct saa7110* decoder = device->data;
242 DEBUG(printk(KERN_INFO "%s_detach\n",device->name));
244 /* stop further output */
245 saa7110_write(decoder,0x0E,0x00);
254 int saa7110_command(struct i2c_device *device, unsigned int cmd, void *arg)
256 struct saa7110* decoder = device->data;
260 case DECODER_GET_CAPABILITIES:
262 struct video_decoder_capability *dc = arg;
263 dc->flags = VIDEO_DECODER_PAL
265 | VIDEO_DECODER_SECAM
267 | VIDEO_DECODER_CCIR;
268 dc->inputs = SAA7110_MAX_INPUT;
269 dc->outputs = SAA7110_MAX_OUTPUT;
273 case DECODER_GET_STATUS:
275 struct saa7110* decoder = device->data;
279 status = i2c_read(device->bus,device->addr|1);
281 res |= DECODER_STATUS_GOOD;
283 res |= DECODER_STATUS_COLOR;
285 switch (decoder->norm) {
286 case VIDEO_MODE_NTSC:
287 res |= DECODER_STATUS_NTSC;
290 res |= DECODER_STATUS_PAL;
292 case VIDEO_MODE_SECAM:
293 res |= DECODER_STATUS_SECAM;
300 case DECODER_SET_NORM:
302 if (decoder->norm != v) {
304 saa7110_write(decoder, 0x06, 0x00);
306 case VIDEO_MODE_NTSC:
307 saa7110_write(decoder, 0x0D, 0x06);
308 saa7110_write(decoder, 0x11, 0x2C);
309 saa7110_write(decoder, 0x30, 0x81);
310 saa7110_write(decoder, 0x2A, 0xDF);
313 saa7110_write(decoder, 0x0D, 0x06);
314 saa7110_write(decoder, 0x11, 0x59);
315 saa7110_write(decoder, 0x2E, 0x9A);
317 case VIDEO_MODE_SECAM:
318 saa7110_write(decoder, 0x0D, 0x07);
319 saa7110_write(decoder, 0x11, 0x59);
320 saa7110_write(decoder, 0x2E, 0x9A);
322 case VIDEO_MODE_AUTO:
323 *(int*)arg = determine_norm(device);
331 case DECODER_SET_INPUT:
333 if (v<0 || v>SAA7110_MAX_INPUT)
335 if (decoder->input != v) {
337 saa7110_selmux(device, v);
341 case DECODER_SET_OUTPUT:
343 /* not much choice of outputs */
348 case DECODER_ENABLE_OUTPUT:
350 if (decoder->enable != v) {
352 saa7110_write(decoder,0x0E, v ? 0x18 : 0x00);
356 case DECODER_SET_PICTURE:
358 struct video_picture *pic = arg;
360 if (decoder->bright != pic->brightness) {
361 /* We want 0 to 255 we get 0-65535 */
362 decoder->bright = pic->brightness;
363 saa7110_write(decoder, 0x19, decoder->bright >> 8);
365 if (decoder->contrast != pic->contrast) {
366 /* We want 0 to 127 we get 0-65535 */
367 decoder->contrast = pic->contrast;
368 saa7110_write(decoder, 0x13, decoder->contrast >> 9);
370 if (decoder->sat != pic->colour) {
371 /* We want 0 to 127 we get 0-65535 */
372 decoder->sat = pic->colour;
373 saa7110_write(decoder, 0x12, decoder->sat >> 9);
375 if (decoder->hue != pic->hue) {
376 /* We want -128 to 127 we get 0-65535 */
377 decoder->hue = pic->hue;
378 saa7110_write(decoder, 0x07, (decoder->hue>>8)-128);
384 for (v=0; v<34; v+=16) {
386 DEBUG(printk(KERN_INFO "%s: %03x\n",device->name,v));
387 for (j=0; j<16; j++) {
388 DEBUG(printk(KERN_INFO " %02x",decoder->reg[v+j]));
390 DEBUG(printk(KERN_INFO "\n"));
395 DEBUG(printk(KERN_INFO "unknown saa7110_command?(%d)\n",cmd));
401 /* ----------------------------------------------------------------------- */
403 static struct i2c_driver i2c_driver_saa7110 =
405 "saa7110", /* name */
407 I2C_DRIVERID_VIDEODECODER, /* in i2c-old.h */
408 I2C_SAA7110, I2C_SAA7110+1, /* Addr range */
417 static int saa7110_init(void)
419 return i2c_register_driver(&i2c_driver_saa7110);
422 static void saa7110_exit(void)
424 i2c_unregister_driver(&i2c_driver_saa7110);
428 module_init(saa7110_init);
429 module_exit(saa7110_exit);
430 MODULE_LICENSE("GPL");