1 /*
2 saa7110 - Philips SAA7110(A) video decoder driver
3
4 Copyright (C) 1998 Pauline Middelink <middelin@polyware.nl>
5
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.
10
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.
15
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.
19 */
20
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>
26 #include <asm/io.h>
27 #include <asm/uaccess.h>
28
29 #include <linux/i2c-old.h>
30 #include <linux/videodev.h>
31 #include "linux/video_decoder.h"
32
33 #define DEBUG(x...) /* remove when no long debugging */
34
35 #define SAA7110_MAX_INPUT 9 /* 6 CVBS, 3 SVHS */
36 #define SAA7110_MAX_OUTPUT 0 /* its a decoder only */
37
38 #define I2C_SAA7110 0x9C /* or 0x9E */
39
40 #define I2C_DELAY 10 /* 10 us or 100khz */
41
42 struct saa7110 {
43 struct i2c_bus *bus;
44 int addr;
45 unsigned char reg[36];
46
47 int norm;
48 int input;
49 int enable;
50 int bright;
51 int contrast;
52 int hue;
53 int sat;
54 };
55
56 /* ----------------------------------------------------------------------- */
57 /* I2C support functions */
58 /* ----------------------------------------------------------------------- */
59 static
saa7110_write(struct saa7110 * decoder,unsigned char subaddr,unsigned char data)60 int saa7110_write(struct saa7110 *decoder, unsigned char subaddr, unsigned char data)
61 {
62 int ack;
63
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);
72 return ack;
73 }
74
75 static
saa7110_write_block(struct saa7110 * decoder,unsigned const char * data,unsigned int len)76 int saa7110_write_block(struct saa7110* decoder, unsigned const char *data, unsigned int len)
77 {
78 unsigned subaddr = *data;
79
80 LOCK_I2C_BUS(decoder->bus);
81 i2c_start(decoder->bus);
82 i2c_sendbyte(decoder->bus,decoder->addr,I2C_DELAY);
83 while (len-- > 0) {
84 if (i2c_sendbyte(decoder->bus,*data,0)) {
85 i2c_stop(decoder->bus);
86 UNLOCK_I2C_BUS(decoder->bus);
87 return -EAGAIN;
88 }
89 decoder->reg[subaddr++] = *data++;
90 }
91 i2c_stop(decoder->bus);
92 UNLOCK_I2C_BUS(decoder->bus);
93
94 return 0;
95 }
96
97 static
saa7110_read(struct saa7110 * decoder)98 int saa7110_read(struct saa7110* decoder)
99 {
100 int data;
101
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);
110 return data;
111 }
112
113 /* ----------------------------------------------------------------------- */
114 /* SAA7110 functions */
115 /* ----------------------------------------------------------------------- */
116 static
saa7110_selmux(struct i2c_device * device,int chan)117 int saa7110_selmux(struct i2c_device *device, int chan)
118 {
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];
131
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 */
140
141 return 0;
142 }
143
144 static
determine_norm(struct i2c_device * dev)145 int determine_norm(struct i2c_device* dev)
146 {
147 struct saa7110* decoder = dev->data;
148 int status;
149
150 /* mode changed, start automatic detection */
151 status = saa7110_read(decoder);
152 if ((status & 3) == 0) {
153 saa7110_write(decoder,0x06,0x80);
154 if (status & 0x20) {
155 DEBUG(printk(KERN_INFO "%s: norm=bw60\n",dev->name));
156 saa7110_write(decoder,0x2E,0x81);
157 return VIDEO_MODE_NTSC;
158 }
159 DEBUG(printk(KERN_INFO "%s: norm=bw50\n",dev->name));
160 saa7110_write(decoder,0x2E,0x9A);
161 return VIDEO_MODE_PAL;
162 }
163
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;
171 }
172
173 /* 50Hz -> PAL/SECAM */
174 saa7110_write(decoder,0x0D,0x06);
175 saa7110_write(decoder,0x11,0x59);
176 saa7110_write(decoder,0x2E,0x9A);
177
178 mdelay(150); /* pause 150 ms */
179
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;
185 }
186 DEBUG(printk(KERN_INFO "%s: norm=pal\n",dev->name));
187 return VIDEO_MODE_PAL;
188 }
189
190 static
saa7110_attach(struct i2c_device * device)191 int saa7110_attach(struct i2c_device *device)
192 {
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;
202 int rv;
203
204 device->data = decoder = kmalloc(sizeof(struct saa7110), GFP_KERNEL);
205 if (device->data == 0)
206 return -ENOMEM;
207
208 MOD_INC_USE_COUNT;
209
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;
216 decoder->input = 0;
217 decoder->enable = 1;
218 decoder->bright = 32768;
219 decoder->contrast = 32768;
220 decoder->hue = 32768;
221 decoder->sat = 32768;
222
223 rv = saa7110_write_block(decoder, initseq, sizeof(initseq));
224 if (rv < 0)
225 printk(KERN_ERR "%s_attach: init status %d\n", device->name, rv);
226 else {
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);
231 }
232
233 /* setup and implicit mode 0 select has been performed */
234 return 0;
235 }
236
237 static
saa7110_detach(struct i2c_device * device)238 int saa7110_detach(struct i2c_device *device)
239 {
240 struct saa7110* decoder = device->data;
241
242 DEBUG(printk(KERN_INFO "%s_detach\n",device->name));
243
244 /* stop further output */
245 saa7110_write(decoder,0x0E,0x00);
246
247 kfree(device->data);
248
249 MOD_DEC_USE_COUNT;
250 return 0;
251 }
252
253 static
saa7110_command(struct i2c_device * device,unsigned int cmd,void * arg)254 int saa7110_command(struct i2c_device *device, unsigned int cmd, void *arg)
255 {
256 struct saa7110* decoder = device->data;
257 int v;
258
259 switch (cmd) {
260 case DECODER_GET_CAPABILITIES:
261 {
262 struct video_decoder_capability *dc = arg;
263 dc->flags = VIDEO_DECODER_PAL
264 | VIDEO_DECODER_NTSC
265 | VIDEO_DECODER_SECAM
266 | VIDEO_DECODER_AUTO
267 | VIDEO_DECODER_CCIR;
268 dc->inputs = SAA7110_MAX_INPUT;
269 dc->outputs = SAA7110_MAX_OUTPUT;
270 }
271 break;
272
273 case DECODER_GET_STATUS:
274 {
275 struct saa7110* decoder = device->data;
276 int status;
277 int res = 0;
278
279 status = i2c_read(device->bus,device->addr|1);
280 if (status & 0x40)
281 res |= DECODER_STATUS_GOOD;
282 if (status & 0x03)
283 res |= DECODER_STATUS_COLOR;
284
285 switch (decoder->norm) {
286 case VIDEO_MODE_NTSC:
287 res |= DECODER_STATUS_NTSC;
288 break;
289 case VIDEO_MODE_PAL:
290 res |= DECODER_STATUS_PAL;
291 break;
292 case VIDEO_MODE_SECAM:
293 res |= DECODER_STATUS_SECAM;
294 break;
295 }
296 *(int*)arg = res;
297 }
298 break;
299
300 case DECODER_SET_NORM:
301 v = *(int*)arg;
302 if (decoder->norm != v) {
303 decoder->norm = v;
304 saa7110_write(decoder, 0x06, 0x00);
305 switch (v) {
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);
311 break;
312 case VIDEO_MODE_PAL:
313 saa7110_write(decoder, 0x0D, 0x06);
314 saa7110_write(decoder, 0x11, 0x59);
315 saa7110_write(decoder, 0x2E, 0x9A);
316 break;
317 case VIDEO_MODE_SECAM:
318 saa7110_write(decoder, 0x0D, 0x07);
319 saa7110_write(decoder, 0x11, 0x59);
320 saa7110_write(decoder, 0x2E, 0x9A);
321 break;
322 case VIDEO_MODE_AUTO:
323 *(int*)arg = determine_norm(device);
324 break;
325 default:
326 return -EPERM;
327 }
328 }
329 break;
330
331 case DECODER_SET_INPUT:
332 v = *(int*)arg;
333 if (v<0 || v>SAA7110_MAX_INPUT)
334 return -EINVAL;
335 if (decoder->input != v) {
336 decoder->input = v;
337 saa7110_selmux(device, v);
338 }
339 break;
340
341 case DECODER_SET_OUTPUT:
342 v = *(int*)arg;
343 /* not much choice of outputs */
344 if (v != 0)
345 return -EINVAL;
346 break;
347
348 case DECODER_ENABLE_OUTPUT:
349 v = *(int*)arg;
350 if (decoder->enable != v) {
351 decoder->enable = v;
352 saa7110_write(decoder,0x0E, v ? 0x18 : 0x00);
353 }
354 break;
355
356 case DECODER_SET_PICTURE:
357 {
358 struct video_picture *pic = arg;
359
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);
364 }
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);
369 }
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);
374 }
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);
379 }
380 }
381 break;
382
383 case DECODER_DUMP:
384 for (v=0; v<34; v+=16) {
385 int j;
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]));
389 }
390 DEBUG(printk(KERN_INFO "\n"));
391 }
392 break;
393
394 default:
395 DEBUG(printk(KERN_INFO "unknown saa7110_command?(%d)\n",cmd));
396 return -EINVAL;
397 }
398 return 0;
399 }
400
401 /* ----------------------------------------------------------------------- */
402
403 static struct i2c_driver i2c_driver_saa7110 =
404 {
405 "saa7110", /* name */
406
407 I2C_DRIVERID_VIDEODECODER, /* in i2c-old.h */
408 I2C_SAA7110, I2C_SAA7110+1, /* Addr range */
409
410 saa7110_attach,
411 saa7110_detach,
412 saa7110_command
413 };
414
415 EXPORT_NO_SYMBOLS;
416
saa7110_init(void)417 static int saa7110_init(void)
418 {
419 return i2c_register_driver(&i2c_driver_saa7110);
420 }
421
saa7110_exit(void)422 static void saa7110_exit(void)
423 {
424 i2c_unregister_driver(&i2c_driver_saa7110);
425 }
426
427
428 module_init(saa7110_init);
429 module_exit(saa7110_exit);
430 MODULE_LICENSE("GPL");
431