Stop sensor_init from being executed twice
[microdia.git] / sn9c20x.c
blobfede1ff2dd2fabb11f08b27927f06ee194476443
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;
169 dev->camera.sensor = sensor;
171 if (!(sensor == OV9650_SENSOR || sensor == OV9655_SENSOR))
172 memset(lens_gain, 0x00, 48);
174 ret = usb_microdia_control_write(dev, 0x11c0, lens_gain, 48);
175 if (ret < 0)
176 goto err;
178 return 0;
180 err:
181 UDIA_ERROR("Devive Init failed (%d)!\n", ret);
182 return ret;
186 * @brief Switch Video stream on and off
188 * @param dev Pointer to device structure
189 * @param enable On or off
191 * @author Brian Johnson
193 * @return 0 or negative error code
196 int sn9c20x_enable_video(struct usb_microdia *dev, int enable)
198 __u8 value;
199 int ret;
201 ret = usb_microdia_control_read(dev, 0x1061, &value, 1);
202 if (ret < 0)
203 return ret;
205 if (enable) {
206 value |= 0x02;
207 ret = usb_microdia_control_write(dev, 0x1061, &value, 1);
208 } else {
209 value &= ~0x02;
210 ret = usb_microdia_control_write(dev, 0x1061, &value, 1);
212 if (ret < 0)
213 return ret;
215 ret = sn9c20x_set_LEDs(dev, enable);
217 return ret;
221 * @brief Switch LEDs on and off
223 * @param dev Pointer to device structure
224 * @param enable On or off
226 * @author GWater
228 * @return 0 or negative error code
231 int sn9c20x_set_LEDs(struct usb_microdia *dev, int enable)
233 int ret;
234 __u8 led[2];
236 int sensor = dev->camera.sensor;
238 if (enable) {
239 switch (sensor) {
240 case MT9M001_SENSOR:
241 led[0] = 0x80;
242 led[1] = 0xa0;
243 break;
244 case SOI968_SENSOR:
245 led[0] = 0x80;
246 led[1] = 0xa0;
247 break;
248 case MT9V011_SENSOR:
249 led[0] = 0x40;
250 led[1] = 0x60;
251 break;
252 case OV7660_SENSOR:
253 led[0] = 0x40;
254 led[1] = 0x60;
255 break;
256 case MT9M111_SENSOR:
257 led[0] = 0x00;
258 led[1] = 0x60;
259 break;
260 default:
261 led[0] = 0x00;
262 led[1] = 0x20;
264 } else {
265 switch (sensor) {
266 case MT9M001_SENSOR:
267 led[0] = 0xa0;
268 led[1] = 0xa0;
269 break;
270 case MT9V011_SENSOR:
271 led[0] = 0xa0;
272 led[1] = 0xa0;
273 break;
274 case MT9M111_SENSOR:
275 led[0] = 0x20;
276 led[1] = 0x60;
277 break;
278 case OV7660_SENSOR:
279 led[0] = 0x20;
280 led[1] = 0x60;
281 break;
282 default:
283 led[0] = 0x20;
284 led[1] = 0x20;
288 ret = usb_microdia_control_write(dev, 0x1006, led, 2);
290 return ret;
294 * @brief Initializes Micro-Controller's I2C interface
296 * @author Neekhil
298 * @param dev Pointer to the device
300 * @return Zero (success) or negative (USB-error value)
303 int sn9c20x_i2c_initialize(struct usb_microdia *dev)
305 __u8 buf[9];
306 int ret;
308 buf[0] = dev->camera.sensor_flags;
309 buf[1] = dev->camera.sensor_slave_address;
310 buf[2] = 0x00;
311 buf[3] = 0x00;
312 buf[4] = 0x00;
313 buf[5] = 0x00;
314 buf[6] = 0x00;
315 buf[7] = 0x00;
316 buf[8] = 0x03;
317 /* Initialize I2C registers to avoid getting no ACK at first I2C operation: */
318 /* Get green diagonal bands w/o this dummy write, Bridge does not know sensor address ? */
319 ret = usb_microdia_control_write(dev, 0x10c0, buf, 9);
320 if (ret < 0)
321 return ret;
322 else
323 return 0;
327 * @brief Wait until the I2C slave is ready for the next operation
329 * @param dev Pointer to the device
330 * @param highspeed
331 * @param slave_error
333 * @return Zero for success or a negative error value
336 int sn9c20x_i2c_ack_wait(struct usb_microdia *dev, bool highspeed, bool *slave_error)
338 int ret, i;
339 __u8 readbuf;
340 int delay = highspeed ? 100 : 400;
342 for (i = 0; i < 5; i++) {
343 ret = usb_microdia_control_read(dev, 0x10c0, &readbuf, 1);
345 if (ret < 0)
346 return ret;
347 else if (readbuf & SN9C20X_I2C_ERROR) {
348 *slave_error = 1;
349 /* probably should come up w/ an error value and
350 * return it via the error return */
351 return 0;
352 } else if (readbuf & SN9C20X_I2C_READY)
353 return 0;
354 else
355 udelay(delay);
357 return -EBUSY;
361 * @brief Read up to 5 bytes of data from an I2C slave
363 * @param dev Pointer to the device
364 * @param nbytes Number of bytes to read
365 * @param address The address of the register on the slave to read
366 * @param result A pointer to the location at which the result should be stored
368 * @return Zero for success or a negative error value
371 int sn9c20x_read_i2c_data(struct usb_microdia *dev, __u8 nbytes,
372 __u8 address, __u8 *result)
374 int ret, i, j;
375 __u8 row[5];
377 if (!dev || nbytes > 4)
378 return -EINVAL;
380 /* first, we must do a dummy write of just the address */
381 ret = sn9c20x_write_i2c_data(dev, 0, address, NULL);
382 if (ret < 0)
383 return ret;
385 memset(row, 0, 5);
386 /* now we issue the same command but with the read bit set
387 * and no slave register address */
388 dev->camera.sensor_flags |= SN9C20X_I2C_READ;
389 ret = sn9c20x_write_i2c_data(dev, nbytes - 1, 0, row);
390 dev->camera.sensor_flags &= ~SN9C20X_I2C_READ;
391 if (ret < 0)
392 return ret;
394 /* finally, ask the bridge for the data */
395 ret = usb_microdia_control_read(dev, 0x10c2, row, 5);
396 if (ret < 0)
397 return ret;
399 for (i = 0, j = 5 - nbytes; i < nbytes; i++, j++)
400 result[i] = row[j];
402 return 0;
406 * @brief Read up to 4 bytes of data from an I2C slave an return them as 16bit values
408 * @param dev Pointer to the device
409 * @param datalen Number of 16bit values to read
410 * @param address The address of the register on the slave to read
411 * @param result A pointer to the location at which the result should be stored
413 * @return Zero for success or a negative error value
416 int sn9c20x_read_i2c_data16(struct usb_microdia *dev, __u8 datalen,
417 __u8 address, __u16 *result)
419 __u8 result8[4];
420 __u8 k;
421 int ret;
423 if (datalen > 2)
424 return -EINVAL;
425 ret = sn9c20x_read_i2c_data(dev, 2*datalen, address, result8);
426 for (k = 0; k < datalen; k++)
427 result[k] = (result8[k*2] << 8) | result8[k*2+1];
428 return ret;
431 static const char *wasread = "read from";
432 static const char *waswrite = "write to";
435 * @brief Write up to 5 bytes of data to an I2C slave
437 * @param dev Pointer to the device
438 * @param nbytes The number of bytes of data
439 * @param address The address of the register on the slave to write
440 * @param data An array containing the data to write
442 * @return Zero for success or a negative error value
445 int sn9c20x_write_i2c_data(struct usb_microdia *dev, __u8 nbytes,
446 __u8 address, const __u8 data[nbytes])
448 int ret, i;
449 __u8 row[8];
450 bool slave_error = 0;
452 if (!dev || (nbytes > 0 && !data) || nbytes > 4)
453 return -EINVAL;
455 /* from the point of view of the bridge, the length
456 * includes the address */
457 row[0] = dev->camera.sensor_flags | ((nbytes + 1) << 4);
458 row[1] = dev->camera.sensor_slave_address;
459 row[2] = address;
460 row[7] = 0x10; /* I think this means we want an ack */
462 for (i = 0; i < 4; i++)
463 row[i + 3] = i < nbytes ? data[i] : 0;
465 UDIA_DEBUG("I2C %s %02x: %02x %02x %02x %02x %02x %02x %02x %02x\n",
466 (dev->camera.sensor_flags & SN9C20X_I2C_READ ? wasread : waswrite), address,
467 row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7]);
469 ret = usb_microdia_control_write(dev, 0x10c0, row, 8);
470 if (ret >= 0)
471 ret = sn9c20x_i2c_ack_wait(dev,
472 dev->camera.sensor_flags & SN9C20X_I2C_400KHZ,
473 &slave_error);
475 if (slave_error) {
476 UDIA_ERROR("I2C slave 0x%02x returned error during %s address 0x%02x\n",
477 dev->camera.sensor_slave_address,
478 (dev->camera.sensor_flags & SN9C20X_I2C_READ ? wasread : waswrite),
479 address);
480 return -1000;
481 /* there should be no interference with USB errors */
484 if (ret < 0) {
485 /* we got no ack */
486 UDIA_ERROR("No ack from I2C slave 0x%02x for %s address 0x%02x\n",
487 dev->camera.sensor_slave_address,
488 (dev->camera.sensor_flags & SN9C20X_I2C_READ ? wasread : waswrite),
489 address);
490 return ret;
493 return 0;
497 * @brief Write up to 2 16bit values als single bytes to an I2C slave
499 * @param dev Pointer to the device
500 * @param datalen The number of 16bit data values to write
501 * @param address The address of the register on the slave to write
502 * @param data An array containing the data to write
504 * @return Zero for success or a negative error value
507 int sn9c20x_write_i2c_data16(struct usb_microdia *dev, __u8 datalen,
508 __u8 address, const __u16 data[datalen])
510 __u8 data8[4];
511 __u8 k;
512 int ret;
514 if (datalen > 2)
515 return -EINVAL;
516 for (k = 0; k < datalen; k++) {
517 data8[k*2] = data[k] >> 8;
518 data8[k*2+1] = data[k] & 0xff;
520 ret = sn9c20x_write_i2c_data(dev, 2*datalen, address, data8);
521 return ret;
525 * @brief Set contrast inside sn9c20x chip
527 * @author Comer352l
529 * @param dev Pointer to the device
531 * @return Zero (success) or negative (USB-error value)
534 int sn9c20x_set_contrast(struct usb_microdia *dev)
536 /* from 0x26 to 0x4b */
537 __u8 brightness_contrast[21] = {0x16, 0x0, 0x2b, 0x0, 0x8, 0x0, 0xf6, 0x0f,
538 0xd2, 0x0f, 0x38, 0x0, 0x34, 0x0, 0xcf, 0x0f,
539 0xfd, 0x0f, 0x0, 0x0, 0x0};
540 __u8 contrast_val = (dev->vsettings.contrast >> 8) * 0x25 / 0x100;
541 __u8 brightness_val = dev->vsettings.brightness >> 8;
543 brightness_val -= 0x80;
544 brightness_contrast[18] = brightness_val;
546 contrast_val += 0x26;
547 brightness_contrast[2] = contrast_val;
548 brightness_contrast[0] = 0x13 + (brightness_contrast[2] - 0x26) * 0x13 / 0x25;
549 brightness_contrast[4] = 0x7 + (brightness_contrast[2] - 0x26) * 0x7 / 0x25;
551 return usb_microdia_control_write(dev, 0x10e1, brightness_contrast, 21);
555 * @brief Set brightness inside sn9c20x chip
557 * @author Comer352l
559 * @param dev Pointer to the device
561 * @return Zero (success) or negative (USB-error value)
563 * Wrapper for sn9c20x_set_contrast
566 int sn9c20x_set_brightness(struct usb_microdia *dev)
568 return dev_microdia_camera_set_contrast(dev);
572 * @brief Set gamma inside sn9c20x chip
574 * @author Comer352l
576 * @param dev Pointer to the device
578 * @return Zero (success) or negative (USB-error value)
581 int sn9c20x_set_gamma(struct usb_microdia *dev)
583 int value = (dev->vsettings.whiteness >> 8) * 0xb8 / 0x100;
584 int r = 0;
586 __u8 gamma_val[17] = {0x0a, 0x13, 0x25, 0x37, 0x45, 0x55, 0x65, 0x74,
587 0x83, 0x92, 0xa1, 0xb0, 0xbf, 0xce, 0xdf, 0xea, 0xf5};
589 gamma_val[0] = 0x0a;
590 gamma_val[1] = 0x13 + (value * (0xcb - 0x13) / 0xb8);
591 gamma_val[2] = 0x25 + (value * (0xee - 0x25) / 0xb8);
592 gamma_val[3] = 0x37 + (value * (0xfa - 0x37) / 0xb8);
593 gamma_val[4] = 0x45 + (value * (0xfc - 0x45) / 0xb8);
594 gamma_val[5] = 0x55 + (value * (0xfb - 0x55) / 0xb8);
595 gamma_val[6] = 0x65 + (value * (0xfc - 0x65) / 0xb8);
596 gamma_val[7] = 0x74 + (value * (0xfd - 0x74) / 0xb8);
597 gamma_val[8] = 0x83 + (value * (0xfe - 0x83) / 0xb8);
598 gamma_val[9] = 0x92 + (value * (0xfc - 0x92) / 0xb8);
599 gamma_val[10] = 0xa1 + (value * (0xfc - 0xa1) / 0xb8);
600 gamma_val[11] = 0xb0 + (value * (0xfc - 0xb0) / 0xb8);
601 gamma_val[12] = 0xbf + (value * (0xfb - 0xbf) / 0xb8);
602 gamma_val[13] = 0xce + (value * (0xfb - 0xce) / 0xb8);
603 gamma_val[14] = 0xdf + (value * (0xfd - 0xdf) / 0xb8);
604 gamma_val[15] = 0xea + (value * (0xf9 - 0xea) / 0xb8);
605 gamma_val[16] = 0xf5;
607 r = usb_microdia_control_write(dev, 0x1190, gamma_val, 17);
609 return r;
613 * @brief Set sharpness inside sn9c20x chip
615 * @author Comer352l
617 * @param dev Pointer to the device
619 * @return Zero (success) or negative (USB-error value)
622 int sn9c20x_set_sharpness(struct usb_microdia *dev)
624 __u8 val[1];
625 int ret;
627 ret = usb_microdia_control_read(dev, SN9C20X_SHARPNESS, val, 1);
628 if (ret < 0)
629 return ret;
630 val[0] = (val[0] & 0xc0) | (dev->vsettings.sharpness & 0x3f);
631 ret = usb_microdia_control_write(dev, SN9C20X_SHARPNESS, val, 1);
632 if (ret < 0)
633 return ret;
634 else
635 return 0;
639 * @brief Set colour gain inside sn9c20x chip
641 * @author Brian Johnson
643 * @param dev Pointer to the device
645 * @return Zero (success) or negative (USB-error value)
648 int sn9c20x_set_rgb_gain(struct usb_microdia *dev)
650 __u8 val[4];
651 int ret;
653 memcpy(&val, &(dev->vsettings.rgb_gain), 4);
654 ret = usb_microdia_control_write(dev, SN9C20X_RED_GAIN, val, 4);
655 if (ret < 0)
656 return ret;
657 else
658 return 0;
662 * @brief Calculate closest resolution to input from application
664 * @author Brian Johnson
666 * @param dev Pointer to the device structure
667 * @param width Requested width of video stream
668 * @param height Requested height of video stream
670 * @retval width Closest possible width of video stream
671 * @retval height Closest possible height of video stream
673 * @return Number of the
676 int sn9c20x_get_closest_resolution(struct usb_microdia *dev,
677 int *width, int *height)
679 int i;
681 for (i = dev->camera.nmodes - 1; i >= 0; i--) {
682 if (*width >= dev->camera.modes[i].width
683 && *height >= dev->camera.modes[i].height)
684 break;
687 *width = dev->camera.modes[i].width;
688 *height = dev->camera.modes[i].height;
690 return i;
694 * @brief Set resolution inside sn9c20x chip
696 * @author Brian Johnson
698 * @param dev Pointer to the device
699 * @param width Width
700 * @param height Height
702 * @return 0
705 int sn9c20x_set_resolution(struct usb_microdia *dev,
706 int width, int height)
708 int ret;
709 __u8 scale;
710 __u8 window[6];
711 __u8 clrwindow[6];
712 struct microdia_video_resolution *mode;
714 ret = sn9c20x_get_closest_resolution(dev, &width, &height);
716 mode = &dev->camera.modes[ret];
718 dev->vsettings.format.width = mode->width;
719 dev->vsettings.format.height = mode->height;
721 clrwindow[0] = 0; clrwindow[1] = mode->width >> 2;
722 clrwindow[2] = 0; clrwindow[3] = mode->height >> 1;
723 clrwindow[4] = ((mode->width >> 10) & 0x01) |
724 ((mode->height >> 10) & 0x06);
726 scale = mode->scale;
727 if (clrwindow[4] & 0x01)
728 scale += 0x40;
730 window[0] = mode->window[0] & 0xff; window[1] = mode->window[0] >> 8;
731 window[2] = mode->window[1] & 0xff; window[3] = mode->window[1] >> 8;
732 window[4] = mode->window[2] >> 4; window[5] = mode->window[3] >> 3;
734 usb_microdia_control_write(dev, 0x10fb, clrwindow, 5);
735 usb_microdia_control_write(dev, 0x1180, window, 6);
736 usb_microdia_control_write(dev, SN9C20X_SCALE, &scale, 1);
738 UDIA_DEBUG("Set mode [%dx%d]\n", mode->width, mode->height);
740 return 0;
743 int sn9c20x_set_raw(struct usb_microdia *dev)
745 __u8 value = 0x2d;
746 usb_microdia_control_write(dev, 0x10e0, &value, 1);
747 return 0;
750 int sn9c20x_set_jpeg(struct usb_microdia *dev)
752 __u8 value = 0x2c;
753 usb_microdia_control_write(dev, 0x10e0, &value, 1);
754 return 0;
758 * @brief Set exposure inside sn9c20x chip
760 * @param dev
762 * @returns 0 or negative error value
764 * @author GWater
766 int sn9c20x_set_exposure(struct usb_microdia *dev)
768 __u8 buf;
769 int ret;
770 int exposure = dev->vsettings.exposure;
772 buf = (__u8) (exposure * 0x00ff / 0xffff) & 0x00ff;
774 /* exposure can't be 0 - below 0x04 the image freezes */
775 if (buf < 0x05)
776 buf = 0x05;
778 /* write new value to register 0x118a */
779 ret = usb_microdia_control_write(dev, 0x118a, &buf, 1);
780 if (ret < 0) {
781 UDIA_ERROR("Error: setting exposure failed: "
782 "error while writing to register 0x118a\n");
783 return ret;
786 return 0;