Add autowhitebalance for SOI968
[microdia.git] / sn9c20x-bridge.c
blobac54af320601694890bc94f1525ddd9c55e6be13
1 /**
2 * @file sn9c20x-bridge.c
3 * @author Dave Neuer
4 * @date 2008-03-02
6 * @brief Common functions and data for the Sonix SN9C20x webcam bridge chips.
8 * @note Copyright (C) Dave Neuer
10 * @par Licences
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <linux/delay.h>
28 #include <linux/errno.h>
29 #include <linux/string.h>
30 #include "sn9c20x.h"
31 #include "sn9c20x-bridge.h"
33 int sn9c20x_set_camera_control(struct usb_sn9c20x *dev,
34 __u32 control, __u32 value)
36 int ret = -EINVAL;
37 switch (control) {
38 case V4L2_CID_CONTRAST:
39 if (dev->camera.set_contrast) {
40 dev->vsettings.contrast = value;
41 ret = dev->camera.set_contrast(dev);
43 break;
44 case V4L2_CID_BRIGHTNESS:
45 if (dev->camera.set_brightness) {
46 dev->vsettings.brightness = value;
47 ret = dev->camera.set_brightness(dev);
49 break;
50 case V4L2_CID_GAMMA:
51 if (dev->camera.set_gamma) {
52 dev->vsettings.gamma = value;
53 ret = dev->camera.set_gamma(dev);
55 break;
56 case V4L2_CID_SATURATION:
57 if (dev->camera.set_saturation) {
58 dev->vsettings.colour = value;
59 ret = dev->camera.set_saturation(dev);
61 break;
62 case V4L2_CID_SHARPNESS:
63 if (dev->camera.set_sharpness) {
64 dev->vsettings.sharpness = value;
65 ret = dev->camera.set_sharpness(dev);
67 break;
68 case V4L2_CID_RED_BALANCE:
69 if (dev->camera.set_red_gain) {
70 dev->vsettings.red_gain = value & 0x7f;
71 ret = dev->camera.set_red_gain(dev);
73 break;
74 case V4L2_CID_BLUE_BALANCE:
75 if (dev->camera.set_blue_gain) {
76 dev->vsettings.blue_gain = value & 0x7f;
77 ret = dev->camera.set_blue_gain(dev);
79 break;
80 case V4L2_CID_HFLIP:
81 if (dev->camera.set_hvflip) {
82 dev->vsettings.hflip = value;
83 ret = dev->camera.set_hvflip(dev);
85 break;
86 case V4L2_CID_VFLIP:
87 if (dev->camera.set_hvflip) {
88 dev->vsettings.vflip = value;
89 ret = dev->camera.set_hvflip(dev);
91 break;
92 case V4L2_CID_AUTOGAIN:
93 if (dev->camera.set_auto_gain) {
94 dev->vsettings.auto_gain = value;
95 ret = dev->camera.set_auto_gain(dev);
97 break;
98 case V4L2_CID_EXPOSURE:
99 if (dev->camera.set_exposure) {
100 dev->vsettings.exposure = value;
101 ret = dev->camera.set_exposure(dev);
103 break;
104 case V4L2_CID_GAIN:
105 if (dev->camera.set_gain) {
106 dev->vsettings.gain = value;
107 ret = dev->camera.set_gain(dev);
109 break;
110 case V4L2_CID_AUTO_WHITE_BALANCE:
111 if (dev->camera.set_auto_whitebalance) {
112 dev->vsettings.auto_whitebalance = value;
113 ret = dev->camera.set_auto_whitebalance(dev);
115 break;
116 case V4L2_CID_EXPOSURE_AUTO:
117 dev->vsettings.auto_exposure = value;
118 ret = 0;
119 if (dev->camera.set_auto_exposure)
120 ret = dev->camera.set_auto_exposure(dev);
121 break;
123 return ret;
127 * @brief Switch Video stream on and off
129 * @param dev Pointer to device structure
130 * @param enable On or off
132 * @author Brian Johnson
134 * @return 0 or negative error code
137 int sn9c20x_enable_video(struct usb_sn9c20x *dev, int enable)
139 __u8 value;
140 int ret;
142 ret = usb_sn9c20x_control_read(dev, 0x1061, &value, 1);
143 if (ret < 0)
144 return ret;
146 if (enable) {
147 value |= 0x02;
148 ret = usb_sn9c20x_control_write(dev, 0x1061, &value, 1);
149 } else {
150 value &= ~0x02;
151 ret = usb_sn9c20x_control_write(dev, 0x1061, &value, 1);
154 sn9c20x_set_LEDs(dev, enable);
156 return ret;
160 * @brief Switch LEDs on and off
162 * @param dev Pointer to device structure
163 * @param enable On or off
165 * @author Josua Grawitter
167 * @return 0 or negative error code
170 int sn9c20x_set_LEDs(struct usb_sn9c20x *dev, int enable)
172 int ret;
173 __u8 led[2];
175 int sensor = dev->camera.sensor;
177 if (enable) {
178 switch (sensor) {
179 case MT9M001_SENSOR:
180 case HV7131R_SENSOR:
181 case SOI968_SENSOR:
182 led[0] = 0x80;
183 led[1] = 0xa0;
184 break;
185 case MT9V011_SENSOR:
186 case OV7660_SENSOR:
187 led[0] = 0x40;
188 led[1] = 0x60;
189 break;
190 case MT9M111_SENSOR:
191 led[0] = 0x00;
192 led[1] = 0x60;
193 break;
194 case MT9V111_SENSOR:
195 led[0] = 0xc0;
196 led[1] = 0xe0;
197 break;
198 default:
199 led[0] = 0x00;
200 led[1] = 0x20;
202 } else {
203 switch (sensor) {
204 case HV7131R_SENSOR:
205 case MT9M001_SENSOR:
206 case MT9V011_SENSOR:
207 led[0] = 0xa0;
208 led[1] = 0xa0;
209 break;
210 case MT9M111_SENSOR:
211 case OV7660_SENSOR:
212 led[0] = 0x20;
213 led[1] = 0x60;
214 break;
215 case MT9V111_SENSOR:
216 led[0] = 0x80;
217 led[1] = 0xe0;
218 break;
219 default:
220 led[0] = 0x20;
221 led[1] = 0x20;
225 ret = usb_sn9c20x_control_write(dev, 0x1006, led, 2);
227 return ret;
231 * @brief Initializes Micro-Controller's I2C interface
233 * @author Neekhil
235 * @param dev Pointer to the device
237 * @return Zero (success) or negative (USB-error value)
240 int sn9c20x_i2c_initialize(struct usb_sn9c20x *dev)
242 __u8 buf[9];
243 int ret;
245 dev->camera.i2c_flags = SN9C20X_I2C_2WIRE;
247 buf[0] = dev->camera.i2c_flags;
248 buf[1] = dev->camera.address;
249 buf[2] = 0x00;
250 buf[3] = 0x00;
251 buf[4] = 0x00;
252 buf[5] = 0x00;
253 buf[6] = 0x00;
254 buf[7] = 0x00;
255 buf[8] = 0x03;
256 /* Initialize I2C registers to avoid getting no ACK at first I2C operation: */
257 /* Get green diagonal bands w/o this dummy write, Bridge does not know sensor address ? */
258 ret = usb_sn9c20x_control_write(dev, 0x10c0, buf, 9);
259 if (ret < 0)
260 return ret;
261 else
262 return 0;
266 * @brief Wait until the I2C slave is ready for the next operation
268 * @param dev Pointer to the device
269 * @param highspeed
270 * @param slave_error
272 * @return Zero for success or a negative error value
275 int sn9c20x_i2c_ack_wait(struct usb_sn9c20x *dev, bool highspeed, bool *slave_error)
277 int ret, i;
278 __u8 readbuf;
279 int delay = highspeed ? 100 : 400;
281 for (i = 0; i < 5; i++) {
282 ret = usb_sn9c20x_control_read(dev, 0x10c0, &readbuf, 1);
284 if (ret < 0)
285 return ret;
286 else if (readbuf & SN9C20X_I2C_ERROR) {
287 *slave_error = 1;
288 /* probably should come up w/ an error value and
289 * return it via the error return */
290 return 0;
291 } else if (readbuf & SN9C20X_I2C_READY)
292 return 0;
293 else
294 udelay(delay);
296 return -EBUSY;
300 * @brief Read up to 5 bytes of data from an I2C slave
302 * @param dev Pointer to the device
303 * @param nbytes Number of bytes to read
304 * @param address The address of the register on the slave to read
305 * @param result A pointer to the location at which the result should be stored
307 * @return Zero for success or a negative error value
310 int sn9c20x_read_i2c_data(struct usb_sn9c20x *dev, __u8 nbytes,
311 __u8 address, __u8 *result)
313 int ret, i, j;
314 __u8 row[5];
316 if (!dev || nbytes > 4)
317 return -EINVAL;
319 /* first, we must do a dummy write of just the address */
320 ret = sn9c20x_write_i2c_data(dev, 0, address, NULL);
321 if (ret < 0)
322 return ret;
324 memset(row, 0, 5);
325 /* now we issue the same command but with the read bit set
326 * and no slave register address */
327 dev->camera.i2c_flags |= SN9C20X_I2C_READ;
328 ret = sn9c20x_write_i2c_data(dev, nbytes - 1, 0, row);
329 dev->camera.i2c_flags &= ~SN9C20X_I2C_READ;
330 if (ret < 0)
331 return ret;
333 /* finally, ask the bridge for the data */
334 ret = usb_sn9c20x_control_read(dev, 0x10c2, row, 5);
335 if (ret < 0)
336 return ret;
338 UDIA_DEBUG("I2C read: %02x %02x %02x %02x %02x %02x\n",
339 address, row[0], row[1], row[2], row[3], row[4]);
341 for (i = 0, j = 5 - nbytes; i < nbytes; i++, j++)
342 result[i] = row[j];
344 return 0;
348 * @brief Read up to 4 bytes of data from an I2C slave an return them as 16bit values
350 * @param dev Pointer to the device
351 * @param datalen Number of 16bit values to read
352 * @param address The address of the register on the slave to read
353 * @param result A pointer to the location at which the result should be stored
355 * @return Zero for success or a negative error value
358 int sn9c20x_read_i2c_data16(struct usb_sn9c20x *dev, __u8 datalen,
359 __u8 address, __u16 *result)
361 __u8 result8[4];
362 __u8 k;
363 int ret;
365 if (datalen > 2)
366 return -EINVAL;
367 ret = sn9c20x_read_i2c_data(dev, 2*datalen, address, result8);
368 for (k = 0; k < datalen; k++)
369 result[k] = (result8[k*2] << 8) | result8[k*2+1];
370 return ret;
373 static const char *wasread = "read from";
374 static const char *waswrite = "write to";
377 * @brief Write up to 5 bytes of data to an I2C slave
379 * @param dev Pointer to the device
380 * @param nbytes The number of bytes of data
381 * @param address The address of the register on the slave to write
382 * @param data An array containing the data to write
383 * @param last_byte The byte to be sent as last byte of control sequence
385 * @return Zero for success or a negative error value
388 int sn9c20x_write_i2c_data_ext(struct usb_sn9c20x *dev, __u8 nbytes,
389 __u8 address, const __u8 data[nbytes], __u8 last_byte)
391 int ret, i;
392 __u8 row[8];
393 bool slave_error = 0;
395 if (!dev || (nbytes > 0 && !data) || nbytes > 4)
396 return -EINVAL;
398 /* from the point of view of the bridge, the length
399 * includes the address */
400 row[0] = dev->camera.i2c_flags | ((nbytes + 1) << 4);
401 row[1] = dev->camera.address;
402 row[2] = address;
403 row[7] = last_byte;
405 for (i = 0; i < 4; i++)
406 row[i + 3] = i < nbytes ? data[i] : 0;
408 UDIA_DEBUG("I2C %s %02x: %02x %02x %02x %02x %02x %02x %02x %02x\n",
409 (dev->camera.i2c_flags & SN9C20X_I2C_READ ? wasread : waswrite),
410 address, row[0], row[1], row[2], row[3], row[4], row[5], row[6],
411 row[7]);
413 ret = usb_sn9c20x_control_write(dev, 0x10c0, row, 8);
414 if (ret >= 0)
415 ret = sn9c20x_i2c_ack_wait(dev,
416 dev->camera.i2c_flags & SN9C20X_I2C_400KHZ,
417 &slave_error);
419 if (slave_error) {
420 UDIA_ERROR("I2C slave 0x%02x returned error during %s address 0x%02x\n",
421 dev->camera.address, (dev->camera.i2c_flags &
422 SN9C20X_I2C_READ ? wasread : waswrite), address);
423 return -1000;
424 /* there should be no interference with USB errors */
427 if (ret < 0) {
428 /* we got no ack */
429 UDIA_ERROR("No ack from I2C slave 0x%02x for %s address 0x%02x\n",
430 dev->camera.address, (dev->camera.i2c_flags &
431 SN9C20X_I2C_READ ? wasread : waswrite), address);
432 return ret;
435 return 0;
439 * @brief Write up to 2 16bit values als single bytes to an I2C slave
441 * @param dev Pointer to the device
442 * @param datalen The number of 16bit data values to write
443 * @param address The address of the register on the slave to write
444 * @param data An array containing the data to write
446 * @return Zero for success or a negative error value
449 int sn9c20x_write_i2c_data16(struct usb_sn9c20x *dev, __u8 datalen,
450 __u8 address, const __u16 data[datalen])
452 __u8 data8[4];
453 __u8 k;
454 int ret;
456 if (datalen > 2)
457 return -EINVAL;
458 for (k = 0; k < datalen; k++) {
459 data8[k*2] = data[k] >> 8;
460 data8[k*2+1] = data[k] & 0xff;
462 ret = sn9c20x_write_i2c_data(dev, 2*datalen, address, data8);
463 return ret;
466 int sn9c20x_write_i2c_array(struct usb_sn9c20x *dev,
467 struct sn9c20x_i2c_regs *regs, int bits16)
469 int i;
470 int ret = 0;
471 __u16 value16;
472 __u8 value8;
473 for (i = 0;; i++) {
474 if (regs[i].address == 0xff)
475 break;
476 if (bits16) {
477 value16 = regs[i].value;
478 ret = sn9c20x_write_i2c_data16(dev, 1,
479 regs[i].address, &value16);
480 } else {
481 value8 = (__u8)regs[i].value;
482 ret = sn9c20x_write_i2c_data(dev, 1,
483 regs[i].address, &value8);
485 if (ret < 0)
486 return ret;
488 return ret;
492 * @brief Set contrast inside sn9c20x chip
494 * @author Comer352l
496 * @param dev Pointer to the device
498 * @return Zero (success) or negative (USB-error value)
501 int sn9c20x_set_contrast(struct usb_sn9c20x *dev)
503 /* from 0x26 to 0x4b */
504 __u8 brightness_contrast[21] = {0x16, 0x0, 0x2b, 0x0, 0x8, 0x0, 0xf6, 0x0f,
505 0xd2, 0x0f, 0x38, 0x0, 0x34, 0x0, 0xcf, 0x0f,
506 0xfd, 0x0f, 0x0, 0x0, 0x0};
507 __u8 contrast_val = (dev->vsettings.contrast) * 0x25 / 0x100;
508 __u8 brightness_val = dev->vsettings.brightness;
510 brightness_val -= 0x80;
511 brightness_contrast[18] = brightness_val;
513 contrast_val += 0x26;
514 brightness_contrast[2] = contrast_val;
515 brightness_contrast[0] = 0x13 + (brightness_contrast[2] - 0x26) * 0x13 / 0x25;
516 brightness_contrast[4] = 0x7 + (brightness_contrast[2] - 0x26) * 0x7 / 0x25;
518 return usb_sn9c20x_control_write(dev, 0x10e1, brightness_contrast, 21);
522 * @brief Set brightness inside sn9c20x chip
524 * @author Comer352l
526 * @param dev Pointer to the device
528 * @return Zero (success) or negative (USB-error value)
530 * Wrapper for sn9c20x_set_contrast
533 int sn9c20x_set_brightness(struct usb_sn9c20x *dev)
535 return sn9c20x_set_contrast(dev);
539 * @brief Set gamma inside sn9c20x chip
541 * @author Comer352l
543 * @param dev Pointer to the device
545 * @return Zero (success) or negative (USB-error value)
548 int sn9c20x_set_gamma(struct usb_sn9c20x *dev)
550 int value = (dev->vsettings.gamma) * 0xb8 / 0x100;
551 int r = 0;
553 __u8 gamma_val[17] = {0x0a, 0x13, 0x25, 0x37, 0x45, 0x55, 0x65, 0x74,
554 0x83, 0x92, 0xa1, 0xb0, 0xbf, 0xce, 0xdf, 0xea, 0xf5};
556 gamma_val[0] = 0x0a;
557 gamma_val[1] = 0x13 + (value * (0xcb - 0x13) / 0xb8);
558 gamma_val[2] = 0x25 + (value * (0xee - 0x25) / 0xb8);
559 gamma_val[3] = 0x37 + (value * (0xfa - 0x37) / 0xb8);
560 gamma_val[4] = 0x45 + (value * (0xfc - 0x45) / 0xb8);
561 gamma_val[5] = 0x55 + (value * (0xfb - 0x55) / 0xb8);
562 gamma_val[6] = 0x65 + (value * (0xfc - 0x65) / 0xb8);
563 gamma_val[7] = 0x74 + (value * (0xfd - 0x74) / 0xb8);
564 gamma_val[8] = 0x83 + (value * (0xfe - 0x83) / 0xb8);
565 gamma_val[9] = 0x92 + (value * (0xfc - 0x92) / 0xb8);
566 gamma_val[10] = 0xa1 + (value * (0xfc - 0xa1) / 0xb8);
567 gamma_val[11] = 0xb0 + (value * (0xfc - 0xb0) / 0xb8);
568 gamma_val[12] = 0xbf + (value * (0xfb - 0xbf) / 0xb8);
569 gamma_val[13] = 0xce + (value * (0xfb - 0xce) / 0xb8);
570 gamma_val[14] = 0xdf + (value * (0xfd - 0xdf) / 0xb8);
571 gamma_val[15] = 0xea + (value * (0xf9 - 0xea) / 0xb8);
572 gamma_val[16] = 0xf5;
574 r = usb_sn9c20x_control_write(dev, 0x1190, gamma_val, 17);
576 return r;
580 * @brief Set saturation inside sn9c20x chip
582 * @author Neekhil
584 * @param dev Pointer to the device
586 * @return Zero (success) or negative (USB-error value)
589 int sn9c20x_set_saturation(struct usb_sn9c20x *dev)
591 int ret = 0;
592 int i = 0;
593 __u16 reg;
594 __u8 value;
595 __u16 saturation[10][2] = {
596 {0x10e7, 0xc2},
597 {0x10e8, 0x0f},
598 {0x10e9, 0xa0},
599 {0x10ea, 0x0f},
600 {0x10eb, 0x9e},
601 {0x10ed, 0x7e},
602 {0x10ef, 0x9d},
603 {0x10f0, 0x0f},
604 {0x10f1, 0xe7},
605 {0x10f2, 0x0f},
608 /* __u16 saturation[10][2] = {
609 {0x10e7, 0xdc},
610 {0x10e8, 0x0f},
611 {0x10e9, 0xb9},
612 {0x10ea, 0x0f},
613 {0x10eb, 0x6b},
614 {0x10ed, 0x59},
615 {0x10ef, 0xb6},
616 {0x10f0, 0x0f},
617 {0x10f1, 0xf2},
618 {0x10f2, 0x0f},
622 for( i = 0; i < 10; i++) {
623 reg = saturation[i][0];
624 value = saturation[i][1]*(dev->vsettings.colour/0xff);
625 ret = usb_sn9c20x_control_write(dev, reg, &value, 1);
626 UDIA_DEBUG("Saturation - Reg:0x%X Value:0x%X\n", reg, value);
629 if (ret < 0)
630 return ret;
631 else
632 return 0;
637 * @brief Set sharpness inside sn9c20x chip
639 * @author Comer352l
641 * @param dev Pointer to the device
643 * @return Zero (success) or negative (USB-error value)
646 int sn9c20x_set_sharpness(struct usb_sn9c20x *dev)
648 __u8 val[1];
649 int ret;
651 ret = usb_sn9c20x_control_read(dev, SN9C20X_SHARPNESS, val, 1);
652 if (ret < 0)
653 return ret;
654 val[0] = (val[0] & 0xc0) | (dev->vsettings.sharpness & 0x3f);
655 ret = usb_sn9c20x_control_write(dev, SN9C20X_SHARPNESS, val, 1);
656 if (ret < 0)
657 return ret;
658 else
659 return 0;
663 * @brief Set red gain inside sn9c20x chip
665 * @author Brian Johnson
667 * @param dev Pointer to the device
669 * @return Zero (success) or negative (USB-error value)
672 int sn9c20x_set_red_gain(struct usb_sn9c20x *dev)
674 __u8 val;
675 int ret;
677 val = dev->vsettings.red_gain;
678 ret = usb_sn9c20x_control_write(dev, SN9C20X_RED_GAIN, &val, 1);
679 if (ret < 0)
680 return ret;
681 else
682 return 0;
686 * @brief Set blue gain inside sn9c20x chip
688 * @author Brian Johnson
690 * @param dev Pointer to the device
692 * @return Zero (success) or negative (USB-error value)
695 int sn9c20x_set_blue_gain(struct usb_sn9c20x *dev)
697 __u8 val;
698 int ret;
700 val = dev->vsettings.blue_gain;
701 ret = usb_sn9c20x_control_write(dev, SN9C20X_BLUE_GAIN, &val, 1);
702 if (ret < 0)
703 return ret;
704 else
705 return 0;
710 * @brief Calculate closest resolution to input from application
712 * @author Brian Johnson
714 * @param dev Pointer to the device structure
715 * @param width Requested width of video stream
716 * @param height Requested height of video stream
718 * @retval width Closest possible width of video stream
719 * @retval height Closest possible height of video stream
721 * @return Number of the
724 int sn9c20x_get_closest_resolution(struct usb_sn9c20x *dev,
725 int *width, int *height)
727 int i;
729 for (i = SN9C20X_N_MODES - 1; i >= 0; i--) {
730 if (*width >= sn9c20x_modes[i].width
731 && *height >= sn9c20x_modes[i].height)
732 break;
735 *width = sn9c20x_modes[i].width;
736 *height = sn9c20x_modes[i].height;
738 return i;
742 * @brief Set resolution inside sn9c20x chip
744 * @author Brian Johnson
746 * @param dev Pointer to the device
747 * @param width Width
748 * @param height Height
750 * @return 0
753 int sn9c20x_set_resolution(struct usb_sn9c20x *dev,
754 int width, int height)
756 int ret;
757 __u8 scale;
758 __u8 window[6];
759 __u8 clrwindow[5];
760 struct sn9c20x_video_mode *mode;
762 ret = sn9c20x_get_closest_resolution(dev, &width, &height);
764 mode = &sn9c20x_modes[ret];
766 dev->vsettings.format.width = mode->width;
767 dev->vsettings.format.height = mode->height;
769 clrwindow[0] = 0;
770 clrwindow[1] = mode->width >> 2;
771 clrwindow[2] = 0;
772 clrwindow[3] = mode->height >> 1;
773 clrwindow[4] = ((mode->width >> 10) & 0x01) |
774 ((mode->height >> 8) & 0x06);
776 scale = mode->scale;
778 window[0] = (mode->window[0] + dev->camera.hstart) & 0xff;
779 window[1] = (mode->window[0] + dev->camera.hstart) >> 8;
780 window[2] = (mode->window[1] + dev->camera.vstart) & 0xff;
781 window[3] = (mode->window[1] + dev->camera.vstart) >> 8;
782 window[4] = mode->window[2] >> 4;
783 window[5] = mode->window[3] >> 3;
785 usb_sn9c20x_control_write(dev, 0x10fb, clrwindow, 5);
786 usb_sn9c20x_control_write(dev, 0x1180, window, 6);
787 usb_sn9c20x_control_write(dev, SN9C20X_SCALE, &scale, 1);
789 UDIA_DEBUG("Set mode [%dx%d]\n", mode->width, mode->height);
791 return 0;
795 int sn9c20x_set_format(struct usb_sn9c20x *dev, __u32 format)
797 int i;
798 int ret = -EINVAL;
799 for (i = 0; i < SN9C20X_N_FMTS; i++) {
800 if (sn9c20x_fmts[i].pix_fmt == format) {
801 dev->vsettings.format.bytesperline =
802 dev->vsettings.format.width *
803 sn9c20x_fmts[i].depth / 8;
804 dev->vsettings.format.sizeimage =
805 dev->vsettings.format.height *
806 dev->vsettings.format.bytesperline;
807 dev->vsettings.format.pixelformat = format;
808 dev->vsettings.format.colorspace = V4L2_COLORSPACE_SRGB;
809 dev->vsettings.format.priv = 0;
810 sn9c20x_fmts[i].set_format(dev);
811 ret = 0;
812 break;
815 return ret;
818 void sn9c20x_set_raw(struct usb_sn9c20x *dev)
820 __u8 value;
821 value = 0x2d;
822 usb_sn9c20x_control_write(dev, 0x10e0, &value, 1);
823 UDIA_INFO("Using raw output format\n");
826 void sn9c20x_set_jpeg(struct usb_sn9c20x *dev)
828 __u8 value;
829 value = 0x2c;
830 usb_sn9c20x_control_write(dev, 0x10e0, &value, 1);
831 UDIA_INFO("Using jpeg output format\n");
834 void sn9c20x_set_yuv420(struct usb_sn9c20x *dev)
836 __u8 value;
837 value = 0x2f;
838 usb_sn9c20x_control_write(dev, 0x10e0, &value, 1);
839 UDIA_INFO("Using yuv420 output format\n");
842 void sn9c20x_set_yuv422(struct usb_sn9c20x *dev)
844 __u8 value;
845 value = 0x2e;
846 usb_sn9c20x_control_write(dev, 0x10e0, &value, 1);
847 UDIA_INFO("Using yuv422 output format\n");
851 * @brief This function initializes the SN9C20x bridge,
852 * these are the bare minimum writes that must be done for
853 * the bridge to work correctly.
855 * @author Neekhil
857 * @param dev Pointer to the device
859 * @return Zero for success or error value
862 int sn9c20x_initialize(struct usb_sn9c20x *dev)
864 int ret, i;
866 __u16 reg;
867 __u8 value;
869 __u16 regs[][2] = {
870 {0x1000, 0x78},
871 {0x1001, 0x40},
872 {0x1002, 0x1c},
873 {0x1020, 0x80},
874 {0x1061, 0x01},
875 {0x1067, 0x40},
876 {0x1068, 0x30},
877 {0x1069, 0x20},
878 {0x106a, 0x10},
879 {0x106b, 0x08},
880 {0x1188, 0x87},
881 {0x11a1, 0x00},
882 {0x11a2, 0x00},
883 {0x11a3, 0x6a},
884 {0x11a4, 0x50},
885 {0x11ab, 0x00},
886 {0x11ac, 0x00},
887 {0x11ad, 0x50},
888 {0x11ae, 0x3c},
889 {0x118a, 0x04},
890 {0x0395, 0x04},
891 {0x11b8, 0x3a},
892 {0x118b, 0x0e},
893 {0x10f7, 0x05},
894 {0x10f8, 0x14},
895 {0x10fa, 0xff},
896 {0x10f9, 0x00},
897 {0x11ba, 0x0a},
898 {0x11a5, 0x2d},
899 {0x11a6, 0x2d},
900 {0x11a7, 0x3a},
901 {0x11a8, 0x05},
902 {0x11a9, 0x04},
903 {0x11aa, 0x3f},
904 {0x11af, 0x28},
905 {0x11b0, 0xd8},
906 {0x11b1, 0x14},
907 {0x11b2, 0xec},
908 {0x11b3, 0x32},
909 {0x11b4, 0xdd},
910 {0x11b5, 0x32},
911 {0x11b6, 0xdd},
912 {0x10e0, 0x2c},
913 {0x11bc, 0x40},
914 {0x11bd, 0x01},
915 {0x11be, 0xf0},
916 {0x11bf, 0x00},
917 {0x118c, 0x1f},
918 {0x118d, 0x1f},
919 {0x118e, 0x1f},
920 {0x118f, 0x1f},
921 {0x1180, 0x01},
922 {0x1181, 0x00},
923 {0x1182, 0x01},
924 {0x1183, 0x00},
925 {0x1184, 0x50},
926 {0x1185, 0x80},
929 __u8 qtable1[64] = {
930 0x0d, 0x08, 0x08, 0x0d, 0x08, 0x08, 0x0d, 0x0d,
931 0x0d, 0x0d, 0x11, 0x0d, 0x0d, 0x11, 0x15, 0x21,
932 0x15, 0x15, 0x11, 0x11, 0x15, 0x2a, 0x1d, 0x1d,
933 0x19, 0x21, 0x32, 0x2a, 0x32, 0x32, 0x2e, 0x2a,
934 0x2e, 0x2e, 0x36, 0x3a, 0x4b, 0x43, 0x36, 0x3a,
935 0x47, 0x3a, 0x2e, 0x2e, 0x43, 0x5c, 0x43, 0x47,
936 0x4f, 0x54, 0x58, 0x58, 0x58, 0x32, 0x3f, 0x60,
937 0x64, 0x5c, 0x54, 0x64, 0x4b, 0x54, 0x58, 0x54
940 __u8 qtable2[64] = {
941 0x0d, 0x11, 0x11, 0x15, 0x11, 0x15, 0x26, 0x15,
942 0x15, 0x26, 0x54, 0x36, 0x2e, 0x36, 0x54, 0x54,
943 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54,
944 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54,
945 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54,
946 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54,
947 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54,
948 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54
951 for (i = 0; i < ARRAY_SIZE(regs); i++) {
952 reg = regs[i][0];
953 value = regs[i][1];
954 ret = usb_sn9c20x_control_write(dev, reg, &value, 1);
955 if (ret < 0) {
956 UDIA_INFO("Bridge Init Error (%d). line %d\n", ret, i);
957 goto err;
961 ret = usb_sn9c20x_control_write(dev, 0x1100, qtable1, 64);
962 if (ret < 0)
963 goto err;
965 ret = usb_sn9c20x_control_write(dev, 0x1140, qtable2, 64);
966 if (ret < 0)
967 goto err;
969 dev->camera.set_contrast = sn9c20x_set_contrast;
970 dev->camera.set_brightness = sn9c20x_set_brightness;
971 dev->camera.set_gamma = sn9c20x_set_gamma;
972 dev->camera.set_saturation = sn9c20x_set_saturation;
973 dev->camera.set_sharpness = sn9c20x_set_sharpness;
974 dev->camera.set_red_gain = sn9c20x_set_red_gain;
975 dev->camera.set_blue_gain = sn9c20x_set_blue_gain;
977 ret = sn9c20x_i2c_initialize(dev);
978 if (ret < 0)
979 goto err;
981 ret = sn9c20x_initialize_sensor(dev);
982 return ret;
984 err:
985 UDIA_ERROR("Device Init failed (%d)!\n", ret);
986 return ret;