xref: /linux/drivers/media/i2c/vpx3220.c (revision d91517839e5d95adc0cf4b28caa7af62a71de526)
1 /*
2  * vpx3220a, vpx3216b & vpx3214c video decoder driver version 0.0.1
3  *
4  * Copyright (C) 2001 Laurent Pinchart <lpinchart@freegates.be>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 
21 #include <linux/module.h>
22 #include <linux/init.h>
23 #include <linux/delay.h>
24 #include <linux/types.h>
25 #include <linux/slab.h>
26 #include <asm/uaccess.h>
27 #include <linux/i2c.h>
28 #include <linux/videodev2.h>
29 #include <media/v4l2-device.h>
30 #include <media/v4l2-ctrls.h>
31 
32 MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver");
33 MODULE_AUTHOR("Laurent Pinchart");
34 MODULE_LICENSE("GPL");
35 
36 static int debug;
37 module_param(debug, int, 0);
38 MODULE_PARM_DESC(debug, "Debug level (0-1)");
39 
40 
41 #define VPX_TIMEOUT_COUNT  10
42 
43 /* ----------------------------------------------------------------------- */
44 
45 struct vpx3220 {
46 	struct v4l2_subdev sd;
47 	struct v4l2_ctrl_handler hdl;
48 	unsigned char reg[255];
49 
50 	v4l2_std_id norm;
51 	int input;
52 	int enable;
53 };
54 
55 static inline struct vpx3220 *to_vpx3220(struct v4l2_subdev *sd)
56 {
57 	return container_of(sd, struct vpx3220, sd);
58 }
59 
60 static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
61 {
62 	return &container_of(ctrl->handler, struct vpx3220, hdl)->sd;
63 }
64 
65 static char *inputs[] = { "internal", "composite", "svideo" };
66 
67 /* ----------------------------------------------------------------------- */
68 
69 static inline int vpx3220_write(struct v4l2_subdev *sd, u8 reg, u8 value)
70 {
71 	struct i2c_client *client = v4l2_get_subdevdata(sd);
72 	struct vpx3220 *decoder = i2c_get_clientdata(client);
73 
74 	decoder->reg[reg] = value;
75 	return i2c_smbus_write_byte_data(client, reg, value);
76 }
77 
78 static inline int vpx3220_read(struct v4l2_subdev *sd, u8 reg)
79 {
80 	struct i2c_client *client = v4l2_get_subdevdata(sd);
81 
82 	return i2c_smbus_read_byte_data(client, reg);
83 }
84 
85 static int vpx3220_fp_status(struct v4l2_subdev *sd)
86 {
87 	unsigned char status;
88 	unsigned int i;
89 
90 	for (i = 0; i < VPX_TIMEOUT_COUNT; i++) {
91 		status = vpx3220_read(sd, 0x29);
92 
93 		if (!(status & 4))
94 			return 0;
95 
96 		udelay(10);
97 
98 		if (need_resched())
99 			cond_resched();
100 	}
101 
102 	return -1;
103 }
104 
105 static int vpx3220_fp_write(struct v4l2_subdev *sd, u8 fpaddr, u16 data)
106 {
107 	struct i2c_client *client = v4l2_get_subdevdata(sd);
108 
109 	/* Write the 16-bit address to the FPWR register */
110 	if (i2c_smbus_write_word_data(client, 0x27, swab16(fpaddr)) == -1) {
111 		v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
112 		return -1;
113 	}
114 
115 	if (vpx3220_fp_status(sd) < 0)
116 		return -1;
117 
118 	/* Write the 16-bit data to the FPDAT register */
119 	if (i2c_smbus_write_word_data(client, 0x28, swab16(data)) == -1) {
120 		v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
121 		return -1;
122 	}
123 
124 	return 0;
125 }
126 
127 static u16 vpx3220_fp_read(struct v4l2_subdev *sd, u16 fpaddr)
128 {
129 	struct i2c_client *client = v4l2_get_subdevdata(sd);
130 	s16 data;
131 
132 	/* Write the 16-bit address to the FPRD register */
133 	if (i2c_smbus_write_word_data(client, 0x26, swab16(fpaddr)) == -1) {
134 		v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
135 		return -1;
136 	}
137 
138 	if (vpx3220_fp_status(sd) < 0)
139 		return -1;
140 
141 	/* Read the 16-bit data from the FPDAT register */
142 	data = i2c_smbus_read_word_data(client, 0x28);
143 	if (data == -1) {
144 		v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
145 		return -1;
146 	}
147 
148 	return swab16(data);
149 }
150 
151 static int vpx3220_write_block(struct v4l2_subdev *sd, const u8 *data, unsigned int len)
152 {
153 	u8 reg;
154 	int ret = -1;
155 
156 	while (len >= 2) {
157 		reg = *data++;
158 		ret = vpx3220_write(sd, reg, *data++);
159 		if (ret < 0)
160 			break;
161 		len -= 2;
162 	}
163 
164 	return ret;
165 }
166 
167 static int vpx3220_write_fp_block(struct v4l2_subdev *sd,
168 		const u16 *data, unsigned int len)
169 {
170 	u8 reg;
171 	int ret = 0;
172 
173 	while (len > 1) {
174 		reg = *data++;
175 		ret |= vpx3220_fp_write(sd, reg, *data++);
176 		len -= 2;
177 	}
178 
179 	return ret;
180 }
181 
182 /* ---------------------------------------------------------------------- */
183 
184 static const unsigned short init_ntsc[] = {
185 	0x1c, 0x00,		/* NTSC tint angle */
186 	0x88, 17,		/* Window 1 vertical */
187 	0x89, 240,		/* Vertical lines in */
188 	0x8a, 240,		/* Vertical lines out */
189 	0x8b, 000,		/* Horizontal begin */
190 	0x8c, 640,		/* Horizontal length */
191 	0x8d, 640,		/* Number of pixels */
192 	0x8f, 0xc00,		/* Disable window 2 */
193 	0xf0, 0x73,		/* 13.5 MHz transport, Forced
194 				 * mode, latch windows */
195 	0xf2, 0x13,		/* NTSC M, composite input */
196 	0xe7, 0x1e1,		/* Enable vertical standard
197 				 * locking @ 240 lines */
198 };
199 
200 static const unsigned short init_pal[] = {
201 	0x88, 23,		/* Window 1 vertical begin */
202 	0x89, 288,		/* Vertical lines in (16 lines
203 				 * skipped by the VFE) */
204 	0x8a, 288,		/* Vertical lines out (16 lines
205 				 * skipped by the VFE) */
206 	0x8b, 16,		/* Horizontal begin */
207 	0x8c, 768,		/* Horizontal length */
208 	0x8d, 784, 		/* Number of pixels
209 				 * Must be >= Horizontal begin + Horizontal length */
210 	0x8f, 0xc00,		/* Disable window 2 */
211 	0xf0, 0x77,		/* 13.5 MHz transport, Forced
212 				 * mode, latch windows */
213 	0xf2, 0x3d1,		/* PAL B,G,H,I, composite input */
214 	0xe7, 0x241,		/* PAL/SECAM set to 288 lines */
215 };
216 
217 static const unsigned short init_secam[] = {
218 	0x88, 23,		/* Window 1 vertical begin */
219 	0x89, 288,		/* Vertical lines in (16 lines
220 				 * skipped by the VFE) */
221 	0x8a, 288,		/* Vertical lines out (16 lines
222 				 * skipped by the VFE) */
223 	0x8b, 16,		/* Horizontal begin */
224 	0x8c, 768,		/* Horizontal length */
225 	0x8d, 784,		/* Number of pixels
226 				 * Must be >= Horizontal begin + Horizontal length */
227 	0x8f, 0xc00,		/* Disable window 2 */
228 	0xf0, 0x77,		/* 13.5 MHz transport, Forced
229 				 * mode, latch windows */
230 	0xf2, 0x3d5,		/* SECAM, composite input */
231 	0xe7, 0x241,		/* PAL/SECAM set to 288 lines */
232 };
233 
234 static const unsigned char init_common[] = {
235 	0xf2, 0x00,		/* Disable all outputs */
236 	0x33, 0x0d,		/* Luma : VIN2, Chroma : CIN
237 				 * (clamp off) */
238 	0xd8, 0xa8,		/* HREF/VREF active high, VREF
239 				 * pulse = 2, Odd/Even flag */
240 	0x20, 0x03,		/* IF compensation 0dB/oct */
241 	0xe0, 0xff,		/* Open up all comparators */
242 	0xe1, 0x00,
243 	0xe2, 0x7f,
244 	0xe3, 0x80,
245 	0xe4, 0x7f,
246 	0xe5, 0x80,
247 	0xe6, 0x00,		/* Brightness set to 0 */
248 	0xe7, 0xe0,		/* Contrast to 1.0, noise shaping
249 				 * 10 to 8 2-bit error diffusion */
250 	0xe8, 0xf8,		/* YUV422, CbCr binary offset,
251 				 * ... (p.32) */
252 	0xea, 0x18,		/* LLC2 connected, output FIFO
253 				 * reset with VACTintern */
254 	0xf0, 0x8a,		/* Half full level to 10, bus
255 				 * shuffler [7:0, 23:16, 15:8] */
256 	0xf1, 0x18,		/* Single clock, sync mode, no
257 				 * FE delay, no HLEN counter */
258 	0xf8, 0x12,		/* Port A, PIXCLK, HF# & FE#
259 				 * strength to 2 */
260 	0xf9, 0x24,		/* Port B, HREF, VREF, PREF &
261 				 * ALPHA strength to 4 */
262 };
263 
264 static const unsigned short init_fp[] = {
265 	0x59, 0,
266 	0xa0, 2070,		/* ACC reference */
267 	0xa3, 0,
268 	0xa4, 0,
269 	0xa8, 30,
270 	0xb2, 768,
271 	0xbe, 27,
272 	0x58, 0,
273 	0x26, 0,
274 	0x4b, 0x298,		/* PLL gain */
275 };
276 
277 
278 static int vpx3220_init(struct v4l2_subdev *sd, u32 val)
279 {
280 	struct vpx3220 *decoder = to_vpx3220(sd);
281 
282 	vpx3220_write_block(sd, init_common, sizeof(init_common));
283 	vpx3220_write_fp_block(sd, init_fp, sizeof(init_fp) >> 1);
284 	if (decoder->norm & V4L2_STD_NTSC)
285 		vpx3220_write_fp_block(sd, init_ntsc, sizeof(init_ntsc) >> 1);
286 	else if (decoder->norm & V4L2_STD_PAL)
287 		vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
288 	else if (decoder->norm & V4L2_STD_SECAM)
289 		vpx3220_write_fp_block(sd, init_secam, sizeof(init_secam) >> 1);
290 	else
291 		vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
292 	return 0;
293 }
294 
295 static int vpx3220_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd)
296 {
297 	int res = V4L2_IN_ST_NO_SIGNAL, status;
298 	v4l2_std_id std = pstd ? *pstd : V4L2_STD_ALL;
299 
300 	status = vpx3220_fp_read(sd, 0x0f3);
301 
302 	v4l2_dbg(1, debug, sd, "status: 0x%04x\n", status);
303 
304 	if (status < 0)
305 		return status;
306 
307 	if ((status & 0x20) == 0) {
308 		res = 0;
309 
310 		switch (status & 0x18) {
311 		case 0x00:
312 		case 0x10:
313 		case 0x14:
314 		case 0x18:
315 			std &= V4L2_STD_PAL;
316 			break;
317 
318 		case 0x08:
319 			std &= V4L2_STD_SECAM;
320 			break;
321 
322 		case 0x04:
323 		case 0x0c:
324 		case 0x1c:
325 			std &= V4L2_STD_NTSC;
326 			break;
327 		}
328 	} else {
329 		std = V4L2_STD_UNKNOWN;
330 	}
331 	if (pstd)
332 		*pstd = std;
333 	if (pstatus)
334 		*pstatus = res;
335 	return 0;
336 }
337 
338 static int vpx3220_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
339 {
340 	v4l2_dbg(1, debug, sd, "querystd\n");
341 	return vpx3220_status(sd, NULL, std);
342 }
343 
344 static int vpx3220_g_input_status(struct v4l2_subdev *sd, u32 *status)
345 {
346 	v4l2_dbg(1, debug, sd, "g_input_status\n");
347 	return vpx3220_status(sd, status, NULL);
348 }
349 
350 static int vpx3220_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
351 {
352 	struct vpx3220 *decoder = to_vpx3220(sd);
353 	int temp_input;
354 
355 	/* Here we back up the input selection because it gets
356 	   overwritten when we fill the registers with the
357 	   chosen video norm */
358 	temp_input = vpx3220_fp_read(sd, 0xf2);
359 
360 	v4l2_dbg(1, debug, sd, "s_std %llx\n", (unsigned long long)std);
361 	if (std & V4L2_STD_NTSC) {
362 		vpx3220_write_fp_block(sd, init_ntsc, sizeof(init_ntsc) >> 1);
363 		v4l2_dbg(1, debug, sd, "norm switched to NTSC\n");
364 	} else if (std & V4L2_STD_PAL) {
365 		vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
366 		v4l2_dbg(1, debug, sd, "norm switched to PAL\n");
367 	} else if (std & V4L2_STD_SECAM) {
368 		vpx3220_write_fp_block(sd, init_secam, sizeof(init_secam) >> 1);
369 		v4l2_dbg(1, debug, sd, "norm switched to SECAM\n");
370 	} else {
371 		return -EINVAL;
372 	}
373 
374 	decoder->norm = std;
375 
376 	/* And here we set the backed up video input again */
377 	vpx3220_fp_write(sd, 0xf2, temp_input | 0x0010);
378 	udelay(10);
379 	return 0;
380 }
381 
382 static int vpx3220_s_routing(struct v4l2_subdev *sd,
383 			     u32 input, u32 output, u32 config)
384 {
385 	int data;
386 
387 	/* RJ:   input = 0: ST8 (PCTV) input
388 		 input = 1: COMPOSITE  input
389 		 input = 2: SVHS       input  */
390 
391 	const int input_vals[3][2] = {
392 		{0x0c, 0},
393 		{0x0d, 0},
394 		{0x0e, 1}
395 	};
396 
397 	if (input > 2)
398 		return -EINVAL;
399 
400 	v4l2_dbg(1, debug, sd, "input switched to %s\n", inputs[input]);
401 
402 	vpx3220_write(sd, 0x33, input_vals[input][0]);
403 
404 	data = vpx3220_fp_read(sd, 0xf2) & ~(0x0020);
405 	if (data < 0)
406 		return data;
407 	/* 0x0010 is required to latch the setting */
408 	vpx3220_fp_write(sd, 0xf2,
409 			data | (input_vals[input][1] << 5) | 0x0010);
410 
411 	udelay(10);
412 	return 0;
413 }
414 
415 static int vpx3220_s_stream(struct v4l2_subdev *sd, int enable)
416 {
417 	v4l2_dbg(1, debug, sd, "s_stream %s\n", enable ? "on" : "off");
418 
419 	vpx3220_write(sd, 0xf2, (enable ? 0x1b : 0x00));
420 	return 0;
421 }
422 
423 static int vpx3220_s_ctrl(struct v4l2_ctrl *ctrl)
424 {
425 	struct v4l2_subdev *sd = to_sd(ctrl);
426 
427 	switch (ctrl->id) {
428 	case V4L2_CID_BRIGHTNESS:
429 		vpx3220_write(sd, 0xe6, ctrl->val);
430 		return 0;
431 	case V4L2_CID_CONTRAST:
432 		/* Bit 7 and 8 is for noise shaping */
433 		vpx3220_write(sd, 0xe7, ctrl->val + 192);
434 		return 0;
435 	case V4L2_CID_SATURATION:
436 		vpx3220_fp_write(sd, 0xa0, ctrl->val);
437 		return 0;
438 	case V4L2_CID_HUE:
439 		vpx3220_fp_write(sd, 0x1c, ctrl->val);
440 		return 0;
441 	}
442 	return -EINVAL;
443 }
444 
445 /* ----------------------------------------------------------------------- */
446 
447 static const struct v4l2_ctrl_ops vpx3220_ctrl_ops = {
448 	.s_ctrl = vpx3220_s_ctrl,
449 };
450 
451 static const struct v4l2_subdev_core_ops vpx3220_core_ops = {
452 	.init = vpx3220_init,
453 	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
454 	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
455 	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
456 	.g_ctrl = v4l2_subdev_g_ctrl,
457 	.s_ctrl = v4l2_subdev_s_ctrl,
458 	.queryctrl = v4l2_subdev_queryctrl,
459 	.querymenu = v4l2_subdev_querymenu,
460 	.s_std = vpx3220_s_std,
461 };
462 
463 static const struct v4l2_subdev_video_ops vpx3220_video_ops = {
464 	.s_routing = vpx3220_s_routing,
465 	.s_stream = vpx3220_s_stream,
466 	.querystd = vpx3220_querystd,
467 	.g_input_status = vpx3220_g_input_status,
468 };
469 
470 static const struct v4l2_subdev_ops vpx3220_ops = {
471 	.core = &vpx3220_core_ops,
472 	.video = &vpx3220_video_ops,
473 };
474 
475 /* -----------------------------------------------------------------------
476  * Client management code
477  */
478 
479 static int vpx3220_probe(struct i2c_client *client,
480 			const struct i2c_device_id *id)
481 {
482 	struct vpx3220 *decoder;
483 	struct v4l2_subdev *sd;
484 	const char *name = NULL;
485 	u8 ver;
486 	u16 pn;
487 
488 	/* Check if the adapter supports the needed features */
489 	if (!i2c_check_functionality(client->adapter,
490 		I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
491 		return -ENODEV;
492 
493 	decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL);
494 	if (decoder == NULL)
495 		return -ENOMEM;
496 	sd = &decoder->sd;
497 	v4l2_i2c_subdev_init(sd, client, &vpx3220_ops);
498 	decoder->norm = V4L2_STD_PAL;
499 	decoder->input = 0;
500 	decoder->enable = 1;
501 	v4l2_ctrl_handler_init(&decoder->hdl, 4);
502 	v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops,
503 		V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
504 	v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops,
505 		V4L2_CID_CONTRAST, 0, 63, 1, 32);
506 	v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops,
507 		V4L2_CID_SATURATION, 0, 4095, 1, 2048);
508 	v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops,
509 		V4L2_CID_HUE, -512, 511, 1, 0);
510 	sd->ctrl_handler = &decoder->hdl;
511 	if (decoder->hdl.error) {
512 		int err = decoder->hdl.error;
513 
514 		v4l2_ctrl_handler_free(&decoder->hdl);
515 		return err;
516 	}
517 	v4l2_ctrl_handler_setup(&decoder->hdl);
518 
519 	ver = i2c_smbus_read_byte_data(client, 0x00);
520 	pn = (i2c_smbus_read_byte_data(client, 0x02) << 8) +
521 		i2c_smbus_read_byte_data(client, 0x01);
522 	if (ver == 0xec) {
523 		switch (pn) {
524 		case 0x4680:
525 			name = "vpx3220a";
526 			break;
527 		case 0x4260:
528 			name = "vpx3216b";
529 			break;
530 		case 0x4280:
531 			name = "vpx3214c";
532 			break;
533 		}
534 	}
535 	if (name)
536 		v4l2_info(sd, "%s found @ 0x%x (%s)\n", name,
537 			client->addr << 1, client->adapter->name);
538 	else
539 		v4l2_info(sd, "chip (%02x:%04x) found @ 0x%x (%s)\n",
540 			ver, pn, client->addr << 1, client->adapter->name);
541 
542 	vpx3220_write_block(sd, init_common, sizeof(init_common));
543 	vpx3220_write_fp_block(sd, init_fp, sizeof(init_fp) >> 1);
544 	/* Default to PAL */
545 	vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
546 	return 0;
547 }
548 
549 static int vpx3220_remove(struct i2c_client *client)
550 {
551 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
552 	struct vpx3220 *decoder = to_vpx3220(sd);
553 
554 	v4l2_device_unregister_subdev(sd);
555 	v4l2_ctrl_handler_free(&decoder->hdl);
556 
557 	return 0;
558 }
559 
560 static const struct i2c_device_id vpx3220_id[] = {
561 	{ "vpx3220a", 0 },
562 	{ "vpx3216b", 0 },
563 	{ "vpx3214c", 0 },
564 	{ }
565 };
566 MODULE_DEVICE_TABLE(i2c, vpx3220_id);
567 
568 static struct i2c_driver vpx3220_driver = {
569 	.driver = {
570 		.owner	= THIS_MODULE,
571 		.name	= "vpx3220",
572 	},
573 	.probe		= vpx3220_probe,
574 	.remove		= vpx3220_remove,
575 	.id_table	= vpx3220_id,
576 };
577 
578 module_i2c_driver(vpx3220_driver);
579