bt866.c revision c18fdcf65732b87f6015ea4e423fc7abf7c26dd2
1/*
2    bt866 - BT866 Digital Video Encoder (Rockwell Part)
3
4    Copyright (C) 1999 Mike Bernson <mike@mlb.org>
5    Copyright (C) 1998 Dave Perks <dperks@ibm.net>
6
7    Modifications for LML33/DC10plus unified driver
8    Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
9
10    This code was modify/ported from the saa7111 driver written
11    by Dave Perks.
12
13    This code was adapted for the bt866 by Christer Weinigel and ported
14    to 2.6 by Martin Samuelsson.
15
16    This program is free software; you can redistribute it and/or modify
17    it under the terms of the GNU General Public License as published by
18    the Free Software Foundation; either version 2 of the License, or
19    (at your option) any later version.
20
21    This program is distributed in the hope that it will be useful,
22    but WITHOUT ANY WARRANTY; without even the implied warranty of
23    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24    GNU General Public License for more details.
25
26    You should have received a copy of the GNU General Public License
27    along with this program; if not, write to the Free Software
28    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29*/
30
31#include <linux/module.h>
32#include <linux/types.h>
33#include <linux/ioctl.h>
34#include <asm/uaccess.h>
35#include <linux/i2c.h>
36#include <linux/i2c-id.h>
37#include <linux/videodev.h>
38#include <linux/video_encoder.h>
39#include <media/v4l2-common.h>
40#include <media/v4l2-i2c-drv-legacy.h>
41
42MODULE_DESCRIPTION("Brooktree-866 video encoder driver");
43MODULE_AUTHOR("Mike Bernson & Dave Perks");
44MODULE_LICENSE("GPL");
45
46static int debug;
47module_param(debug, int, 0);
48MODULE_PARM_DESC(debug, "Debug level (0-1)");
49
50/* ----------------------------------------------------------------------- */
51
52struct bt866 {
53	u8 reg[256];
54
55	int norm;
56	int enable;
57	int bright;
58	int contrast;
59	int hue;
60	int sat;
61};
62
63static int bt866_write(struct i2c_client *client, u8 subaddr, u8 data)
64{
65	struct bt866 *encoder = i2c_get_clientdata(client);
66	u8 buffer[2];
67	int err;
68
69	buffer[0] = subaddr;
70	buffer[1] = data;
71
72	encoder->reg[subaddr] = data;
73
74	v4l_dbg(1, debug, client, "write 0x%02x = 0x%02x\n", subaddr, data);
75
76	for (err = 0; err < 3;) {
77		if (i2c_master_send(client, buffer, 2) == 2)
78			break;
79		err++;
80		v4l_warn(client, "error #%d writing to 0x%02x\n",
81				err, subaddr);
82		schedule_timeout_interruptible(msecs_to_jiffies(100));
83	}
84	if (err == 3) {
85		v4l_warn(client, "giving up\n");
86		return -1;
87	}
88
89	return 0;
90}
91
92static int bt866_command(struct i2c_client *client, unsigned cmd, void *arg)
93{
94	struct bt866 *encoder = i2c_get_clientdata(client);
95
96	switch (cmd) {
97	case ENCODER_GET_CAPABILITIES:
98	{
99		struct video_encoder_capability *cap = arg;
100
101		v4l_dbg(1, debug, client, "get capabilities\n");
102
103		cap->flags
104			= VIDEO_ENCODER_PAL
105			| VIDEO_ENCODER_NTSC
106			| VIDEO_ENCODER_CCIR;
107		cap->inputs = 2;
108		cap->outputs = 1;
109		break;
110	}
111
112	case ENCODER_SET_NORM:
113	{
114		int *iarg = arg;
115
116		v4l_dbg(1, debug, client, "set norm %d\n", *iarg);
117
118		switch (*iarg) {
119		case VIDEO_MODE_NTSC:
120			break;
121
122		case VIDEO_MODE_PAL:
123			break;
124
125		default:
126			return -EINVAL;
127		}
128		encoder->norm = *iarg;
129		break;
130	}
131
132	case ENCODER_SET_INPUT:
133	{
134		int *iarg = arg;
135		static const __u8 init[] = {
136			0xc8, 0xcc, /* CRSCALE */
137			0xca, 0x91, /* CBSCALE */
138			0xcc, 0x24, /* YC16 | OSDNUM */
139			0xda, 0x00, /*  */
140			0xdc, 0x24, /* SETMODE | PAL */
141			0xde, 0x02, /* EACTIVE */
142
143			/* overlay colors */
144			0x70, 0xEB, 0x90, 0x80, 0xB0, 0x80, /* white */
145			0x72, 0xA2, 0x92, 0x8E, 0xB2, 0x2C, /* yellow */
146			0x74, 0x83, 0x94, 0x2C, 0xB4, 0x9C, /* cyan */
147			0x76, 0x70, 0x96, 0x3A, 0xB6, 0x48, /* green */
148			0x78, 0x54, 0x98, 0xC6, 0xB8, 0xB8, /* magenta */
149			0x7A, 0x41, 0x9A, 0xD4, 0xBA, 0x64, /* red */
150			0x7C, 0x23, 0x9C, 0x72, 0xBC, 0xD4, /* blue */
151			0x7E, 0x10, 0x9E, 0x80, 0xBE, 0x80, /* black */
152
153			0x60, 0xEB, 0x80, 0x80, 0xc0, 0x80, /* white */
154			0x62, 0xA2, 0x82, 0x8E, 0xc2, 0x2C, /* yellow */
155			0x64, 0x83, 0x84, 0x2C, 0xc4, 0x9C, /* cyan */
156			0x66, 0x70, 0x86, 0x3A, 0xc6, 0x48, /* green */
157			0x68, 0x54, 0x88, 0xC6, 0xc8, 0xB8, /* magenta */
158			0x6A, 0x41, 0x8A, 0xD4, 0xcA, 0x64, /* red */
159			0x6C, 0x23, 0x8C, 0x72, 0xcC, 0xD4, /* blue */
160			0x6E, 0x10, 0x8E, 0x80, 0xcE, 0x80, /* black */
161		};
162		int i;
163		u8 val;
164
165		for (i = 0; i < ARRAY_SIZE(init) / 2; i += 2)
166			bt866_write(client, init[i], init[i+1]);
167
168		val = encoder->reg[0xdc];
169
170		if (*iarg == 0)
171			val |= 0x40; /* CBSWAP */
172		else
173			val &= ~0x40; /* !CBSWAP */
174
175		bt866_write(client, 0xdc, val);
176
177		val = encoder->reg[0xcc];
178		if (*iarg == 2)
179			val |= 0x01; /* OSDBAR */
180		else
181			val &= ~0x01; /* !OSDBAR */
182		bt866_write(client, 0xcc, val);
183
184		v4l_dbg(1, debug, client, "set input %d\n", *iarg);
185
186		switch (*iarg) {
187		case 0:
188			break;
189		case 1:
190			break;
191		default:
192			return -EINVAL;
193		}
194		break;
195	}
196
197	case ENCODER_SET_OUTPUT:
198	{
199		int *iarg = arg;
200
201		v4l_dbg(1, debug, client, "set output %d\n", *iarg);
202
203		/* not much choice of outputs */
204		if (*iarg != 0)
205			return -EINVAL;
206		break;
207	}
208
209	case ENCODER_ENABLE_OUTPUT:
210	{
211		int *iarg = arg;
212		encoder->enable = !!*iarg;
213
214		v4l_dbg(1, debug, client, "enable output %d\n", encoder->enable);
215		break;
216	}
217
218	case 4711:
219	{
220		int *iarg = arg;
221		__u8 val;
222
223		v4l_dbg(1, debug, client, "square %d\n", *iarg);
224
225		val = encoder->reg[0xdc];
226		if (*iarg)
227			val |= 1; /* SQUARE */
228		else
229			val &= ~1; /* !SQUARE */
230		bt866_write(client, 0xdc, val);
231		break;
232	}
233
234	default:
235		return -EINVAL;
236	}
237
238	return 0;
239}
240
241static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
242
243I2C_CLIENT_INSMOD;
244
245static int bt866_probe(struct i2c_client *client,
246			const struct i2c_device_id *id)
247{
248	struct bt866 *encoder;
249
250	v4l_info(client, "chip found @ 0x%x (%s)\n",
251			client->addr << 1, client->adapter->name);
252
253	encoder = kzalloc(sizeof(*encoder), GFP_KERNEL);
254	if (encoder == NULL)
255		return -ENOMEM;
256
257	i2c_set_clientdata(client, encoder);
258	return 0;
259}
260
261static int bt866_remove(struct i2c_client *client)
262{
263	kfree(i2c_get_clientdata(client));
264	return 0;
265}
266
267static int bt866_legacy_probe(struct i2c_adapter *adapter)
268{
269	return adapter->id == I2C_HW_B_ZR36067;
270}
271
272static const struct i2c_device_id bt866_id[] = {
273	{ "bt866", 0 },
274	{ }
275};
276MODULE_DEVICE_TABLE(i2c, bt866_id);
277
278static struct v4l2_i2c_driver_data v4l2_i2c_data = {
279	.name = "bt866",
280	.driverid = I2C_DRIVERID_BT866,
281	.command = bt866_command,
282	.probe = bt866_probe,
283	.remove = bt866_remove,
284	.legacy_probe = bt866_legacy_probe,
285	.id_table = bt866_id,
286};
287