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