1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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/uaccess.h>
35#include <linux/i2c.h>
36#include <linux/videodev2.h>
37#include <media/v4l2-device.h>
38#include <media/v4l2-chip-ident.h>
39#include <media/v4l2-ctrls.h>
40
41MODULE_DESCRIPTION("Philips SAA7110 video decoder driver");
42MODULE_AUTHOR("Pauline Middelink");
43MODULE_LICENSE("GPL");
44
45
46static int debug;
47module_param(debug, int, 0);
48MODULE_PARM_DESC(debug, "Debug level (0-1)");
49
50#define SAA7110_MAX_INPUT 9
51#define SAA7110_MAX_OUTPUT 1
52
53#define SAA7110_NR_REG 0x35
54
55struct saa7110 {
56 struct v4l2_subdev sd;
57 struct v4l2_ctrl_handler hdl;
58 u8 reg[SAA7110_NR_REG];
59
60 v4l2_std_id norm;
61 int input;
62 int enable;
63
64 wait_queue_head_t wq;
65};
66
67static inline struct saa7110 *to_saa7110(struct v4l2_subdev *sd)
68{
69 return container_of(sd, struct saa7110, sd);
70}
71
72static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
73{
74 return &container_of(ctrl->handler, struct saa7110, hdl)->sd;
75}
76
77
78
79
80
81static int saa7110_write(struct v4l2_subdev *sd, u8 reg, u8 value)
82{
83 struct i2c_client *client = v4l2_get_subdevdata(sd);
84 struct saa7110 *decoder = to_saa7110(sd);
85
86 decoder->reg[reg] = value;
87 return i2c_smbus_write_byte_data(client, reg, value);
88}
89
90static int saa7110_write_block(struct v4l2_subdev *sd, const u8 *data, unsigned int len)
91{
92 struct i2c_client *client = v4l2_get_subdevdata(sd);
93 struct saa7110 *decoder = to_saa7110(sd);
94 int ret = -1;
95 u8 reg = *data;
96
97
98 if (reg + (len - 1) > SAA7110_NR_REG)
99 return ret;
100
101
102
103 if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
104 ret = i2c_master_send(client, data, len);
105
106
107 memcpy(decoder->reg + reg, data + 1, len - 1);
108 } else {
109 for (++data, --len; len; len--) {
110 ret = saa7110_write(sd, reg++, *data++);
111 if (ret < 0)
112 break;
113 }
114 }
115
116 return ret;
117}
118
119static inline int saa7110_read(struct v4l2_subdev *sd)
120{
121 struct i2c_client *client = v4l2_get_subdevdata(sd);
122
123 return i2c_smbus_read_byte(client);
124}
125
126
127
128
129
130#define FRESP_06H_COMPST 0x03
131#define FRESP_06H_SVIDEO 0x83
132
133
134static int saa7110_selmux(struct v4l2_subdev *sd, int chan)
135{
136 static const unsigned char modes[9][8] = {
137
138 {FRESP_06H_COMPST, 0xD9, 0x17, 0x40, 0x03,
139 0x44, 0x75, 0x16},
140
141 {FRESP_06H_COMPST, 0xD8, 0x17, 0x40, 0x03,
142 0x44, 0x75, 0x16},
143
144 {FRESP_06H_COMPST, 0xBA, 0x07, 0x91, 0x03,
145 0x60, 0xB5, 0x05},
146
147 {FRESP_06H_COMPST, 0xB8, 0x07, 0x91, 0x03,
148 0x60, 0xB5, 0x05},
149
150 {FRESP_06H_COMPST, 0x7C, 0x07, 0xD2, 0x83,
151 0x60, 0xB5, 0x03},
152
153 {FRESP_06H_COMPST, 0x78, 0x07, 0xD2, 0x83,
154 0x60, 0xB5, 0x03},
155
156 {FRESP_06H_SVIDEO, 0x59, 0x17, 0x42, 0xA3,
157 0x44, 0x75, 0x12},
158
159 {FRESP_06H_SVIDEO, 0x9A, 0x17, 0xB1, 0x13,
160 0x60, 0xB5, 0x14},
161
162 {FRESP_06H_SVIDEO, 0x3C, 0x27, 0xC1, 0x23,
163 0x44, 0x75, 0x21}
164 };
165 struct saa7110 *decoder = to_saa7110(sd);
166 const unsigned char *ptr = modes[chan];
167
168 saa7110_write(sd, 0x06, ptr[0]);
169 saa7110_write(sd, 0x20, ptr[1]);
170 saa7110_write(sd, 0x21, ptr[2]);
171 saa7110_write(sd, 0x22, ptr[3]);
172 saa7110_write(sd, 0x2C, ptr[4]);
173 saa7110_write(sd, 0x30, ptr[5]);
174 saa7110_write(sd, 0x31, ptr[6]);
175 saa7110_write(sd, 0x21, ptr[7]);
176 decoder->input = chan;
177
178 return 0;
179}
180
181static const unsigned char initseq[1 + SAA7110_NR_REG] = {
182 0, 0x4C, 0x3C, 0x0D, 0xEF, 0xBD, 0xF2, 0x03, 0x00,
183 0xF8, 0xF8, 0x60, 0x60, 0x00, 0x86, 0x18, 0x90,
184 0x00, 0x59, 0x40, 0x46, 0x42, 0x1A, 0xFF, 0xDA,
185 0xF2, 0x8B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
186 0xD9, 0x16, 0x40, 0x41, 0x80, 0x41, 0x80, 0x4F,
187 0xFE, 0x01, 0xCF, 0x0F, 0x03, 0x01, 0x03, 0x0C,
188 0x44, 0x71, 0x02, 0x8C, 0x02
189};
190
191static v4l2_std_id determine_norm(struct v4l2_subdev *sd)
192{
193 DEFINE_WAIT(wait);
194 struct saa7110 *decoder = to_saa7110(sd);
195 int status;
196
197
198 saa7110_write_block(sd, initseq, sizeof(initseq));
199 saa7110_selmux(sd, decoder->input);
200 prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
201 schedule_timeout(msecs_to_jiffies(250));
202 finish_wait(&decoder->wq, &wait);
203 status = saa7110_read(sd);
204 if (status & 0x40) {
205 v4l2_dbg(1, debug, sd, "status=0x%02x (no signal)\n", status);
206 return decoder->norm;
207 }
208 if ((status & 3) == 0) {
209 saa7110_write(sd, 0x06, 0x83);
210 if (status & 0x20) {
211 v4l2_dbg(1, debug, sd, "status=0x%02x (NTSC/no color)\n", status);
212
213 return V4L2_STD_NTSC;
214 }
215 v4l2_dbg(1, debug, sd, "status=0x%02x (PAL/no color)\n", status);
216
217 return V4L2_STD_PAL;
218 }
219
220 if (status & 0x20) {
221 v4l2_dbg(1, debug, sd, "status=0x%02x (NTSC)\n", status);
222 saa7110_write(sd, 0x0D, 0x86);
223 saa7110_write(sd, 0x0F, 0x50);
224 saa7110_write(sd, 0x11, 0x2C);
225
226 return V4L2_STD_NTSC;
227 }
228
229
230 saa7110_write(sd, 0x0D, 0x86);
231 saa7110_write(sd, 0x0F, 0x10);
232 saa7110_write(sd, 0x11, 0x59);
233
234
235 prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
236 schedule_timeout(msecs_to_jiffies(250));
237 finish_wait(&decoder->wq, &wait);
238
239 status = saa7110_read(sd);
240 if ((status & 0x03) == 0x01) {
241 v4l2_dbg(1, debug, sd, "status=0x%02x (SECAM)\n", status);
242 saa7110_write(sd, 0x0D, 0x87);
243 return V4L2_STD_SECAM;
244 }
245 v4l2_dbg(1, debug, sd, "status=0x%02x (PAL)\n", status);
246 return V4L2_STD_PAL;
247}
248
249static int saa7110_g_input_status(struct v4l2_subdev *sd, u32 *pstatus)
250{
251 struct saa7110 *decoder = to_saa7110(sd);
252 int res = V4L2_IN_ST_NO_SIGNAL;
253 int status = saa7110_read(sd);
254
255 v4l2_dbg(1, debug, sd, "status=0x%02x norm=%llx\n",
256 status, (unsigned long long)decoder->norm);
257 if (!(status & 0x40))
258 res = 0;
259 if (!(status & 0x03))
260 res |= V4L2_IN_ST_NO_COLOR;
261
262 *pstatus = res;
263 return 0;
264}
265
266static int saa7110_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
267{
268 *(v4l2_std_id *)std = determine_norm(sd);
269 return 0;
270}
271
272static int saa7110_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
273{
274 struct saa7110 *decoder = to_saa7110(sd);
275
276 if (decoder->norm != std) {
277 decoder->norm = std;
278
279 if (std & V4L2_STD_NTSC) {
280 saa7110_write(sd, 0x0D, 0x86);
281 saa7110_write(sd, 0x0F, 0x50);
282 saa7110_write(sd, 0x11, 0x2C);
283
284 v4l2_dbg(1, debug, sd, "switched to NTSC\n");
285 } else if (std & V4L2_STD_PAL) {
286 saa7110_write(sd, 0x0D, 0x86);
287 saa7110_write(sd, 0x0F, 0x10);
288 saa7110_write(sd, 0x11, 0x59);
289
290 v4l2_dbg(1, debug, sd, "switched to PAL\n");
291 } else if (std & V4L2_STD_SECAM) {
292 saa7110_write(sd, 0x0D, 0x87);
293 saa7110_write(sd, 0x0F, 0x10);
294 saa7110_write(sd, 0x11, 0x59);
295
296 v4l2_dbg(1, debug, sd, "switched to SECAM\n");
297 } else {
298 return -EINVAL;
299 }
300 }
301 return 0;
302}
303
304static int saa7110_s_routing(struct v4l2_subdev *sd,
305 u32 input, u32 output, u32 config)
306{
307 struct saa7110 *decoder = to_saa7110(sd);
308
309 if (input >= SAA7110_MAX_INPUT) {
310 v4l2_dbg(1, debug, sd, "input=%d not available\n", input);
311 return -EINVAL;
312 }
313 if (decoder->input != input) {
314 saa7110_selmux(sd, input);
315 v4l2_dbg(1, debug, sd, "switched to input=%d\n", input);
316 }
317 return 0;
318}
319
320static int saa7110_s_stream(struct v4l2_subdev *sd, int enable)
321{
322 struct saa7110 *decoder = to_saa7110(sd);
323
324 if (decoder->enable != enable) {
325 decoder->enable = enable;
326 saa7110_write(sd, 0x0E, enable ? 0x18 : 0x80);
327 v4l2_dbg(1, debug, sd, "YUV %s\n", enable ? "on" : "off");
328 }
329 return 0;
330}
331
332static int saa7110_s_ctrl(struct v4l2_ctrl *ctrl)
333{
334 struct v4l2_subdev *sd = to_sd(ctrl);
335
336 switch (ctrl->id) {
337 case V4L2_CID_BRIGHTNESS:
338 saa7110_write(sd, 0x19, ctrl->val);
339 break;
340 case V4L2_CID_CONTRAST:
341 saa7110_write(sd, 0x13, ctrl->val);
342 break;
343 case V4L2_CID_SATURATION:
344 saa7110_write(sd, 0x12, ctrl->val);
345 break;
346 case V4L2_CID_HUE:
347 saa7110_write(sd, 0x07, ctrl->val);
348 break;
349 default:
350 return -EINVAL;
351 }
352 return 0;
353}
354
355static int saa7110_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
356{
357 struct i2c_client *client = v4l2_get_subdevdata(sd);
358
359 return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7110, 0);
360}
361
362
363
364static const struct v4l2_ctrl_ops saa7110_ctrl_ops = {
365 .s_ctrl = saa7110_s_ctrl,
366};
367
368static const struct v4l2_subdev_core_ops saa7110_core_ops = {
369 .g_chip_ident = saa7110_g_chip_ident,
370 .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
371 .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
372 .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
373 .g_ctrl = v4l2_subdev_g_ctrl,
374 .s_ctrl = v4l2_subdev_s_ctrl,
375 .queryctrl = v4l2_subdev_queryctrl,
376 .querymenu = v4l2_subdev_querymenu,
377 .s_std = saa7110_s_std,
378};
379
380static const struct v4l2_subdev_video_ops saa7110_video_ops = {
381 .s_routing = saa7110_s_routing,
382 .s_stream = saa7110_s_stream,
383 .querystd = saa7110_querystd,
384 .g_input_status = saa7110_g_input_status,
385};
386
387static const struct v4l2_subdev_ops saa7110_ops = {
388 .core = &saa7110_core_ops,
389 .video = &saa7110_video_ops,
390};
391
392
393
394static int saa7110_probe(struct i2c_client *client,
395 const struct i2c_device_id *id)
396{
397 struct saa7110 *decoder;
398 struct v4l2_subdev *sd;
399 int rv;
400
401
402 if (!i2c_check_functionality(client->adapter,
403 I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
404 return -ENODEV;
405
406 v4l_info(client, "chip found @ 0x%x (%s)\n",
407 client->addr << 1, client->adapter->name);
408
409 decoder = kzalloc(sizeof(struct saa7110), GFP_KERNEL);
410 if (!decoder)
411 return -ENOMEM;
412 sd = &decoder->sd;
413 v4l2_i2c_subdev_init(sd, client, &saa7110_ops);
414 decoder->norm = V4L2_STD_PAL;
415 decoder->input = 0;
416 decoder->enable = 1;
417 v4l2_ctrl_handler_init(&decoder->hdl, 2);
418 v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops,
419 V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
420 v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops,
421 V4L2_CID_CONTRAST, 0, 127, 1, 64);
422 v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops,
423 V4L2_CID_SATURATION, 0, 127, 1, 64);
424 v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops,
425 V4L2_CID_HUE, -128, 127, 1, 0);
426 sd->ctrl_handler = &decoder->hdl;
427 if (decoder->hdl.error) {
428 int err = decoder->hdl.error;
429
430 v4l2_ctrl_handler_free(&decoder->hdl);
431 kfree(decoder);
432 return err;
433 }
434 v4l2_ctrl_handler_setup(&decoder->hdl);
435
436 init_waitqueue_head(&decoder->wq);
437
438 rv = saa7110_write_block(sd, initseq, sizeof(initseq));
439 if (rv < 0) {
440 v4l2_dbg(1, debug, sd, "init status %d\n", rv);
441 } else {
442 int ver, status;
443 saa7110_write(sd, 0x21, 0x10);
444 saa7110_write(sd, 0x0e, 0x18);
445 saa7110_write(sd, 0x0D, 0x04);
446 ver = saa7110_read(sd);
447 saa7110_write(sd, 0x0D, 0x06);
448
449 status = saa7110_read(sd);
450 v4l2_dbg(1, debug, sd, "version %x, status=0x%02x\n",
451 ver, status);
452 saa7110_write(sd, 0x0D, 0x86);
453 saa7110_write(sd, 0x0F, 0x10);
454 saa7110_write(sd, 0x11, 0x59);
455
456 }
457
458
459
460
461
462 return 0;
463}
464
465static int saa7110_remove(struct i2c_client *client)
466{
467 struct v4l2_subdev *sd = i2c_get_clientdata(client);
468 struct saa7110 *decoder = to_saa7110(sd);
469
470 v4l2_device_unregister_subdev(sd);
471 v4l2_ctrl_handler_free(&decoder->hdl);
472 kfree(decoder);
473 return 0;
474}
475
476
477
478static const struct i2c_device_id saa7110_id[] = {
479 { "saa7110", 0 },
480 { }
481};
482MODULE_DEVICE_TABLE(i2c, saa7110_id);
483
484static struct i2c_driver saa7110_driver = {
485 .driver = {
486 .owner = THIS_MODULE,
487 .name = "saa7110",
488 },
489 .probe = saa7110_probe,
490 .remove = saa7110_remove,
491 .id_table = saa7110_id,
492};
493
494module_i2c_driver(saa7110_driver);
495