OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [media/] [video/] [saa7110.c] - Blame information for rev 65

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * saa7110 - Philips SAA7110(A) video decoder driver
3
 *
4
 * Copyright (C) 1998 Pauline Middelink <middelin@polyware.nl>
5
 *
6
 * Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net>
7
 * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
8
 *    - some corrections for Pinnacle Systems Inc. DC10plus card.
9
 *
10
 * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
11
 *    - moved over to linux>=2.4.x i2c protocol (1/1/2003)
12
 *
13
 * This program is free software; you can redistribute it and/or modify
14
 * it under the terms of the GNU General Public License as published by
15
 * the Free Software Foundation; either version 2 of the License, or
16
 * (at your option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU General Public License
24
 * along with this program; if not, write to the Free Software
25
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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
 
37
MODULE_DESCRIPTION("Philips SAA7110 video decoder driver");
38
MODULE_AUTHOR("Pauline Middelink");
39
MODULE_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
 
49
static int debug = 0;
50
module_param(debug, int, 0);
51
MODULE_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       /* 6 CVBS, 3 SVHS */
60
#define SAA7110_MAX_OUTPUT      0        /* its a decoder only */
61
 
62
#define I2C_SAA7110             0x9C    /* or 0x9E */
63
 
64
#define SAA7110_NR_REG          0x35
65
 
66
struct 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
/* I2C support functions                                                   */
82
/* ----------------------------------------------------------------------- */
83
 
84
static int
85
saa7110_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
 
95
static int
96
saa7110_write_block (struct i2c_client *client,
97
                     const u8          *data,
98
                     unsigned int       len)
99
{
100
        int ret = -1;
101
        u8 reg = *data;         /* first register to write to */
102
 
103
        /* Sanity check */
104
        if (reg + (len - 1) > SAA7110_NR_REG)
105
                return ret;
106
 
107
        /* the saa7110 has an autoincrement function, use it if
108
         * the adapter understands raw I2C */
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
                /* Cache the written data */
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
 
127
static inline int
128
saa7110_read (struct i2c_client *client)
129
{
130
        return i2c_smbus_read_byte(client);
131
}
132
 
133
/* ----------------------------------------------------------------------- */
134
/* SAA7110 functions                                                       */
135
/* ----------------------------------------------------------------------- */
136
 
137
#define FRESP_06H_COMPST 0x03   //0x13
138
#define FRESP_06H_SVIDEO 0x83   //0xC0
139
 
140
 
141
static int
142
saa7110_selmux (struct i2c_client *client,
143
                int                chan)
144
{
145
        static const unsigned char modes[9][8] = {
146
                /* mode 0 */
147
                {FRESP_06H_COMPST, 0xD9, 0x17, 0x40, 0x03,
148
                              0x44, 0x75, 0x16},
149
                /* mode 1 */
150
                {FRESP_06H_COMPST, 0xD8, 0x17, 0x40, 0x03,
151
                              0x44, 0x75, 0x16},
152
                /* mode 2 */
153
                {FRESP_06H_COMPST, 0xBA, 0x07, 0x91, 0x03,
154
                              0x60, 0xB5, 0x05},
155
                /* mode 3 */
156
                {FRESP_06H_COMPST, 0xB8, 0x07, 0x91, 0x03,
157
                              0x60, 0xB5, 0x05},
158
                /* mode 4 */
159
                {FRESP_06H_COMPST, 0x7C, 0x07, 0xD2, 0x83,
160
                              0x60, 0xB5, 0x03},
161
                /* mode 5 */
162
                {FRESP_06H_COMPST, 0x78, 0x07, 0xD2, 0x83,
163
                              0x60, 0xB5, 0x03},
164
                /* mode 6 */
165
                {FRESP_06H_SVIDEO, 0x59, 0x17, 0x42, 0xA3,
166
                              0x44, 0x75, 0x12},
167
                /* mode 7 */
168
                {FRESP_06H_SVIDEO, 0x9A, 0x17, 0xB1, 0x13,
169
                              0x60, 0xB5, 0x14},
170
                /* mode 8 */
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]);     /* Luminance control    */
178
        saa7110_write(client, 0x20, ptr[1]);    /* Analog Control #1    */
179
        saa7110_write(client, 0x21, ptr[2]);    /* Analog Control #2    */
180
        saa7110_write(client, 0x22, ptr[3]);    /* Mixer Control #1     */
181
        saa7110_write(client, 0x2C, ptr[4]);    /* Mixer Control #2     */
182
        saa7110_write(client, 0x30, ptr[5]);    /* ADCs gain control    */
183
        saa7110_write(client, 0x31, ptr[6]);    /* Mixer Control #3     */
184
        saa7110_write(client, 0x21, ptr[7]);    /* Analog Control #2    */
185
        decoder->input = chan;
186
 
187
        return 0;
188
}
189
 
190
static const unsigned char initseq[1 + SAA7110_NR_REG] = {
191
        0, 0x4C, 0x3C, 0x0D, 0xEF, 0xBD, 0xF2, 0x03, 0x00,
192
        /* 0x08 */ 0xF8, 0xF8, 0x60, 0x60, 0x00, 0x86, 0x18, 0x90,
193
        /* 0x10 */ 0x00, 0x59, 0x40, 0x46, 0x42, 0x1A, 0xFF, 0xDA,
194
        /* 0x18 */ 0xF2, 0x8B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
195
        /* 0x20 */ 0xD9, 0x16, 0x40, 0x41, 0x80, 0x41, 0x80, 0x4F,
196
        /* 0x28 */ 0xFE, 0x01, 0xCF, 0x0F, 0x03, 0x01, 0x03, 0x0C,
197
        /* 0x30 */ 0x44, 0x71, 0x02, 0x8C, 0x02
198
};
199
 
200
static int
201
determine_norm (struct i2c_client *client)
202
{
203
        DEFINE_WAIT(wait);
204
        struct saa7110 *decoder = i2c_get_clientdata(client);
205
        int status;
206
 
207
        /* mode changed, start automatic detection */
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;   // no change
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
                        //saa7110_write(client,0x2E,0x81);
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
                //saa7110_write(client,0x2E,0x9A);
232
                return VIDEO_MODE_PAL;
233
        }
234
        //saa7110_write(client,0x06,0x03);
235
        if (status & 0x20) {    /* 60Hz */
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
                //saa7110_write(client,0x2E,0x81);
242
                return VIDEO_MODE_NTSC;
243
        }
244
 
245
        /* 50Hz -> PAL/SECAM */
246
        saa7110_write(client, 0x0D, 0x86);
247
        saa7110_write(client, 0x0F, 0x10);
248
        saa7110_write(client, 0x11, 0x59);
249
        //saa7110_write(client,0x2E,0x9A);
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
 
267
static int
268
saa7110_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
                //saa7110_write_block(client, initseq, sizeof(initseq));
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
                        //saa7110_write(client, 0x06, 0x03);
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
                                //saa7110_write(client, 0x2E, 0x81);
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
                                //saa7110_write(client, 0x2E, 0x9A);
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
                                //saa7110_write(client, 0x2E, 0x9A);
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
                /* not much choice of outputs */
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
                        /* We want 0 to 255 we get 0-65535 */
406
                        decoder->bright = pic->brightness;
407
                        saa7110_write(client, 0x19, decoder->bright >> 8);
408
                }
