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