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.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 /* it's a decoder only */
38 #define I2C_SAA7110 0x9C /* or 0x9E */
40 #define IF_NAME "saa7110"
41 #define I2C_DELAY 10 /* 10 us or 100khz */
43 static unsigned short normal_i2c[] = {34>>1, I2C_CLIENT_END };
44 static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
45 static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
46 static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
47 static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
48 static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
49 static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
51 static struct i2c_client_address_data addr_data = {
52 normal_i2c, normal_i2c_range,
58 static struct i2c_client client_template;
61 struct i2c_client *client;
63 unsigned char reg[36];
64 struct semaphore lock;
74 /* ----------------------------------------------------------------------- */
75 /* SAA7110 functions */
76 /* ----------------------------------------------------------------------- */
78 int saa7110_selmux(struct i2c_client *client, int chan)
80 static const unsigned char modes[9][8] = {
81 /* mode 0 */ { 0x00, 0xD9, 0x17, 0x40, 0x03, 0x44, 0x75, 0x16 },
82 /* mode 1 */ { 0x00, 0xD8, 0x17, 0x40, 0x03, 0x44, 0x75, 0x16 },
83 /* mode 2 */ { 0x00, 0xBA, 0x07, 0x91, 0x03, 0x60, 0xB5, 0x05 },
84 /* mode 3 */ { 0x00, 0xB8, 0x07, 0x91, 0x03, 0x60, 0xB5, 0x05 },
85 /* mode 4 */ { 0x00, 0x7C, 0x07, 0xD2, 0x83, 0x60, 0xB5, 0x03 },
86 /* mode 5 */ { 0x00, 0x78, 0x07, 0xD2, 0x83, 0x60, 0xB5, 0x03 },
87 /* mode 6 */ { 0x80, 0x59, 0x17, 0x42, 0xA3, 0x44, 0x75, 0x12 },
88 /* mode 7 */ { 0x80, 0x9A, 0x17, 0xB1, 0x13, 0x60, 0xB5, 0x14 },
89 /* mode 8 */ { 0x80, 0x3C, 0x27, 0xC1, 0x23, 0x44, 0x75, 0x21 } };
90 const unsigned char* ptr = modes[chan];
92 i2c_smbus_write_byte_data(client,0x06,ptr[0]); /* Luminance control */
93 i2c_smbus_write_byte_data(client,0x20,ptr[1]); /* Analog Control #1 */
94 i2c_smbus_write_byte_data(client,0x21,ptr[2]); /* Analog Control #2 */
95 i2c_smbus_write_byte_data(client,0x22,ptr[3]); /* Mixer Control #1 */
96 i2c_smbus_write_byte_data(client,0x2C,ptr[4]); /* Mixer Control #2 */
97 i2c_smbus_write_byte_data(client,0x30,ptr[5]); /* ADCs gain control */
98 i2c_smbus_write_byte_data(client,0x31,ptr[6]); /* Mixer Control #3 */
99 i2c_smbus_write_byte_data(client,0x21,ptr[7]); /* Analog Control #2 */
105 int determine_norm(struct i2c_client* client)
109 /* mode changed, start automatic detection */
110 status = i2c_smbus_read_byte(client);
111 if ((status & 3) == 0) {
112 i2c_smbus_write_byte_data(client,0x06,0x80);
114 DEBUG(printk(KERN_INFO "%s: norm=bw60\n",adp->name));
115 i2c_smbus_write_byte_data(client,0x2E,0x81);
116 return VIDEO_MODE_NTSC;
118 DEBUG(printk(KERN_INFO "%s: norm=bw50\n",adp->name));
119 i2c_smbus_write_byte_data(client,0x2E,0x9A);
120 return VIDEO_MODE_PAL;
123 i2c_smbus_write_byte_data(client,0x06,0x00);
124 if (status & 0x20) { /* 60Hz */
125 DEBUG(printk(KERN_INFO "%s: norm=ntsc\n",adp->name));
126 i2c_smbus_write_byte_data(client,0x0D,0x06);
127 i2c_smbus_write_byte_data(client,0x11,0x2C);
128 i2c_smbus_write_byte_data(client,0x2E,0x81);
129 return VIDEO_MODE_NTSC;
132 /* 50Hz -> PAL/SECAM */
133 i2c_smbus_write_byte_data(client,0x0D,0x06);
134 i2c_smbus_write_byte_data(client,0x11,0x59);
135 i2c_smbus_write_byte_data(client,0x2E,0x9A);
137 mdelay(150); /* pause 150 ms */
139 status = i2c_smbus_read_byte(client);
140 if ((status & 0x03) == 0x01) {
141 DEBUG(printk(KERN_INFO "%s: norm=secam\n",dev->name));
142 i2c_smbus_write_byte_data(client,0x0D,0x07);
143 return VIDEO_MODE_SECAM;
145 DEBUG(printk(KERN_INFO "%s: norm=pal\n",dev->name));
146 return VIDEO_MODE_PAL;
150 int saa7110_attach(struct i2c_adapter *adap, int addr, int kind)
152 static const unsigned char initseq[] = {
153 0, 0x4C, 0x3C, 0x0D, 0xEF, 0xBD, 0xF0, 0x00, 0x00,
154 0xF8, 0xF8, 0x60, 0x60, 0x00, 0x06, 0x18, 0x90,
155 0x00, 0x2C, 0x40, 0x46, 0x42, 0x1A, 0xFF, 0xDA,
156 0xF0, 0x8B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
157 0xD9, 0x17, 0x40, 0x41, 0x80, 0x41, 0x80, 0x4F,
158 0xFE, 0x01, 0xCF, 0x0F, 0x03, 0x01, 0x81, 0x03,
159 0x40, 0x75, 0x01, 0x8C, 0x03};
160 struct saa7110 *decoder;
161 struct i2c_client *client;
163 client=kmalloc(sizeof(*client), GFP_KERNEL);
166 memset(client, 0, sizeof(*client));
167 client_template.adapter = adap;
168 client_template.addr = addr;
169 memcpy(client, &client_template, sizeof(*client));
171 decoder = kmalloc(sizeof(*decoder), GFP_KERNEL);
172 if (decoder == NULL) {
177 /* clear our private data */
178 memset(decoder, 0, sizeof(*decoder));
179 strlcpy(client->name, IF_NAME, DEVICE_NAME_SIZE);
180 decoder->client = client;
181 i2c_set_clientdata(client, decoder);
182 decoder->addr = addr;
183 decoder->norm = VIDEO_MODE_PAL;
186 decoder->bright = 32768;
187 decoder->contrast = 32768;
188 decoder->hue = 32768;
189 decoder->sat = 32768;
191 rv = i2c_master_send(client, initseq, sizeof(initseq));
193 printk(KERN_ERR "%s_attach: init status %d\n", client->name, rv);
195 i2c_smbus_write_byte_data(client,0x21,0x16);
196 i2c_smbus_write_byte_data(client,0x0D,0x04);
197 DEBUG(printk(KERN_INFO "%s_attach: chip version %x\n", client->name, i2c_smbus_read_byte(client)));
198 i2c_smbus_write_byte_data(client,0x0D,0x06);
201 init_MUTEX(&decoder->lock);
202 i2c_attach_client(client);
204 /* setup and implicit mode 0 select has been performed */
209 int saa7110_probe(struct i2c_adapter *adap)
211 return i2c_probe(adap, &addr_data, saa7110_attach);
215 int saa7110_detach(struct i2c_client *client)
217 struct saa7110* decoder = i2c_get_clientdata(client);
219 i2c_detach_client(client);
221 DEBUG(printk(KERN_INFO "%s_detach\n",client->name));
223 /* stop further output */
224 i2c_smbus_write_byte_data(client,0x0E,0x00);
234 int saa7110_command(struct i2c_client *client, unsigned int cmd, void *arg)
236 struct saa7110* decoder = i2c_get_clientdata(client);
240 case DECODER_GET_CAPABILITIES:
242 struct video_decoder_capability *dc = arg;
243 dc->flags = VIDEO_DECODER_PAL
245 | VIDEO_DECODER_SECAM
247 | VIDEO_DECODER_CCIR;
248 dc->inputs = SAA7110_MAX_INPUT;
249 dc->outputs = SAA7110_MAX_OUTPUT;
253 case DECODER_GET_STATUS:
255 struct saa7110* decoder = i2c_get_clientdata(client);
259 status = i2c_smbus_read_byte(client);
261 res |= DECODER_STATUS_GOOD;
263 res |= DECODER_STATUS_COLOR;
265 switch (decoder->norm) {
266 case VIDEO_MODE_NTSC:
267 res |= DECODER_STATUS_NTSC;
270 res |= DECODER_STATUS_PAL;
272 case VIDEO_MODE_SECAM:
273 res |= DECODER_STATUS_SECAM;
280 case DECODER_SET_NORM:
282 if (decoder->norm != v) {
284 i2c_smbus_write_byte_data(client, 0x06, 0x00);
286 case VIDEO_MODE_NTSC:
287 i2c_smbus_write_byte_data(client, 0x0D, 0x06);
288 i2c_smbus_write_byte_data(client, 0x11, 0x2C);
289 i2c_smbus_write_byte_data(client, 0x30, 0x81);
290 i2c_smbus_write_byte_data(client, 0x2A, 0xDF);
293 i2c_smbus_write_byte_data(client, 0x0D, 0x06);
294 i2c_smbus_write_byte_data(client, 0x11, 0x59);
295 i2c_smbus_write_byte_data(client, 0x2E, 0x9A);
297 case VIDEO_MODE_SECAM:
298 i2c_smbus_write_byte_data(client, 0x0D, 0x07);
299 i2c_smbus_write_byte_data(client, 0x11, 0x59);
300 i2c_smbus_write_byte_data(client, 0x2E, 0x9A);
302 case VIDEO_MODE_AUTO:
303 *(int*)arg = determine_norm(client);
311 case DECODER_SET_INPUT:
313 if (v<0 || v>SAA7110_MAX_INPUT)
315 if (decoder->input != v) {
317 saa7110_selmux(client, v);
321 case DECODER_SET_OUTPUT:
323 /* not much choice of outputs */
328 case DECODER_ENABLE_OUTPUT:
330 if (decoder->enable != v) {
332 i2c_smbus_write_byte_data(client,0x0E, v ? 0x18 : 0x00);
336 case DECODER_SET_PICTURE:
338 struct video_picture *pic = arg;
340 if (decoder->bright != pic->brightness) {
341 /* We want 0 to 255 we get 0-65535 */
342 decoder->bright = pic->brightness;
343 i2c_smbus_write_byte_data(client, 0x19, decoder->bright >> 8);
345 if (decoder->contrast != pic->contrast) {
346 /* We want 0 to 127 we get 0-65535 */
347 decoder->contrast = pic->contrast;
348 i2c_smbus_write_byte_data(client, 0x13, decoder->contrast >> 9);
350 if (decoder->sat != pic->colour) {
351 /* We want 0 to 127 we get 0-65535 */
352 decoder->sat = pic->colour;
353 i2c_smbus_write_byte_data(client, 0x12, decoder->sat >> 9);
355 if (decoder->hue != pic->hue) {
356 /* We want -128 to 127 we get 0-65535 */
357 decoder->hue = pic->hue;
358 i2c_smbus_write_byte_data(client, 0x07, (decoder->hue>>8)-128);
364 for (v=0; v<34; v+=16) {
366 DEBUG(printk(KERN_INFO "%s: %03x\n",client->name,v));
367 for (j=0; j<16; j++) {
368 DEBUG(printk(KERN_INFO " %02x",decoder->reg[v+j]));
370 DEBUG(printk(KERN_INFO "\n"));
375 DEBUG(printk(KERN_INFO "unknown saa7110_command??(%d)\n",cmd));
381 /* ----------------------------------------------------------------------- */
383 static struct i2c_driver i2c_driver_saa7110 =
385 .owner = THIS_MODULE,
386 .name = IF_NAME, /* name */
387 .id = I2C_DRIVERID_SAA7110, /* in i2c.h */
388 .flags = I2C_DF_NOTIFY, /* Addr range */
389 .attach_adapter = saa7110_probe,
390 .detach_client = saa7110_detach,
391 .command = saa7110_command
393 static struct i2c_client client_template = {
395 .driver = &i2c_driver_saa7110,
396 .name = "saa7110_client",
399 static int saa7110_init(void)
401 return i2c_add_driver(&i2c_driver_saa7110);
404 static void saa7110_exit(void)
406 i2c_del_driver(&i2c_driver_saa7110);
410 module_init(saa7110_init);
411 module_exit(saa7110_exit);
412 MODULE_LICENSE("GPL");