diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2005-09-06 18:19:37 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-09-07 19:58:01 -0400 |
commit | d203a7eca85101f0a8ce1dc139ee91196142da36 (patch) | |
tree | 83c7d467ef3b6e3e9a2b9ad56ee4f5b2f8d76aa5 /drivers/media/video/saa7191.c | |
parent | 0bb6fcc13ae4fad98e0d610458975e47be0d2203 (diff) |
[PATCH] Indycam / VINO drivers
Rewrite of the Indycam / VINO video v4l2 drivers for the SGI Indy.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Signed-off-by: Mikael Nousiainen <tmnousia@cc.hut.fi>
Cc: <video4linux-list@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/media/video/saa7191.c')
-rw-r--r-- | drivers/media/video/saa7191.c | 512 |
1 files changed, 512 insertions, 0 deletions
diff --git a/drivers/media/video/saa7191.c b/drivers/media/video/saa7191.c new file mode 100644 index 000000000000..454f5c1199b4 --- /dev/null +++ b/drivers/media/video/saa7191.c | |||
@@ -0,0 +1,512 @@ | |||
1 | /* | ||
2 | * saa7191.c - Philips SAA7191 video decoder driver | ||
3 | * | ||
4 | * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org> | ||
5 | * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi> | ||
6 | * | ||
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. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/errno.h> | ||
16 | #include <linux/fs.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/major.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/mm.h> | ||
21 | #include <linux/sched.h> | ||
22 | |||
23 | #include <linux/videodev.h> | ||
24 | #include <linux/video_decoder.h> | ||
25 | #include <linux/i2c.h> | ||
26 | |||
27 | #include "saa7191.h" | ||
28 | |||
29 | #define SAA7191_MODULE_VERSION "0.0.3" | ||
30 | |||
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"); | ||
35 | |||
36 | #define VINO_ADAPTER (I2C_ALGO_SGI | I2C_HW_SGI_VINO) | ||
37 | |||
38 | struct saa7191 { | ||
39 | struct i2c_client *client; | ||
40 | |||
41 | /* the register values are stored here as the actual | ||
42 | * I2C-registers are write-only */ | ||
43 | unsigned char reg[25]; | ||
44 | |||
45 | unsigned char norm; | ||
46 | unsigned char input; | ||
47 | }; | ||
48 | |||
49 | static struct i2c_driver i2c_driver_saa7191; | ||
50 | |||
51 | static const unsigned char initseq[] = { | ||
52 | 0, /* Subaddress */ | ||
53 | 0x50, /* SAA7191_REG_IDEL */ | ||
54 | 0x30, /* SAA7191_REG_HSYB */ | ||
55 | 0x00, /* SAA7191_REG_HSYS */ | ||
56 | 0xe8, /* SAA7191_REG_HCLB */ | ||
57 | 0xb6, /* SAA7191_REG_HCLS */ | ||
58 | 0xf4, /* SAA7191_REG_HPHI */ | ||
59 | 0x01, /* SAA7191_REG_LUMA - chrominance trap active (CVBS) */ | ||
60 | 0x00, /* SAA7191_REG_HUEC */ | ||
61 | 0xf8, /* SAA7191_REG_CKTQ */ | ||
62 | 0xf8, /* SAA7191_REG_CKTS */ | ||
63 | 0x90, /* SAA7191_REG_PLSE */ | ||
64 | 0x90, /* SAA7191_REG_SESE */ | ||
65 | 0x00, /* SAA7191_REG_GAIN */ | ||
66 | 0x0c, /* SAA7191_REG_STDC - not SECAM, slow time constant */ | ||
67 | 0x78, /* SAA7191_REG_IOCK - chrominance from CVBS, GPSW1 & 2 off */ | ||
68 | 0x99, /* SAA7191_REG_CTL3 - automatic field detection */ | ||
69 | 0x00, /* SAA7191_REG_CTL4 */ | ||
70 | 0x2c, /* SAA7191_REG_CHCV */ | ||
71 | 0x00, /* unused */ | ||
72 | 0x00, /* unused */ | ||
73 | 0x34, /* SAA7191_REG_HS6B */ | ||
74 | 0x0a, /* SAA7191_REG_HS6S */ | ||
75 | 0xf4, /* SAA7191_REG_HC6B */ | ||
76 | 0xce, /* SAA7191_REG_HC6S */ | ||
77 | 0xf4, /* SAA7191_REG_HP6I */ | ||
78 | }; | ||
79 | |||
80 | /* SAA7191 register handling */ | ||
81 | |||
82 | static unsigned char saa7191_read_reg(struct i2c_client *client, | ||
83 | unsigned char reg) | ||
84 | { | ||
85 | return ((struct saa7191 *)i2c_get_clientdata(client))->reg[reg]; | ||
86 | } | ||
87 | |||
88 | static int saa7191_read_status(struct i2c_client *client, | ||
89 | unsigned char *value) | ||
90 | { | ||
91 | int ret; | ||
92 | |||
93 | ret = i2c_master_recv(client, value, 1); | ||
94 | if (ret < 0) { | ||
95 | printk(KERN_ERR "SAA7191: saa7191_read_status(): read failed"); | ||
96 | return ret; | ||
97 | } | ||
98 | |||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | |||
103 | static int saa7191_write_reg(struct i2c_client *client, unsigned char reg, | ||
104 | unsigned char value) | ||
105 | { | ||
106 | |||
107 | ((struct saa7191 *)i2c_get_clientdata(client))->reg[reg] = value; | ||
108 | return i2c_smbus_write_byte_data(client, reg, value); | ||
109 | } | ||
110 | |||
111 | /* the first byte of data must be the first subaddress number (register) */ | ||
112 | static int saa7191_write_block(struct i2c_client *client, | ||
113 | unsigned char length, unsigned char *data) | ||
114 | { | ||
115 | int i; | ||
116 | int ret; | ||
117 | |||
118 | struct saa7191 *decoder = (struct saa7191 *)i2c_get_clientdata(client); | ||
119 | for (i = 0; i < (length - 1); i++) { | ||
120 | decoder->reg[data[0] + i] = data[i + 1]; | ||
121 | } | ||
122 | |||
123 | ret = i2c_master_send(client, data, length); | ||
124 | if (ret < 0) { | ||
125 | printk(KERN_ERR "SAA7191: saa7191_write_block(): " | ||
126 | "write failed"); | ||
127 | return ret; | ||
128 | } | ||
129 | |||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | /* Helper functions */ | ||
134 | |||
135 | static int saa7191_set_input(struct i2c_client *client, int input) | ||
136 | { | ||
137 | unsigned char luma = saa7191_read_reg(client, SAA7191_REG_LUMA); | ||
138 | unsigned char iock = saa7191_read_reg(client, SAA7191_REG_IOCK); | ||
139 | int err; | ||
140 | |||
141 | switch (input) { | ||
142 | case SAA7191_INPUT_COMPOSITE: /* Set Composite input */ | ||
143 | iock &= ~(SAA7191_IOCK_CHRS | SAA7191_IOCK_GPSW1 | ||
144 | | SAA7191_IOCK_GPSW2); | ||
145 | /* Chrominance trap active */ | ||
146 | luma &= ~SAA7191_LUMA_BYPS; | ||
147 | break; | ||
148 | case SAA7191_INPUT_SVIDEO: /* Set S-Video input */ | ||
149 | iock |= SAA7191_IOCK_CHRS | SAA7191_IOCK_GPSW2; | ||
150 | /* Chrominance trap bypassed */ | ||
151 | luma |= SAA7191_LUMA_BYPS; | ||
152 | break; | ||
153 | default: | ||
154 | return -EINVAL; | ||
155 | } | ||
156 | |||
157 | err = saa7191_write_reg(client, SAA7191_REG_LUMA, luma); | ||
158 | if (err) | ||
159 | return -EIO; | ||
160 | err = saa7191_write_reg(client, SAA7191_REG_IOCK, iock); | ||
161 | if (err) | ||
162 | return -EIO; | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static int saa7191_set_norm(struct i2c_client *client, int norm) | ||
168 | { | ||
169 | struct saa7191 *decoder = i2c_get_clientdata(client); | ||
170 | unsigned char stdc = saa7191_read_reg(client, SAA7191_REG_STDC); | ||
171 | unsigned char ctl3 = saa7191_read_reg(client, SAA7191_REG_CTL3); | ||
172 | unsigned char chcv = saa7191_read_reg(client, SAA7191_REG_CHCV); | ||
173 | int err; | ||
174 | |||
175 | switch(norm) { | ||
176 | case SAA7191_NORM_AUTO: { | ||
177 | unsigned char status; | ||
178 | |||
179 | // does status depend on current norm ? | ||
180 | if (saa7191_read_status(client, &status)) | ||
181 | return -EIO; | ||
182 | |||
183 | stdc &= ~SAA7191_STDC_SECS; | ||
184 | ctl3 &= ~SAA7191_CTL3_FSEL; | ||
185 | ctl3 |= SAA7191_CTL3_AUFD; | ||
186 | chcv = (status & SAA7191_STATUS_FIDT) | ||
187 | ? SAA7191_CHCV_NTSC : SAA7191_CHCV_PAL; | ||
188 | break; | ||
189 | } | ||
190 | case SAA7191_NORM_PAL: | ||
191 | stdc &= ~SAA7191_STDC_SECS; | ||
192 | ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL); | ||
193 | chcv = SAA7191_CHCV_PAL; | ||
194 | break; | ||
195 | case SAA7191_NORM_NTSC: | ||
196 | stdc &= ~SAA7191_STDC_SECS; | ||
197 | ctl3 &= ~SAA7191_CTL3_AUFD; | ||
198 | ctl3 |= SAA7191_CTL3_FSEL; | ||
199 | chcv = SAA7191_CHCV_NTSC; | ||
200 | break; | ||
201 | case SAA7191_NORM_SECAM: | ||
202 | stdc |= SAA7191_STDC_SECS; | ||
203 | ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL); | ||
204 | chcv = SAA7191_CHCV_PAL; | ||
205 | break; | ||
206 | default: | ||
207 | return -EINVAL; | ||
208 | } | ||
209 | |||
210 | err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3); | ||
211 | if (err) | ||
212 | return -EIO; | ||
213 | err = saa7191_write_reg(client, SAA7191_REG_STDC, stdc); | ||
214 | if (err) | ||
215 | return -EIO; | ||
216 | err = saa7191_write_reg(client, SAA7191_REG_CHCV, chcv); | ||
217 | if (err) | ||
218 | return -EIO; | ||
219 | |||
220 | decoder->norm = norm; | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static int saa7191_get_controls(struct i2c_client *client, | ||
226 | struct saa7191_control *ctrl) | ||
227 | { | ||
228 | unsigned char hue = saa7191_read_reg(client, SAA7191_REG_HUEC); | ||
229 | unsigned char stdc = saa7191_read_reg(client, SAA7191_REG_STDC); | ||
230 | |||
231 | if (hue < 0x80) { | ||
232 | hue += 0x80; | ||
233 | } else { | ||
234 | hue -= 0x80; | ||
235 | } | ||
236 | ctrl->hue = hue; | ||
237 | |||
238 | ctrl->vtrc = (stdc & SAA7191_STDC_VTRC) | ||
239 | ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED; | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | static int saa7191_set_controls(struct i2c_client *client, | ||
245 | struct saa7191_control *ctrl) | ||
246 | { | ||
247 | int err; | ||
248 | |||
249 | if (ctrl->hue >= 0) { | ||
250 | unsigned char hue = ctrl->hue & 0xff; | ||
251 | if (hue < 0x80) { | ||
252 | hue += 0x80; | ||
253 | } else { | ||
254 | hue -= 0x80; | ||
255 | } | ||
256 | err = saa7191_write_reg(client, SAA7191_REG_HUEC, hue); | ||
257 | if (err) | ||
258 | return -EIO; | ||
259 | } | ||
260 | if (ctrl->vtrc >= 0) { | ||
261 | unsigned char stdc = | ||
262 | saa7191_read_reg(client, SAA7191_REG_STDC); | ||
263 | |||
264 | if (ctrl->vtrc) { | ||
265 | stdc |= SAA7191_STDC_VTRC; | ||
266 | } else { | ||
267 | stdc &= ~SAA7191_STDC_VTRC; | ||
268 | } | ||
269 | |||
270 | err = saa7191_write_reg(client, SAA7191_REG_STDC, stdc); | ||
271 | if (err) | ||
272 | return -EIO; | ||
273 | } | ||
274 | |||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | /* I2C-interface */ | ||
279 | |||
280 | static int saa7191_attach(struct i2c_adapter *adap, int addr, int kind) | ||
281 | { | ||
282 | int err = 0; | ||
283 | struct saa7191 *decoder; | ||
284 | struct i2c_client *client; | ||
285 | |||
286 | printk(KERN_INFO "Philips SAA7191 driver version %s\n", | ||
287 | SAA7191_MODULE_VERSION); | ||
288 | |||
289 | client = kmalloc(sizeof(*client), GFP_KERNEL); | ||
290 | if (!client) | ||
291 | return -ENOMEM; | ||
292 | decoder = kmalloc(sizeof(*decoder), GFP_KERNEL); | ||
293 | if (!decoder) { | ||
294 | err = -ENOMEM; | ||
295 | goto out_free_client; | ||
296 | } | ||
297 | |||
298 | memset(client, 0, sizeof(struct i2c_client)); | ||
299 | memset(decoder, 0, sizeof(struct saa7191)); | ||
300 | |||
301 | client->addr = addr; | ||
302 | client->adapter = adap; | ||
303 | client->driver = &i2c_driver_saa7191; | ||
304 | client->flags = 0; | ||
305 | strcpy(client->name, "saa7191 client"); | ||
306 | i2c_set_clientdata(client, decoder); | ||
307 | |||
308 | decoder->client = client; | ||
309 | |||
310 | err = i2c_attach_client(client); | ||
311 | if (err) | ||
312 | goto out_free_decoder; | ||
313 | |||
314 | decoder->input = SAA7191_INPUT_COMPOSITE; | ||
315 | decoder->norm = SAA7191_NORM_AUTO; | ||
316 | |||
317 | err = saa7191_write_block(client, sizeof(initseq), | ||
318 | (unsigned char *)initseq); | ||
319 | if (err) { | ||
320 | printk(KERN_ERR "SAA7191 initialization failed\n"); | ||
321 | goto out_detach_client; | ||
322 | } | ||
323 | |||
324 | printk(KERN_INFO "SAA7191 initialized\n"); | ||
325 | |||
326 | return 0; | ||
327 | |||
328 | out_detach_client: | ||
329 | i2c_detach_client(client); | ||
330 | out_free_decoder: | ||
331 | kfree(decoder); | ||
332 | out_free_client: | ||
333 | kfree(client); | ||
334 | return err; | ||
335 | } | ||
336 | |||
337 | static int saa7191_probe(struct i2c_adapter *adap) | ||
338 | { | ||
339 | /* Always connected to VINO */ | ||
340 | if (adap->id == VINO_ADAPTER) | ||
341 | return saa7191_attach(adap, SAA7191_ADDR, 0); | ||
342 | /* Feel free to add probe here :-) */ | ||
343 | return -ENODEV; | ||
344 | } | ||
345 | |||
346 | static int saa7191_detach(struct i2c_client *client) | ||
347 | { | ||
348 | struct saa7191 *decoder = i2c_get_clientdata(client); | ||
349 | |||
350 | i2c_detach_client(client); | ||
351 | kfree(decoder); | ||
352 | kfree(client); | ||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | static int saa7191_command(struct i2c_client *client, unsigned int cmd, | ||
357 | void *arg) | ||
358 | { | ||
359 | struct saa7191 *decoder = i2c_get_clientdata(client); | ||
360 | |||
361 | switch (cmd) { | ||
362 | case DECODER_GET_CAPABILITIES: { | ||
363 | struct video_decoder_capability *cap = arg; | ||
364 | |||
365 | cap->flags = VIDEO_DECODER_PAL | VIDEO_DECODER_NTSC | | ||
366 | VIDEO_DECODER_SECAM | VIDEO_DECODER_AUTO; | ||
367 | cap->inputs = (client->adapter->id == VINO_ADAPTER) ? 2 : 1; | ||
368 | cap->outputs = 1; | ||
369 | break; | ||
370 | } | ||
371 | case DECODER_GET_STATUS: { | ||
372 | int *iarg = arg; | ||
373 | unsigned char status; | ||
374 | int res = 0; | ||
375 | |||
376 | if (saa7191_read_status(client, &status)) { | ||
377 | return -EIO; | ||
378 | } | ||
379 | if ((status & SAA7191_STATUS_HLCK) == 0) | ||
380 | res |= DECODER_STATUS_GOOD; | ||
381 | if (status & SAA7191_STATUS_CODE) | ||
382 | res |= DECODER_STATUS_COLOR; | ||
383 | switch (decoder->norm) { | ||
384 | case SAA7191_NORM_NTSC: | ||
385 | res |= DECODER_STATUS_NTSC; | ||
386 | break; | ||
387 | case SAA7191_NORM_PAL: | ||
388 | res |= DECODER_STATUS_PAL; | ||
389 | break; | ||
390 | case SAA7191_NORM_SECAM: | ||
391 | res |= DECODER_STATUS_SECAM; | ||
392 | break; | ||
393 | case SAA7191_NORM_AUTO: | ||
394 | default: | ||
395 | if (status & SAA7191_STATUS_FIDT) | ||
396 | res |= DECODER_STATUS_NTSC; | ||
397 | else | ||
398 | res |= DECODER_STATUS_PAL; | ||
399 | break; | ||
400 | } | ||
401 | *iarg = res; | ||
402 | break; | ||
403 | } | ||
404 | case DECODER_SET_NORM: { | ||
405 | int *iarg = arg; | ||
406 | |||
407 | switch (*iarg) { | ||
408 | case VIDEO_MODE_AUTO: | ||
409 | return saa7191_set_norm(client, SAA7191_NORM_AUTO); | ||
410 | case VIDEO_MODE_PAL: | ||
411 | return saa7191_set_norm(client, SAA7191_NORM_PAL); | ||
412 | case VIDEO_MODE_NTSC: | ||
413 | return saa7191_set_norm(client, SAA7191_NORM_NTSC); | ||
414 | case VIDEO_MODE_SECAM: | ||
415 | return saa7191_set_norm(client, SAA7191_NORM_SECAM); | ||
416 | default: | ||
417 | return -EINVAL; | ||
418 | } | ||
419 | break; | ||
420 | } | ||
421 | case DECODER_SET_INPUT: { | ||
422 | int *iarg = arg; | ||
423 | |||
424 | switch (client->adapter->id) { | ||
425 | case VINO_ADAPTER: | ||
426 | return saa7191_set_input(client, *iarg); | ||
427 | default: | ||
428 | if (*iarg != 0) | ||
429 | return -EINVAL; | ||
430 | } | ||
431 | break; | ||
432 | } | ||
433 | case DECODER_SET_OUTPUT: { | ||
434 | int *iarg = arg; | ||
435 | |||
436 | /* not much choice of outputs */ | ||
437 | if (*iarg != 0) | ||
438 | return -EINVAL; | ||
439 | break; | ||
440 | } | ||
441 | case DECODER_ENABLE_OUTPUT: { | ||
442 | /* Always enabled */ | ||
443 | break; | ||
444 | } | ||
445 | case DECODER_SET_PICTURE: { | ||
446 | struct video_picture *pic = arg; | ||
447 | unsigned val; | ||
448 | int err; | ||
449 | |||
450 | val = (pic->hue >> 8) - 0x80; | ||
451 | err = saa7191_write_reg(client, SAA7191_REG_HUEC, val); | ||
452 | if (err) | ||
453 | return -EIO; | ||
454 | break; | ||
455 | } | ||
456 | case DECODER_SAA7191_GET_STATUS: { | ||
457 | struct saa7191_status *status = arg; | ||
458 | unsigned char status_reg; | ||
459 | |||
460 | if (saa7191_read_status(client, &status_reg)) | ||
461 | return -EIO; | ||
462 | status->signal = ((status_reg & SAA7191_STATUS_HLCK) == 0) | ||
463 | ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED; | ||
464 | status->ntsc = (status_reg & SAA7191_STATUS_FIDT) | ||
465 | ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED; | ||
466 | status->color = (status_reg & SAA7191_STATUS_CODE) | ||
467 | ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED; | ||
468 | |||
469 | status->input = decoder->input; | ||
470 | status->norm = decoder->norm; | ||
471 | } | ||
472 | case DECODER_SAA7191_SET_NORM: { | ||
473 | int *norm = arg; | ||
474 | return saa7191_set_norm(client, *norm); | ||
475 | } | ||
476 | case DECODER_SAA7191_GET_CONTROLS: { | ||
477 | struct saa7191_control *ctrl = arg; | ||
478 | return saa7191_get_controls(client, ctrl); | ||
479 | } | ||
480 | case DECODER_SAA7191_SET_CONTROLS: { | ||
481 | struct saa7191_control *ctrl = arg; | ||
482 | return saa7191_set_controls(client, ctrl); | ||
483 | } | ||
484 | default: | ||
485 | return -EINVAL; | ||
486 | } | ||
487 | |||
488 | return 0; | ||
489 | } | ||
490 | |||
491 | static struct i2c_driver i2c_driver_saa7191 = { | ||
492 | .owner = THIS_MODULE, | ||
493 | .name = "saa7191", | ||
494 | .id = I2C_DRIVERID_SAA7191, | ||
495 | .flags = I2C_DF_NOTIFY, | ||
496 | .attach_adapter = saa7191_probe, | ||
497 | .detach_client = saa7191_detach, | ||
498 | .command = saa7191_command | ||
499 | }; | ||
500 | |||
501 | static int saa7191_init(void) | ||
502 | { | ||
503 | return i2c_add_driver(&i2c_driver_saa7191); | ||
504 | } | ||
505 | |||
506 | static void saa7191_exit(void) | ||
507 | { | ||
508 | i2c_del_driver(&i2c_driver_saa7191); | ||
509 | } | ||
510 | |||
511 | module_init(saa7191_init); | ||
512 | module_exit(saa7191_exit); | ||