Readd MT9V111 and MT9V011 (6270)
[microdia.git] / sn9c20x.c
blob8a5853ebfb7ec7ca825d636b4fdafe8c1c8f167f
1 /**
2 * @file sn9c20x.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 "microdia.h"
31 #include "sn9c20x.h"
33 /**
34 * @brief This function initializes the SN9C20x bridge,
35 * these are the bare minimum writes that must be done for
36 * the bridge to work correctly.
38 * @author Neekhil
40 * @param dev Pointer to the device
42 * @return Zero for success or error value
45 int sn9c20x_initialize(struct usb_microdia *dev)
47 int ret, i, sensor;
49 __u16 reg;
50 __u8 value;
52 __u16 regs[][2] = {
53 {0x1000, 0x78},
54 {0x1001, 0x40},
55 {0x1002, 0x1c},
56 {0x1020, 0x80},
57 {0x1061, 0x01},
58 {0x1067, 0x40},
59 {0x1068, 0x30},
60 {0x1069, 0x20},
61 {0x106a, 0x10},
62 {0x106b, 0x08},
63 {0x1188, 0x87},
64 {0x11a1, 0x00},
65 {0x11a2, 0x00},
66 {0x11a3, 0x6a},
67 {0x11a4, 0x50},
68 {0x11ab, 0x00},
69 {0x11ac, 0x00},
70 {0x11ad, 0x50},
71 {0x11ae, 0x3c},
72 {0x118a, 0x04},
73 {0x0395, 0x04},
74 {0x11b8, 0x3a},
75 {0x118b, 0x0e},
76 {0x10f7, 0x05},
77 {0x10f8, 0x14},
78 {0x10fa, 0xff},
79 {0x10f9, 0x00},
80 {0x11ba, 0x0e},
81 {0x11a5, 0x2d},
82 {0x11a6, 0x2d},
83 {0x11a7, 0x3a},
84 {0x11a8, 0x05},
85 {0x11a9, 0x04},
86 {0x11aa, 0x3f},
87 {0x11af, 0x28},
88 {0x11b0, 0xd8},
89 {0x11b1, 0x14},
90 {0x11b2, 0xec},
91 {0x11b3, 0x32},
92 {0x11b4, 0xdd},
93 {0x11b5, 0x32},
94 {0x11b6, 0xdd},
95 {0x10e0, 0x2c},
96 {0x11bc, 0x40},
97 {0x11bd, 0x01},
98 {0x11be, 0xf0},
99 {0x11bf, 0x00},
102 __u8 lens_gain[48] = {
103 0x10, 0x21, 0x34, 0x40, 0x47, 0x4f, 0x57, 0x5f,
104 0x64, 0x68, 0x6d, 0x73, 0x79, 0x80, 0x89, 0x97,
105 0x0d, 0x1c, 0x2a, 0x33, 0x38, 0x3d, 0x44, 0x4a,
106 0x4e, 0x52, 0x56, 0x5b, 0x61, 0x68, 0x6f, 0x7a,
107 0x0d, 0x1a, 0x2a, 0x31, 0x36, 0x3b, 0x41, 0x47,
108 0x4a, 0x4e, 0x53, 0x58, 0x5d, 0x64, 0x6b, 0x76
111 __u8 qtable1[64] = {
112 0x0d, 0x08, 0x08, 0x0d, 0x08, 0x08, 0x0d, 0x0d,
113 0x0d, 0x0d, 0x11, 0x0d, 0x0d, 0x11, 0x15, 0x21,
114 0x15, 0x15, 0x11, 0x11, 0x15, 0x2a, 0x1d, 0x1d,
115 0x19, 0x21, 0x32, 0x2a, 0x32, 0x32, 0x2e, 0x2a,
116 0x2e, 0x2e, 0x36, 0x3a, 0x4b, 0x43, 0x36, 0x3a,
117 0x47, 0x3a, 0x2e, 0x2e, 0x43, 0x5c, 0x43, 0x47,
118 0x4f, 0x54, 0x58, 0x58, 0x58, 0x32, 0x3f, 0x60,
119 0x64, 0x5c, 0x54, 0x64, 0x4b, 0x54, 0x58, 0x54
122 __u8 qtable2[64] = {
123 0x0d, 0x11, 0x11, 0x15, 0x11, 0x15, 0x26, 0x15,
124 0x15, 0x26, 0x54, 0x36, 0x2e, 0x36, 0x54, 0x54,
125 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54,
126 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54,
127 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54,
128 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54,
129 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54,
130 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54
133 for (i = 0; i < ARRAY_SIZE(regs); i++) {
134 reg = regs[i][0];
135 value = regs[i][1];
136 ret = usb_microdia_control_write(dev, reg, &value, 1);
137 if (ret < 0) {
138 UDIA_INFO("Bridge Init Error (%d). line %d\n", ret, i);
139 goto err;
143 ret = usb_microdia_control_write(dev, 0x1100, qtable1, 64);
144 if (ret < 0)
145 goto err;
147 ret = usb_microdia_control_write(dev, 0x1140, qtable2, 64);
148 if (ret < 0)
149 goto err;
151 ret = sn9c20x_i2c_initialize(dev);
152 if (ret < 0)
153 goto err;
155 dev->camera.enable_video = sn9c20x_enable_video;
157 dev->camera.set_contrast = sn9c20x_set_contrast;
158 dev->camera.set_brightness = sn9c20x_set_brightness;
159 dev->camera.set_gamma = sn9c20x_set_gamma;
160 dev->camera.set_sharpness = sn9c20x_set_sharpness;
161 dev->camera.set_rgb_gain = sn9c20x_set_rgb_gain;
163 sensor = dev_microdia_probe_sensor(dev);
164 if (sensor == UNKNOWN_SENSOR) {
165 UDIA_ERROR("Failed to detect sensor.\n");
166 ret = -ENODEV;
167 goto err;
170 if (!(sensor == OV9650_SENSOR || sensor == OV9655_SENSOR))
171 memset(lens_gain, 0x00, 48);
173 ret = usb_microdia_control_write(dev, 0x11c0, lens_gain, 48);
174 if (ret < 0)
175 goto err;
177 return 0;
179 err:
180 UDIA_ERROR("Devive Init failed (%d)!\n", ret);
181 return ret;
185 * @brief Switch Video stream on and off
187 * @param dev Pointer to device structure
188 * @param enable On or off
190 * @author Brian Johnson
192 * @return 0 or negative error code
195 int sn9c20x_enable_video(struct usb_microdia *dev, int enable)
197 __u8 value;
198 int ret;
200 ret = usb_microdia_control_read(dev, 0x1061, &value, 1);
201 if (ret < 0)
202 return ret;
204 if (enable) {
205 value |= 0x02;
206 ret = usb_microdia_control_write(dev, 0x1061, &value, 1);
207 } else {
208 value &= ~0x02;
209 ret = usb_microdia_control_write(dev, 0x1061, &value, 1);
211 if (ret < 0)
212 return ret;
214 ret = sn9c20x_set_LEDs(dev, enable);
216 return ret;
220 * @brief Switch LEDs on and off
222 * @param dev Pointer to device structure
223 * @param enable On or off
225 * @author GWater
227 * @return 0 or negative error code
230 int sn9c20x_set_LEDs(struct usb_microdia *dev, int enable)
232 int ret;
233 __u8 led[2];
235 int sensor = dev_microdia_probe_sensor(dev);
237 if (enable) {
238 switch (sensor) {
239 /* case MI1300_SENSOR:
240 led[0] = 0x80;
241 led[1] = 0xa0;
242 break;
243 case MI1310_SENSOR:
244 led[0] = 0x00;
245 led[1] = 0x60;
246 break;
247 case MT9V011_SENSOR:
248 led[0] = 0x40;
249 led[1] = 0x60;
250 break;
251 */ case SOI968_SENSOR:
252 led[0] = 0x80;
253 led[1] = 0xa0;
254 break;
255 case OV7660_SENSOR:
256 led[0] = 0x40;
257 led[1] = 0x60;
258 break;
259 default:
260 led[0] = 0x00;
261 led[1] = 0x20;
263 } else {
264 switch (sensor) {
265 /* case MI1300_SENSOR:
266 led[0] = 0xa0;
267 led[1] = 0xa0;
268 break;
269 case MI1310_SENSOR:
270 led[0] = 0x20;
271 led[1] = 0x60;
272 break;
273 case MT9V011_SENSOR:
274 led[0] = 0xa0;
275 led[1] = 0xa0;
276 break;
277 */ case OV7660_SENSOR:
278 led[0] = 0x20;
279 led[1] = 0x60;
280 break;
281 default:
282 led[0] = 0x20;
283 led[1] = 0x20;
287 ret = usb_microdia_control_write(dev, 0x1006, led, 2);
289 return ret;
293 * @brief Initializes Micro-Controller's I2C interface
295 * @author Neekhil
297 * @param dev Pointer to the device
299 * @return Zero (success) or negative (USB-error value)
302 int sn9c20x_i2c_initialize(struct usb_microdia *dev)
304 __u8 buf[9];
305 int ret;
307 buf[0] = dev->camera.sensor_flags;
308 buf[1] = dev->camera.sensor_slave_address;
309 buf[2] = 0x00;
310 buf[3] = 0x00;
311 buf[4] = 0x00;
312 buf[5] = 0x00;
313 buf[6] = 0x00;
314 buf[7] = 0x00;
315 buf[8] = 0x03;
316 /* Initialize I2C registers to avoid getting no ACK at first I2C operation: */
317 /* Get green diagonal bands w/o this dummy write, Bridge does not know sensor address ? */
318 ret = usb_microdia_control_write(dev, 0x10c0, buf, 9);
319 if (ret < 0)
320 return ret;
321 else
322 return 0;
326 * @brief Wait until the I2C slave is ready for the next operation
328 * @param dev Pointer to the device
329 * @param highspeed
330 * @param slave_error
332 * @return Zero for success or a negative error value
335 int sn9c20x_i2c_ack_wait(struct usb_microdia *dev, bool highspeed, bool *slave_error)
337 int ret, i;
338 __u8 readbuf;
339 int delay = highspeed ? 100 : 400;
341 for (i = 0; i < 5; i++) {
342 ret = usb_microdia_control_read(dev, 0x10c0, &readbuf, 1);
344 if (ret < 0)
345 return ret;
346 else if (readbuf & SN9C20X_I2C_ERROR) {
347 *slave_error = 1;
348 /* probably should come up w/ an error value and
349 * return it via the error return */
350 return 0;
351 } else if (readbuf & SN9C20X_I2C_READY)
352 return 0;
353 else
354 udelay(delay);
356 return -EBUSY;
360 * @brief Read up to 5 bytes of data from an I2C slave
362 * @param dev Pointer to the device
363 * @param nbytes Number of bytes to read
364 * @param address The address of the register on the slave to read
365 * @param result A pointer to the location at which the result should be stored
367 * @return Zero for success or a negative error value
370 int sn9c20x_read_i2c_data(struct usb_microdia *dev, __u8 nbytes,
371 __u8 address, __u8 *result)
373 int ret, i, j;
374 __u8 row[5];
376 if (!dev || nbytes > 4)
377 return -EINVAL;
379 /* first, we must do a dummy write of just the address */
380 ret = sn9c20x_write_i2c_data(dev, 0, address, NULL);
381 if (ret < 0)
382 return ret;
384 memset(row, 0, 5);
385 /* now we issue the same command but with the read bit set
386 * and no slave register address */
387 dev->camera.sensor_flags |= SN9C20X_I2C_READ;
388 ret = sn9c20x_write_i2c_data(dev, nbytes - 1, 0, row);
389 dev->camera.sensor_flags &= ~SN9C20X_I2C_READ;
390 if (ret < 0)
391 return ret;
393 /* finally, ask the bridge for the data */
394 ret = usb_microdia_control_read(dev, 0x10c2, row, 5);
395 if (ret < 0)
396 return ret;
398 for (i = 0, j = 5 - nbytes; i < nbytes; i++, j++)
399 result[i] = row[j];
401 return 0;
405 * @brief Read up to 4 bytes of data from an I2C slave an return them as 16bit values
407 * @param dev Pointer to the device
408 * @param datalen Number of 16bit values to read
409 * @param address The address of the register on the slave to read
410 * @param result A pointer to the location at which the result should be stored
412 * @return Zero for success or a negative error value
415 int sn9c20x_read_i2c_data16(struct usb_microdia *dev, __u8 datalen,
416 __u8 address, __u16 *result)
418 __u8 result8[4];
419 __u8 k;
420 int ret;
422 if (datalen > 2)
423 return -EINVAL;
424 ret = sn9c20x_read_i2c_data(dev, 2*datalen, address, result8);
425 for (k = 0; k < datalen; k++)
426 result[k] = (result8[k*2] << 8) | result8[k*2+1];
427 return ret;
430 static const char *wasread = "read from";
431 static const char *waswrite = "write to";
434 * @brief Write up to 5 bytes of data to an I2C slave
436 * @param dev Pointer to the device
437 * @param nbytes The number of bytes of data
438 * @param address The address of the register on the slave to write
439 * @param data An array containing the data to write
441 * @return Zero for success or a negative error value
444 int sn9c20x_write_i2c_data(struct usb_microdia *dev, __u8 nbytes,
445 __u8 address, const __u8 data[nbytes])
447 int ret, i;
448 __u8 row[8];
449 bool slave_error = 0;
451 if (!dev || (nbytes > 0 && !data) || nbytes > 4)
452 return -EINVAL;
454 /* from the point of view of the bridge, the length
455 * includes the address */
456 row[0] = dev->camera.sensor_flags | ((nbytes + 1) << 4);
457 row[1] = dev->camera.sensor_slave_address;
458 row[2] = address;
459 row[7] = 0x10; /* I think this means we want an ack */
461 for (i = 0; i < 4; i++)
462 row[i + 3] = i < nbytes ? data[i] : 0;
464 UDIA_DEBUG("I2C %s %02x: %02x %02x %02x %02x %02x %02x %02x %02x\n",
465 (dev->camera.sensor_flags & SN9C20X_I2C_READ ? wasread : waswrite), address,
466 row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7]);
468 ret = usb_microdia_control_write(dev, 0x10c0, row, 8);
469 if (ret >= 0)
470 ret = sn9c20x_i2c_ack_wait(dev,
471 dev->camera.sensor_flags & SN9C20X_I2C_400KHZ,
472 &slave_error);
474 if (slave_error) {
475 UDIA_ERROR("I2C slave 0x%02x returned error during %s address 0x%02x\n",
476 dev->camera.sensor_slave_address,
477 (dev->camera.sensor_flags & SN9C20X_I2C_READ ? wasread : waswrite),
478 address);
479 return -1000;
480 /* there should be no interference with USB errors */
483 if (ret < 0) {
484 /* we got no ack */
485 UDIA_ERROR("No ack from I2C slave 0x%02x for %s address 0x%02x\n",
486 dev->camera.sensor_slave_address,
487 (dev->camera.sensor_flags & SN9C20X_I2C_READ ? wasread : waswrite),
488 address);
489 return ret;
492 return 0;
496 * @brief Write up to 2 16bit values als single bytes to an I2C slave
498 * @param dev Pointer to the device
499 * @param datalen The number of 16bit data values to write
500 * @param address The address of the register on the slave to write
501 * @param data An array containing the data to write
503 * @return Zero for success or a negative error value
506 int sn9c20x_write_i2c_data16(struct usb_microdia *dev, __u8 datalen,
507 __u8 address, const __u16 data[datalen])
509 __u8 data8[4];
510 __u8 k;
511 int ret;
513 if (datalen > 2)
514 return -EINVAL;
515 for (k = 0; k < datalen; k++) {
516 data8[k*2] = data[k] >> 8;
517 data8[k*2+1] = data[k] & 0xff;
519 ret = sn9c20x_write_i2c_data(dev, 2*datalen, address, data8);
520 return ret;
524 * @brief Set contrast inside sn9c20x chip
526 * @author Comer352l
528 * @param dev Pointer to the device
530 * @return Zero (success) or negative (USB-error value)
533 int sn9c20x_set_contrast(struct usb_microdia *dev)
535 /* from 0x26 to 0x4b */
536 __u8 brightness_contrast[21] = {0x16, 0x0, 0x2b, 0x0, 0x8, 0x0, 0xf6, 0x0f,
537 0xd2, 0x0f, 0x38, 0x0, 0x34, 0x0, 0xcf, 0x0f,
538 0xfd, 0x0f, 0x0, 0x0, 0x0};
539 __u8 contrast_val = (dev->vsettings.contrast >> 8) * 0x25 / 0x100;
540 __u8 brightness_val = dev->vsettings.brightness >> 8;
542 brightness_val -= 0x80;
543 brightness_contrast[18] = brightness_val;
545 contrast_val += 0x26;
546 brightness_contrast[2] = contrast_val;
547 brightness_contrast[0] = 0x13 + (brightness_contrast[2] - 0x26) * 0x13 / 0x25;
548 brightness_contrast[4] = 0x7 + (brightness_contrast[2] - 0x26) * 0x7 / 0x25;
550 return usb_microdia_control_write(dev, 0x10e1, brightness_contrast, 21);
554 * @brief Set brightness inside sn9c20x chip
556 * @author Comer352l
558 * @param dev Pointer to the device
560 * @return Zero (success) or negative (USB-error value)
562 * Wrapper for sn9c20x_set_contrast
565 int sn9c20x_set_brightness(struct usb_microdia *dev)
567 return dev_microdia_camera_set_contrast(dev);
571 * @brief Set gamma inside sn9c20x chip
573 * @author Comer352l
575 * @param dev Pointer to the device
577 * @return Zero (success) or negative (USB-error value)
580 int sn9c20x_set_gamma(struct usb_microdia *dev)
582 int value = (dev->vsettings.whiteness >> 8) * 0xb8 / 0x100;
583 int r = 0;
585 __u8 gamma_val[17] = {0x0a, 0x13, 0x25, 0x37, 0x45, 0x55, 0x65, 0x74,
586 0x83, 0x92, 0xa1, 0xb0, 0xbf, 0xce, 0xdf, 0xea, 0xf5};
588 gamma_val[0] = 0x0a;
589 gamma_val[1] = 0x13 + (value * (0xcb - 0x13) / 0xb8);
590 gamma_val[2] = 0x25 + (value * (0xee - 0x25) / 0xb8);
591 gamma_val[3] = 0x37 + (value * (0xfa - 0x37) / 0xb8);
592 gamma_val[4] = 0x45 + (value * (0xfc - 0x45) / 0xb8);
593 gamma_val[5] = 0x55 + (value * (0xfb - 0x55) / 0xb8);
594 gamma_val[6] = 0x65 + (value * (0xfc - 0x65) / 0xb8);
595 gamma_val[7] = 0x74 + (value * (0xfd - 0x74) / 0xb8);
596 gamma_val[8] = 0x83 + (value * (0xfe - 0x83) / 0xb8);
597 gamma_val[9] = 0x92 + (value * (0xfc - 0x92) / 0xb8);
598 gamma_val[10] = 0xa1 + (value * (0xfc - 0xa1) / 0xb8);
599 gamma_val[11] = 0xb0 + (value * (0xfc - 0xb0) / 0xb8);
600 gamma_val[12] = 0xbf + (value * (0xfb - 0xbf) / 0xb8);
601 gamma_val[13] = 0xce + (value * (0xfb - 0xce) / 0xb8);
602 gamma_val[14] = 0xdf + (value * (0xfd - 0xdf) / 0xb8);
603 gamma_val[15] = 0xea + (value * (0xf9 - 0xea) / 0xb8);
604 gamma_val[16] = 0xf5;
606 r = usb_microdia_control_write(dev, 0x1190, gamma_val, 17);
608 return r;
612 * @brief Set sharpness inside sn9c20x chip
614 * @author Comer352l
616 * @param dev Pointer to the device
618 * @return Zero (success) or negative (USB-error value)
621 int sn9c20x_set_sharpness(struct usb_microdia *dev)
623 __u8 val[1];
624 int ret;
626 ret = usb_microdia_control_read(dev, SN9C20X_SHARPNESS, val, 1);
627 if (ret < 0)
628 return ret;
629 val[0] = (val[0] & 0xc0) | (dev->vsettings.sharpness & 0x3f);
630 ret = usb_microdia_control_write(dev, SN9C20X_SHARPNESS, val, 1);
631 if (ret < 0)
632 return ret;
633 else
634 return 0;
638 * @brief Set colour gain inside sn9c20x chip
640 * @author Brian Johnson
642 * @param dev Pointer to the device
644 * @return Zero (success) or negative (USB-error value)
647 int sn9c20x_set_rgb_gain(struct usb_microdia *dev)
649 __u8 val[4];
650 int ret;
652 memcpy(&val, &(dev->vsettings.rgb_gain), 4);
653 ret = usb_microdia_control_write(dev, SN9C20X_RED_GAIN, val, 4);
654 if (ret < 0)
655 return ret;
656 else
657 return 0;
661 * @brief Calculate closest resolution to input from application
663 * @author Brian Johnson
665 * @param dev Pointer to the device structure
666 * @param width Requested width of video stream
667 * @param height Requested height of video stream
669 * @retval width Closest possible width of video stream
670 * @retval height Closest possible height of video stream
672 * @return Number of the
675 int sn9c20x_get_closest_resolution(struct usb_microdia *dev,
676 int *width, int *height)
678 int i;
680 for (i = dev->camera.nmodes - 1; i >= 0; i--) {
681 if (*width >= dev->camera.modes[i].width
682 && *height >= dev->camera.modes[i].height)
683 break;
686 *width = dev->camera.modes[i].width;
687 *height = dev->camera.modes[i].height;
689 return i;
693 * @brief Set resolution inside sn9c20x chip
695 * @author Brian Johnson
697 * @param dev Pointer to the device
698 * @param width Width
699 * @param height Height
701 * @return 0
704 int sn9c20x_set_resolution(struct usb_microdia *dev,
705 int width, int height)
707 int ret;
708 __u8 scale;
709 __u8 window[6];
710 __u8 clrwindow[6];
711 struct microdia_video_resolution *mode;
713 ret = sn9c20x_get_closest_resolution(dev, &width, &height);
715 mode = &dev->camera.modes[ret];
717 dev->vsettings.format.width = mode->width;
718 dev->vsettings.format.height = mode->height;
720 clrwindow[0] = 0; clrwindow[1] = mode->width >> 2;
721 clrwindow[2] = 0; clrwindow[3] = mode->height >> 1;
722 clrwindow[4] = ((mode->width >> 10) & 0x01) |
723 ((mode->height >> 10) & 0x06);
725 scale = mode->scale;
726 if (clrwindow[4] & 0x01)
727 scale += 0x40;
729 window[0] = mode->window[0] & 0xff; window[1] = mode->window[0] >> 8;
730 window[2] = mode->window[1] & 0xff; window[3] = mode->window[1] >> 8;
731 window[4] = mode->window[2] >> 4; window[5] = mode->window[3] >> 3;
733 usb_microdia_control_write(dev, 0x10fb, clrwindow, 5);
734 usb_microdia_control_write(dev, 0x1180, window, 6);
735 usb_microdia_control_write(dev, SN9C20X_SCALE, &scale, 1);
737 UDIA_DEBUG("Set mode [%dx%d]\n", mode->width, mode->height);
739 return 0;
742 int sn9c20x_set_raw(struct usb_microdia *dev)
744 __u8 value = 0x2d;
745 usb_microdia_control_write(dev, 0x10e0, &value, 1);
746 return 0;
749 int sn9c20x_set_jpeg(struct usb_microdia *dev)
751 __u8 value = 0x2c;
752 usb_microdia_control_write(dev, 0x10e0, &value, 1);
753 return 0;
757 * @brief Set exposure inside sn9c20x chip
759 * @param dev
761 * @returns 0 or negative error value
763 * @author GWater
765 int sn9c20x_set_exposure(struct usb_microdia *dev)
767 __u8 buf;
768 int ret;
769 int exposure = dev->vsettings.exposure;
771 buf = (__u8) (exposure * 0x00ff / 0xffff) & 0x00ff;
773 /* exposure can't be 0 - below 0x04 the image freezes */
774 if (buf < 0x05)
775 buf = 0x05;
777 /* write new value to register 0x118a */
778 ret = usb_microdia_control_write(dev, 0x118a, &buf, 1);
779 if (ret < 0) {
780 UDIA_ERROR("Error: setting exposure failed: "
781 "error while writing to register 0x118a\n");
782 return ret;
785 return 0;