blob: 596f9e2376beccf140690bf92228ef973b32880f [file] [log] [blame]
Martin Samuelssonfbe60da2006-04-27 10:17:00 -03001/*
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>
Martin Samuelssonfbe60da2006-04-27 10:17:00 -030032#include <linux/types.h>
Hans Verkuilc18fdcf2008-09-07 07:59:54 -030033#include <linux/ioctl.h>
Martin Samuelssonfbe60da2006-04-27 10:17:00 -030034#include <asm/uaccess.h>
Hans Verkuilc18fdcf2008-09-07 07:59:54 -030035#include <linux/i2c.h>
36#include <linux/i2c-id.h>
37#include <linux/videodev.h>
Martin Samuelssonfbe60da2006-04-27 10:17:00 -030038#include <linux/video_encoder.h>
Hans Verkuilc18fdcf2008-09-07 07:59:54 -030039#include <media/v4l2-common.h>
40#include <media/v4l2-i2c-drv-legacy.h>
Martin Samuelssonfbe60da2006-04-27 10:17:00 -030041
Hans Verkuilc18fdcf2008-09-07 07:59:54 -030042MODULE_DESCRIPTION("Brooktree-866 video encoder driver");
43MODULE_AUTHOR("Mike Bernson & Dave Perks");
Martin Samuelssonfbe60da2006-04-27 10:17:00 -030044MODULE_LICENSE("GPL");
45
Hans Verkuilc18fdcf2008-09-07 07:59:54 -030046static int debug;
47module_param(debug, int, 0);
48MODULE_PARM_DESC(debug, "Debug level (0-1)");
Martin Samuelssonfbe60da2006-04-27 10:17:00 -030049
50/* ----------------------------------------------------------------------- */
51
52struct bt866 {
Hans Verkuilc18fdcf2008-09-07 07:59:54 -030053 u8 reg[256];
Martin Samuelssonfbe60da2006-04-27 10:17:00 -030054
55 int norm;
56 int enable;
57 int bright;
58 int contrast;
59 int hue;
60 int sat;
61};
62
Hans Verkuilc18fdcf2008-09-07 07:59:54 -030063static int bt866_write(struct i2c_client *client, u8 subaddr, u8 data)
Martin Samuelssonfbe60da2006-04-27 10:17:00 -030064{
Hans Verkuilc18fdcf2008-09-07 07:59:54 -030065 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
Martin Samuelssonfbe60da2006-04-27 10:17:00 -030096 switch (cmd) {
97 case ENCODER_GET_CAPABILITIES:
98 {
99 struct video_encoder_capability *cap = arg;
100
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300101 v4l_dbg(1, debug, client, "get capabilities\n");
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300102
103 cap->flags
104 = VIDEO_ENCODER_PAL
105 | VIDEO_ENCODER_NTSC
106 | VIDEO_ENCODER_CCIR;
107 cap->inputs = 2;
108 cap->outputs = 1;
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300109 break;
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300110 }
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300111
112 case ENCODER_SET_NORM:
113 {
114 int *iarg = arg;
115
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300116 v4l_dbg(1, debug, client, "set norm %d\n", *iarg);
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300117
118 switch (*iarg) {
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300119 case VIDEO_MODE_NTSC:
120 break;
121
122 case VIDEO_MODE_PAL:
123 break;
124
125 default:
126 return -EINVAL;
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300127 }
128 encoder->norm = *iarg;
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300129 break;
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300130 }
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300131
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)
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300166 bt866_write(client, init[i], init[i+1]);
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300167
168 val = encoder->reg[0xdc];
169
170 if (*iarg == 0)
171 val |= 0x40; /* CBSWAP */
172 else
173 val &= ~0x40; /* !CBSWAP */
174
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300175 bt866_write(client, 0xdc, val);
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300176
177 val = encoder->reg[0xcc];
178 if (*iarg == 2)
179 val |= 0x01; /* OSDBAR */
180 else
181 val &= ~0x01; /* !OSDBAR */
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300182 bt866_write(client, 0xcc, val);
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300183
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300184 v4l_dbg(1, debug, client, "set input %d\n", *iarg);
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300185
186 switch (*iarg) {
187 case 0:
188 break;
189 case 1:
190 break;
191 default:
192 return -EINVAL;
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300193 }
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300194 break;
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300195 }
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300196
197 case ENCODER_SET_OUTPUT:
198 {
199 int *iarg = arg;
200
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300201 v4l_dbg(1, debug, client, "set output %d\n", *iarg);
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300202
203 /* not much choice of outputs */
204 if (*iarg != 0)
205 return -EINVAL;
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300206 break;
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300207 }
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300208
209 case ENCODER_ENABLE_OUTPUT:
210 {
211 int *iarg = arg;
212 encoder->enable = !!*iarg;
213
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300214 v4l_dbg(1, debug, client, "enable output %d\n", encoder->enable);
215 break;
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300216 }
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300217
218 case 4711:
219 {
220 int *iarg = arg;
221 __u8 val;
222
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300223 v4l_dbg(1, debug, client, "square %d\n", *iarg);
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300224
225 val = encoder->reg[0xdc];
226 if (*iarg)
227 val |= 1; /* SQUARE */
228 else
229 val &= ~1; /* !SQUARE */
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300230 bt866_write(client, 0xdc, val);
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300231 break;
232 }
233
234 default:
235 return -EINVAL;
236 }
237
238 return 0;
239}
240
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300241static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300242
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300243I2C_CLIENT_INSMOD;
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300244
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300245static int bt866_probe(struct i2c_client *client,
246 const struct i2c_device_id *id)
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300247{
248 struct bt866 *encoder;
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300249
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300250 v4l_info(client, "chip found @ 0x%x (%s)\n",
251 client->addr << 1, client->adapter->name);
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300252
253 encoder = kzalloc(sizeof(*encoder), GFP_KERNEL);
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300254 if (encoder == NULL)
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300255 return -ENOMEM;
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300256
257 i2c_set_clientdata(client, encoder);
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300258 return 0;
259}
260
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300261static int bt866_remove(struct i2c_client *client)
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300262{
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300263 kfree(i2c_get_clientdata(client));
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300264 return 0;
265}
266
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300267static int bt866_legacy_probe(struct i2c_adapter *adapter)
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300268{
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300269 return adapter->id == I2C_HW_B_ZR36067;
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300270}
271
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300272static const struct i2c_device_id bt866_id[] = {
273 { "bt866", 0 },
274 { }
275};
276MODULE_DEVICE_TABLE(i2c, bt866_id);
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300277
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300278static 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};