blob: b8109a1b50ce140989408fe0f33d0d550679bde0 [file] [log] [blame]
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * bt819 - BT819A VideoStream Decoder (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>
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03009 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
11 * - moved over to linux>=2.4.x i2c protocol (9/9/2002)
12 *
13 * This code was modify/ported from the saa7111 driver written
14 * by Dave Perks.
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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <linux/delay.h>
Mauro Carvalho Chehab18f3fa12007-07-02 15:39:57 -030033#include <linux/types.h>
Hans Verkuil7fd011f2008-10-13 07:30:15 -030034#include <linux/ioctl.h>
Mauro Carvalho Chehab18f3fa12007-07-02 15:39:57 -030035#include <asm/uaccess.h>
Hans Verkuil7fd011f2008-10-13 07:30:15 -030036#include <linux/i2c.h>
37#include <linux/i2c-id.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <linux/videodev.h>
Mauro Carvalho Chehab18f3fa12007-07-02 15:39:57 -030039#include <linux/video_decoder.h>
Hans Verkuil7fd011f2008-10-13 07:30:15 -030040#include <media/v4l2-common.h>
41#include <media/v4l2-i2c-drv-legacy.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
43MODULE_DESCRIPTION("Brooktree-819 video decoder driver");
44MODULE_AUTHOR("Mike Bernson & Dave Perks");
45MODULE_LICENSE("GPL");
46
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030047static int debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -070048module_param(debug, int, 0);
49MODULE_PARM_DESC(debug, "Debug level (0-1)");
50
Linus Torvalds1da177e2005-04-16 15:20:36 -070051/* ----------------------------------------------------------------------- */
52
53struct bt819 {
54 unsigned char reg[32];
55
56 int initialized;
Hans Verkuil107063c2009-02-18 17:26:06 -030057 v4l2_std_id norm;
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 int input;
59 int enable;
60 int bright;
61 int contrast;
62 int hue;
63 int sat;
64};
65
66struct timing {
67 int hactive;
68 int hdelay;
69 int vactive;
70 int vdelay;
71 int hscale;
72 int vscale;
73};
74
75/* for values, see the bt819 datasheet */
76static struct timing timing_data[] = {
77 {864 - 24, 20, 625 - 2, 1, 0x0504, 0x0000},
78 {858 - 24, 20, 525 - 2, 1, 0x00f8, 0x0000},
79};
80
Linus Torvalds1da177e2005-04-16 15:20:36 -070081/* ----------------------------------------------------------------------- */
82
Hans Verkuil7fd011f2008-10-13 07:30:15 -030083static inline int bt819_write(struct i2c_client *client, u8 reg, u8 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -070084{
85 struct bt819 *decoder = i2c_get_clientdata(client);
86
87 decoder->reg[reg] = value;
88 return i2c_smbus_write_byte_data(client, reg, value);
89}
90
Hans Verkuil7fd011f2008-10-13 07:30:15 -030091static inline int bt819_setbit(struct i2c_client *client, u8 reg, u8 bit, u8 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -070092{
93 struct bt819 *decoder = i2c_get_clientdata(client);
94
95 return bt819_write(client, reg,
Hans Verkuil7fd011f2008-10-13 07:30:15 -030096 (decoder->reg[reg] & ~(1 << bit)) | (value ? (1 << bit) : 0));
Linus Torvalds1da177e2005-04-16 15:20:36 -070097}
98
Hans Verkuil7fd011f2008-10-13 07:30:15 -030099static int bt819_write_block(struct i2c_client *client, const u8 *data, unsigned int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100{
101 int ret = -1;
102 u8 reg;
103
104 /* the bt819 has an autoincrement function, use it if
105 * the adapter understands raw I2C */
106 if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
107 /* do raw I2C, not smbus compatible */
108 struct bt819 *decoder = i2c_get_clientdata(client);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 u8 block_data[32];
Jean Delvare9aa45e32006-03-22 03:48:35 -0300110 int block_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 while (len >= 2) {
Jean Delvare9aa45e32006-03-22 03:48:35 -0300113 block_len = 0;
114 block_data[block_len++] = reg = data[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 do {
Jean Delvare9aa45e32006-03-22 03:48:35 -0300116 block_data[block_len++] =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 decoder->reg[reg++] = data[1];
118 len -= 2;
119 data += 2;
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300120 } while (len >= 2 && data[0] == reg && block_len < 32);
121 ret = i2c_master_send(client, block_data, block_len);
122 if (ret < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 break;
124 }
125 } else {
126 /* do some slow I2C emulation kind of thing */
127 while (len >= 2) {
128 reg = *data++;
129 if ((ret = bt819_write(client, reg, *data++)) < 0)
130 break;
131 len -= 2;
132 }
133 }
134
135 return ret;
136}
137
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300138static inline int bt819_read(struct i2c_client *client, u8 reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139{
140 return i2c_smbus_read_byte_data(client, reg);
141}
142
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300143static int bt819_init(struct i2c_client *client)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144{
145 struct bt819 *decoder = i2c_get_clientdata(client);
146
147 static unsigned char init[] = {
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300148 /*0x1f, 0x00,*/ /* Reset */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 0x01, 0x59, /* 0x01 input format */
150 0x02, 0x00, /* 0x02 temporal decimation */
151 0x03, 0x12, /* 0x03 Cropping msb */
152 0x04, 0x16, /* 0x04 Vertical Delay, lsb */
153 0x05, 0xe0, /* 0x05 Vertical Active lsb */
154 0x06, 0x80, /* 0x06 Horizontal Delay lsb */
155 0x07, 0xd0, /* 0x07 Horizontal Active lsb */
156 0x08, 0x00, /* 0x08 Horizontal Scaling msb */
157 0x09, 0xf8, /* 0x09 Horizontal Scaling lsb */
158 0x0a, 0x00, /* 0x0a Brightness control */
159 0x0b, 0x30, /* 0x0b Miscellaneous control */
160 0x0c, 0xd8, /* 0x0c Luma Gain lsb */
161 0x0d, 0xfe, /* 0x0d Chroma Gain (U) lsb */
162 0x0e, 0xb4, /* 0x0e Chroma Gain (V) msb */
163 0x0f, 0x00, /* 0x0f Hue control */
164 0x12, 0x04, /* 0x12 Output Format */
165 0x13, 0x20, /* 0x13 Vertial Scaling msb 0x00
166 chroma comb OFF, line drop scaling, interlace scaling
167 BUG? Why does turning the chroma comb on fuck up color?
168 Bug in the bt819 stepping on my board?
169 */
170 0x14, 0x00, /* 0x14 Vertial Scaling lsb */
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300171 0x16, 0x07, /* 0x16 Video Timing Polarity
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 ACTIVE=active low
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300173 FIELD: high=odd,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 vreset=active high,
175 hreset=active high */
176 0x18, 0x68, /* 0x18 AGC Delay */
177 0x19, 0x5d, /* 0x19 Burst Gate Delay */
178 0x1a, 0x80, /* 0x1a ADC Interface */
179 };
180
Hans Verkuil107063c2009-02-18 17:26:06 -0300181 struct timing *timing = &timing_data[(decoder->norm & V4L2_STD_525_60) ? 1 : 0];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
183 init[0x03 * 2 - 1] =
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300184 (((timing->vdelay >> 8) & 0x03) << 6) |
185 (((timing->vactive >> 8) & 0x03) << 4) |
186 (((timing->hdelay >> 8) & 0x03) << 2) |
187 ((timing->hactive >> 8) & 0x03);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 init[0x04 * 2 - 1] = timing->vdelay & 0xff;
189 init[0x05 * 2 - 1] = timing->vactive & 0xff;
190 init[0x06 * 2 - 1] = timing->hdelay & 0xff;
191 init[0x07 * 2 - 1] = timing->hactive & 0xff;
192 init[0x08 * 2 - 1] = timing->hscale >> 8;
193 init[0x09 * 2 - 1] = timing->hscale & 0xff;
194 /* 0x15 in array is address 0x19 */
Hans Verkuil107063c2009-02-18 17:26:06 -0300195 init[0x15 * 2 - 1] = (decoder->norm & V4L2_STD_625_50) ? 115 : 93; /* Chroma burst delay */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 /* reset */
197 bt819_write(client, 0x1f, 0x00);
198 mdelay(1);
199
200 /* init */
201 return bt819_write_block(client, init, sizeof(init));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202}
203
204/* ----------------------------------------------------------------------- */
205
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300206static int bt819_command(struct i2c_client *client, unsigned cmd, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207{
208 int temp;
209
210 struct bt819 *decoder = i2c_get_clientdata(client);
211
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300212 if (!decoder->initialized) { /* First call to bt819_init could be */
213 bt819_init(client); /* without #FRST = 0 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 decoder->initialized = 1;
215 }
216
217 switch (cmd) {
Hans Verkuil107063c2009-02-18 17:26:06 -0300218 case VIDIOC_INT_INIT:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 /* This is just for testing!!! */
220 bt819_init(client);
221 break;
222
Hans Verkuil107063c2009-02-18 17:26:06 -0300223 case VIDIOC_QUERYSTD:
224 case VIDIOC_INT_G_INPUT_STATUS: {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 int *iarg = arg;
Hans Verkuil107063c2009-02-18 17:26:06 -0300226 v4l2_std_id *istd = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 int status;
Hans Verkuil107063c2009-02-18 17:26:06 -0300228 int res = V4L2_IN_ST_NO_SIGNAL;
229 v4l2_std_id std;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230
231 status = bt819_read(client, 0x00);
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300232 if ((status & 0x80))
Hans Verkuil107063c2009-02-18 17:26:06 -0300233 res = 0;
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300234
Hans Verkuil107063c2009-02-18 17:26:06 -0300235 if ((status & 0x10))
236 std = V4L2_STD_PAL;
237 else
238 std = V4L2_STD_NTSC;
239 if (cmd == VIDIOC_QUERYSTD)
240 *istd = std;
241 else
242 *iarg = res;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300244 v4l_dbg(1, debug, client, "get status %x\n", *iarg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 break;
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300246 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
Hans Verkuil107063c2009-02-18 17:26:06 -0300248 case VIDIOC_S_STD:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 {
Hans Verkuil107063c2009-02-18 17:26:06 -0300250 v4l2_std_id *iarg = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 struct timing *timing = NULL;
252
Hans Verkuil107063c2009-02-18 17:26:06 -0300253 v4l_dbg(1, debug, client, "set norm %llx\n", *iarg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
Hans Verkuil107063c2009-02-18 17:26:06 -0300255 if (*iarg & V4L2_STD_NTSC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 bt819_setbit(client, 0x01, 0, 1);
257 bt819_setbit(client, 0x01, 1, 0);
258 bt819_setbit(client, 0x01, 5, 0);
259 bt819_write(client, 0x18, 0x68);
260 bt819_write(client, 0x19, 0x5d);
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300261 /* bt819_setbit(client, 0x1a, 5, 1); */
Hans Verkuil107063c2009-02-18 17:26:06 -0300262 timing = &timing_data[1];
263 } else if (*iarg & V4L2_STD_PAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 bt819_setbit(client, 0x01, 0, 1);
265 bt819_setbit(client, 0x01, 1, 1);
266 bt819_setbit(client, 0x01, 5, 1);
267 bt819_write(client, 0x18, 0x7f);
268 bt819_write(client, 0x19, 0x72);
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300269 /* bt819_setbit(client, 0x1a, 5, 0); */
Hans Verkuil107063c2009-02-18 17:26:06 -0300270 timing = &timing_data[0];
271 } else {
272 v4l_dbg(1, debug, client, "unsupported norm %llx\n", *iarg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 return -EINVAL;
274 }
Hans Verkuil107063c2009-02-18 17:26:06 -0300275/* case VIDEO_MODE_AUTO:
276 bt819_setbit(client, 0x01, 0, 0);
277 bt819_setbit(client, 0x01, 1, 0);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
Hans Verkuil107063c2009-02-18 17:26:06 -0300279 bt819_write(client, 0x03,
280 (((timing->vdelay >> 8) & 0x03) << 6) |
281 (((timing->vactive >> 8) & 0x03) << 4) |
282 (((timing->hdelay >> 8) & 0x03) << 2) |
283 ((timing->hactive >> 8) & 0x03));
284 bt819_write(client, 0x04, timing->vdelay & 0xff);
285 bt819_write(client, 0x05, timing->vactive & 0xff);
286 bt819_write(client, 0x06, timing->hdelay & 0xff);
287 bt819_write(client, 0x07, timing->hactive & 0xff);
288 bt819_write(client, 0x08, (timing->hscale >> 8) & 0xff);
289 bt819_write(client, 0x09, timing->hscale & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 decoder->norm = *iarg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 break;
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300292 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
Hans Verkuil107063c2009-02-18 17:26:06 -0300294 case VIDIOC_INT_S_VIDEO_ROUTING:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 {
Hans Verkuil107063c2009-02-18 17:26:06 -0300296 struct v4l2_routing *route = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
Hans Verkuil107063c2009-02-18 17:26:06 -0300298 v4l_dbg(1, debug, client, "set input %x\n", route->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299
Hans Verkuil107063c2009-02-18 17:26:06 -0300300 if (route->input < 0 || route->input > 7)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
Hans Verkuil107063c2009-02-18 17:26:06 -0300303 if (decoder->input != route->input) {
304 decoder->input = route->input;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 /* select mode */
306 if (decoder->input == 0) {
307 bt819_setbit(client, 0x0b, 6, 0);
308 bt819_setbit(client, 0x1a, 1, 1);
309 } else {
310 bt819_setbit(client, 0x0b, 6, 1);
311 bt819_setbit(client, 0x1a, 1, 0);
312 }
313 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 break;
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300315 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
Hans Verkuil107063c2009-02-18 17:26:06 -0300317 case VIDIOC_STREAMON:
318 case VIDIOC_STREAMOFF:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 {
Hans Verkuil107063c2009-02-18 17:26:06 -0300320 int enable = cmd == VIDIOC_STREAMON;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321
Hans Verkuil107063c2009-02-18 17:26:06 -0300322 v4l_dbg(1, debug, client, "enable output %x\n", enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
324 if (decoder->enable != enable) {
325 decoder->enable = enable;
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300326 bt819_setbit(client, 0x16, 7, !enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 break;
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300329 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
Hans Verkuil107063c2009-02-18 17:26:06 -0300331 case VIDIOC_QUERYCTRL:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 {
Hans Verkuil107063c2009-02-18 17:26:06 -0300333 struct v4l2_queryctrl *qc = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334
Hans Verkuil107063c2009-02-18 17:26:06 -0300335 switch (qc->id) {
336 case V4L2_CID_BRIGHTNESS:
337 v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
338 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339
Hans Verkuil107063c2009-02-18 17:26:06 -0300340 case V4L2_CID_CONTRAST:
341 v4l2_ctrl_query_fill(qc, 0, 511, 1, 256);
342 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
Hans Verkuil107063c2009-02-18 17:26:06 -0300344 case V4L2_CID_SATURATION:
345 v4l2_ctrl_query_fill(qc, 0, 511, 1, 256);
346 break;
347
348 case V4L2_CID_HUE:
349 v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
350 break;
351
352 default:
353 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 }
Hans Verkuil107063c2009-02-18 17:26:06 -0300355 break;
356 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357
Hans Verkuil107063c2009-02-18 17:26:06 -0300358 case VIDIOC_S_CTRL:
359 {
360 struct v4l2_control *ctrl = arg;
361
362 switch (ctrl->id) {
363 case V4L2_CID_BRIGHTNESS:
364 if (decoder->bright != ctrl->value) {
365 decoder->bright = ctrl->value;
366 bt819_write(client, 0x0a, decoder->bright);
367 }
368 break;
369
370 case V4L2_CID_CONTRAST:
371 if (decoder->contrast != ctrl->value) {
372 decoder->contrast = ctrl->value;
373 bt819_write(client, 0x0c,
374 decoder->contrast & 0xff);
375 bt819_setbit(client, 0x0b, 2,
376 ((decoder->contrast >> 8) & 0x01));
377 }
378 break;
379
380 case V4L2_CID_SATURATION:
381 if (decoder->sat != ctrl->value) {
382 decoder->sat = ctrl->value;
383 bt819_write(client, 0x0d,
384 (decoder->sat >> 7) & 0xff);
385 bt819_setbit(client, 0x0b, 1,
386 ((decoder->sat >> 15) & 0x01));
387
388 /* Ratio between U gain and V gain must stay the same as
389 the ratio between the default U and V gain values. */
390 temp = (decoder->sat * 180) / 254;
391 bt819_write(client, 0x0e, (temp >> 7) & 0xff);
392 bt819_setbit(client, 0x0b, 0, (temp >> 15) & 0x01);
393 }
394 break;
395
396 case V4L2_CID_HUE:
397 if (decoder->hue != ctrl->value) {
398 decoder->hue = ctrl->value;
399 bt819_write(client, 0x0f, decoder->hue);
400 }
401 break;
402 default:
403 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 }
Hans Verkuil107063c2009-02-18 17:26:06 -0300405 break;
406 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407
Hans Verkuil107063c2009-02-18 17:26:06 -0300408 case VIDIOC_G_CTRL:
409 {
410 struct v4l2_control *ctrl = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411
Hans Verkuil107063c2009-02-18 17:26:06 -0300412 switch (ctrl->id) {
413 case V4L2_CID_BRIGHTNESS:
414 ctrl->value = decoder->bright;
415 break;
416 case V4L2_CID_CONTRAST:
417 ctrl->value = decoder->contrast;
418 break;
419 case V4L2_CID_SATURATION:
420 ctrl->value = decoder->sat;
421 break;
422 case V4L2_CID_HUE:
423 ctrl->value = decoder->hue;
424 break;
425 default:
426 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 break;
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300429 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430
431 default:
432 return -EINVAL;
433 }
434
435 return 0;
436}
437
438/* ----------------------------------------------------------------------- */
439
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300440static unsigned short normal_i2c[] = { 0x8a >> 1, I2C_CLIENT_END };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300442I2C_CLIENT_INSMOD;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300443
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300444static int bt819_probe(struct i2c_client *client,
445 const struct i2c_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446{
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300447 int i, ver;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 struct bt819 *decoder;
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300449 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
451 /* Check if the adapter supports the needed features */
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300452 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
453 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300455 ver = bt819_read(client, 0x17);
456 switch (ver & 0xf0) {
457 case 0x70:
458 name = "bt819a";
459 break;
460 case 0x60:
461 name = "bt817a";
462 break;
463 case 0x20:
464 name = "bt815a";
465 break;
466 default:
467 v4l_dbg(1, debug, client,
468 "unknown chip version 0x%02x\n", ver);
469 return -ENODEV;
470 }
471
472 v4l_info(client, "%s found @ 0x%x (%s)\n", name,
473 client->addr << 1, client->adapter->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474
Panagiotis Issaris74081872006-01-11 19:40:56 -0200475 decoder = kzalloc(sizeof(struct bt819), GFP_KERNEL);
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300476 if (decoder == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 return -ENOMEM;
Hans Verkuil107063c2009-02-18 17:26:06 -0300478 decoder->norm = V4L2_STD_NTSC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 decoder->input = 0;
480 decoder->enable = 1;
Hans Verkuil107063c2009-02-18 17:26:06 -0300481 decoder->bright = 0;
482 decoder->contrast = 0xd8; /* 100% of original signal */
483 decoder->hue = 0;
484 decoder->sat = 0xfe; /* 100% of original signal */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 decoder->initialized = 0;
486 i2c_set_clientdata(client, decoder);
487
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 i = bt819_init(client);
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300489 if (i < 0)
490 v4l_dbg(1, debug, client, "init status %d\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 return 0;
492}
493
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300494static int bt819_remove(struct i2c_client *client)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495{
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300496 kfree(i2c_get_clientdata(client));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 return 0;
498}
499
500/* ----------------------------------------------------------------------- */
501
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300502static const struct i2c_device_id bt819_id[] = {
503 { "bt819a", 0 },
504 { "bt817a", 0 },
505 { "bt815a", 0 },
506 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507};
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300508MODULE_DEVICE_TABLE(i2c, bt819_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
Hans Verkuil7fd011f2008-10-13 07:30:15 -0300510static struct v4l2_i2c_driver_data v4l2_i2c_data = {
511 .name = "bt819",
512 .driverid = I2C_DRIVERID_BT819,
513 .command = bt819_command,
514 .probe = bt819_probe,
515 .remove = bt819_remove,
516 .id_table = bt819_id,
517};