409
                if (decoder->contrast != pic->contrast) {
410
                        /* We want 0 to 127 we get 0-65535 */
411
                        decoder->contrast = pic->contrast;
412
                        saa7110_write(client, 0x13,
413
                                      decoder->contrast >> 9);
414
                }
415
                if (decoder->sat != pic->colour) {
416
                        /* We want 0 to 127 we get 0-65535 */
417
                        decoder->sat = pic->colour;
418
                        saa7110_write(client, 0x12, decoder->sat >> 9);
419
                }
420
                if (decoder->hue != pic->hue) {
421
                        /* We want -128 to 127 we get 0-65535 */
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
 * Generic i2c probe
452
 * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
453
 */
454
static unsigned short normal_i2c[] = {
455
        I2C_SAA7110 >> 1,
456
        (I2C_SAA7110 >> 1) + 1,
457
        I2C_CLIENT_END
458
};
459
 
460
static unsigned short ignore = I2C_CLIENT_END;
461
 
462
static struct i2c_client_address_data addr_data = {
463
        .normal_i2c             = normal_i2c,
464
        .probe                  = &ignore,
465
        .ignore                 = &ignore,
466
};
467
 
468
static struct i2c_driver i2c_driver_saa7110;
469
 
470
static int
471
saa7110_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
        /* Check if the adapter supports the needed features */
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
                //mdelay(150);
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
                //saa7110_write(client, 0x2E, 0x9A);
541
        }
542
 
543
        //saa7110_selmux(client,0);
544
        //determine_norm(client);
545
        /* setup and implicit mode 0 select has been performed */
546
 
547
        return 0;
548
}
549
 
550
static int
551
saa7110_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
 
560
static int
561
saa7110_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
 
579
static 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
 
591
static int __init
592
saa7110_init (void)
593
{
594
        return i2c_add_driver(&i2c_driver_saa7110);
595
}
596
 
597
static void __exit
598
saa7110_exit (void)
599
{
600
        i2c_del_driver(&i2c_driver_saa7110);
601
}
602
 
603
module_init(saa7110_init);
604
module_exit(saa7110_exit);

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.