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/slab.h>
34#include <linux/ioctl.h>
35#include <asm/uaccess.h>
36#include <linux/i2c.h>
37#include <linux/videodev2.h>
38#include <media/v4l2-device.h>
39
40MODULE_DESCRIPTION("Brooktree-866 video encoder driver");
41MODULE_AUTHOR("Mike Bernson & Dave Perks");
42MODULE_LICENSE("GPL");
43
44static int debug;
45module_param(debug, int, 0);
46MODULE_PARM_DESC(debug, "Debug level (0-1)");
47
48
49/* ----------------------------------------------------------------------- */
50
51struct bt866 {
52	struct v4l2_subdev sd;
53	u8 reg[256];
54};
55
56static inline struct bt866 *to_bt866(struct v4l2_subdev *sd)
57{
58	return container_of(sd, struct bt866, sd);
59}
60
61static int bt866_write(struct bt866 *encoder, u8 subaddr, u8 data)
62{
63	struct i2c_client *client = v4l2_get_subdevdata(&encoder->sd);
64	u8 buffer[2];
65	int err;
66
67	buffer[0] = subaddr;
68	buffer[1] = data;
69
70	encoder->reg[subaddr] = data;
71
72	v4l_dbg(1, debug, client, "write 0x%02x = 0x%02x\n", subaddr, data);
73
74	for (err = 0; err < 3;) {
75		if (i2c_master_send(client, buffer, 2) == 2)
76			break;
77		err++;
78		v4l_warn(client, "error #%d writing to 0x%02x\n",
79				err, subaddr);
80		schedule_timeout_interruptible(msecs_to_jiffies(100));
81	}
82	if (err == 3) {
83		v4l_warn(client, "giving up\n");
84		return -1;
85	}
86
87	return 0;
88}
89
90static int bt866_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
91{
92	v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
93
94	/* Only PAL supported by this driver at the moment! */
95	if (!(std & V4L2_STD_NTSC))
96		return -EINVAL;
97	return 0;
98}
99
100static int bt866_s_routing(struct v4l2_subdev *sd,
101			   u32 input, u32 output, u32 config)
102{
103	static const __u8 init[] = {
104		0xc8, 0xcc, /* CRSCALE */
105		0xca, 0x91, /* CBSCALE */
106		0xcc, 0x24, /* YC16 | OSDNUM */
107		0xda, 0x00, /*  */
108		0xdc, 0x24, /* SETMODE | PAL */
109		0xde, 0x02, /* EACTIVE */
110
111		/* overlay colors */
112		0x70, 0xEB, 0x90, 0x80, 0xB0, 0x80, /* white */
113		0x72, 0xA2, 0x92, 0x8E, 0xB2, 0x2C, /* yellow */
114		0x74, 0x83, 0x94, 0x2C, 0xB4, 0x9C, /* cyan */
115		0x76, 0x70, 0x96, 0x3A, 0xB6, 0x48, /* green */
116		0x78, 0x54, 0x98, 0xC6, 0xB8, 0xB8, /* magenta */
117		0x7A, 0x41, 0x9A, 0xD4, 0xBA, 0x64, /* red */
118		0x7C, 0x23, 0x9C, 0x72, 0xBC, 0xD4, /* blue */
119		0x7E, 0x10, 0x9E, 0x80, 0xBE, 0x80, /* black */
120
121		0x60, 0xEB, 0x80, 0x80, 0xc0, 0x80, /* white */
122		0x62, 0xA2, 0x82, 0x8E, 0xc2, 0x2C, /* yellow */
123		0x64, 0x83, 0x84, 0x2C, 0xc4, 0x9C, /* cyan */
124		0x66, 0x70, 0x86, 0x3A, 0xc6, 0x48, /* green */
125		0x68, 0x54, 0x88, 0xC6, 0xc8, 0xB8, /* magenta */
126		0x6A, 0x41, 0x8A, 0xD4, 0xcA, 0x64, /* red */
127		0x6C, 0x23, 0x8C, 0x72, 0xcC, 0xD4, /* blue */
128		0x6E, 0x10, 0x8E, 0x80, 0xcE, 0x80, /* black */
129	};
130	struct bt866 *encoder = to_bt866(sd);
131	u8 val;
132	int i;
133
134	for (i = 0; i < ARRAY_SIZE(init) / 2; i += 2)
135		bt866_write(encoder, init[i], init[i+1]);
136
137	val = encoder->reg[0xdc];
138
139	if (input == 0)
140		val |= 0x40; /* CBSWAP */
141	else
142		val &= ~0x40; /* !CBSWAP */
143
144	bt866_write(encoder, 0xdc, val);
145
146	val = encoder->reg[0xcc];
147	if (input == 2)
148		val |= 0x01; /* OSDBAR */
149	else
150		val &= ~0x01; /* !OSDBAR */
151	bt866_write(encoder, 0xcc, val);
152
153	v4l2_dbg(1, debug, sd, "set input %d\n", input);
154
155	switch (input) {
156	case 0:
157	case 1:
158	case 2:
159		break;
160	default:
161		return -EINVAL;
162	}
163	return 0;
164}
165
166#if 0
167/* Code to setup square pixels, might be of some use in the future,
168   but is currently unused. */
169	val = encoder->reg[0xdc];
170	if (*iarg)
171		val |= 1; /* SQUARE */
172	else
173		val &= ~1; /* !SQUARE */
174	bt866_write(client, 0xdc, val);
175#endif
176
177/* ----------------------------------------------------------------------- */
178
179static const struct v4l2_subdev_video_ops bt866_video_ops = {
180	.s_std_output = bt866_s_std_output,
181	.s_routing = bt866_s_routing,
182};
183
184static const struct v4l2_subdev_ops bt866_ops = {
185	.video = &bt866_video_ops,
186};
187
188static int bt866_probe(struct i2c_client *client,
189			const struct i2c_device_id *id)
190{
191	struct bt866 *encoder;
192	struct v4l2_subdev *sd;
193
194	v4l_info(client, "chip found @ 0x%x (%s)\n",
195			client->addr << 1, client->adapter->name);
196
197	encoder = devm_kzalloc(&client->dev, sizeof(*encoder), GFP_KERNEL);
198	if (encoder == NULL)
199		return -ENOMEM;
200	sd = &encoder->sd;
201	v4l2_i2c_subdev_init(sd, client, &bt866_ops);
202	return 0;
203}
204
205static int bt866_remove(struct i2c_client *client)
206{
207	struct v4l2_subdev *sd = i2c_get_clientdata(client);
208
209	v4l2_device_unregister_subdev(sd);
210	return 0;
211}
212
213static const struct i2c_device_id bt866_id[] = {
214	{ "bt866", 0 },
215	{ }
216};
217MODULE_DEVICE_TABLE(i2c, bt866_id);
218
219static struct i2c_driver bt866_driver = {
220	.driver = {
221		.owner	= THIS_MODULE,
222		.name	= "bt866",
223	},
224	.probe		= bt866_probe,
225	.remove		= bt866_remove,
226	.id_table	= bt866_id,
227};
228
229module_i2c_driver(bt866_driver);
230