1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * Copyright (C) 2010 Jean-Francois Moine (http://moinejf.free.fr)
7 *Notes: * t613 + tas5130A
8 * * Focus to light do not balance well as in win.
9 * Quality in win is not good, but its kinda better.
10 * * Fix some "extraneous bytes", most of apps will show the image anyway
11 * * Gamma table, is there, but its really doing something?
12 * * 7~8 Fps, its ok, max on win its 10.
16 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18 #define MODULE_NAME "t613"
20 #include <linux/input.h>
21 #include <linux/slab.h>
24 MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>");
25 MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver");
26 MODULE_LICENSE("GPL");
29 struct gspca_dev gspca_dev
; /* !! must be the first item */
30 struct v4l2_ctrl
*freq
;
31 struct { /* awb / color gains control cluster */
32 struct v4l2_ctrl
*awb
;
33 struct v4l2_ctrl
*gain
;
34 struct v4l2_ctrl
*red_balance
;
35 struct v4l2_ctrl
*blue_balance
;
45 SENSOR_LT168G
, /* must verify if this is the actual model */
48 static const struct v4l2_pix_format vga_mode_t16
[] = {
49 {160, 120, V4L2_PIX_FMT_JPEG
, V4L2_FIELD_NONE
,
51 .sizeimage
= 160 * 120 * 4 / 8 + 590,
52 .colorspace
= V4L2_COLORSPACE_JPEG
,
54 #if 0 /* HDG: broken with my test cam, so lets disable it */
55 {176, 144, V4L2_PIX_FMT_JPEG
, V4L2_FIELD_NONE
,
57 .sizeimage
= 176 * 144 * 3 / 8 + 590,
58 .colorspace
= V4L2_COLORSPACE_JPEG
,
61 {320, 240, V4L2_PIX_FMT_JPEG
, V4L2_FIELD_NONE
,
63 .sizeimage
= 320 * 240 * 3 / 8 + 590,
64 .colorspace
= V4L2_COLORSPACE_JPEG
,
66 #if 0 /* HDG: broken with my test cam, so lets disable it */
67 {352, 288, V4L2_PIX_FMT_JPEG
, V4L2_FIELD_NONE
,
69 .sizeimage
= 352 * 288 * 3 / 8 + 590,
70 .colorspace
= V4L2_COLORSPACE_JPEG
,
73 {640, 480, V4L2_PIX_FMT_JPEG
, V4L2_FIELD_NONE
,
75 .sizeimage
= 640 * 480 * 3 / 8 + 590,
76 .colorspace
= V4L2_COLORSPACE_JPEG
,
80 /* sensor specific data */
81 struct additional_sensor_data
{
84 const u8 reg80
, reg8e
;
93 static const u8 n4_om6802
[] = {
94 0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,
95 0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,
96 0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,
97 0xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8,
98 0xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48,
99 0xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0,
100 0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
101 0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
102 0xac, 0x84, 0xad, 0x86, 0xaf, 0x46
104 static const u8 n4_other
[] = {
105 0x66, 0x00, 0x7f, 0x00, 0x80, 0xac, 0x81, 0x69,
106 0x84, 0x40, 0x85, 0x70, 0x86, 0x20, 0x8a, 0x68,
107 0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xff, 0x8e, 0xb8,
108 0x8f, 0x28, 0xa2, 0x60, 0xa5, 0x40, 0xa8, 0xa8,
109 0xac, 0x84, 0xad, 0x84, 0xae, 0x24, 0xaf, 0x56,
110 0xb0, 0x68, 0xb1, 0x00, 0xb2, 0x88, 0xbb, 0xc5,
111 0xbc, 0x4a, 0xbe, 0x36, 0xc2, 0x88, 0xc5, 0xc0,
112 0xc6, 0xda, 0xe9, 0x26, 0xeb, 0x00
114 static const u8 n4_tas5130a
[] = {
115 0x80, 0x3c, 0x81, 0x68, 0x83, 0xa0, 0x84, 0x20,
116 0x8a, 0x68, 0x8b, 0x58, 0x8c, 0x88, 0x8e, 0xb4,
117 0x8f, 0x24, 0xa1, 0xb1, 0xa2, 0x30, 0xa5, 0x10,
118 0xa6, 0x4a, 0xae, 0x03, 0xb1, 0x44, 0xb2, 0x08,
119 0xb7, 0x06, 0xb9, 0xe7, 0xbb, 0xc4, 0xbc, 0x4a,
120 0xbe, 0x36, 0xbf, 0xff, 0xc2, 0x88, 0xc5, 0xc8,
123 static const u8 n4_lt168g
[] = {
124 0x66, 0x01, 0x7f, 0x00, 0x80, 0x7c, 0x81, 0x28,
125 0x83, 0x44, 0x84, 0x20, 0x86, 0x20, 0x8a, 0x70,
126 0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xa0, 0x8e, 0xb3,
127 0x8f, 0x24, 0xa1, 0xb0, 0xa2, 0x38, 0xa5, 0x20,
128 0xa6, 0x4a, 0xa8, 0xe8, 0xaf, 0x38, 0xb0, 0x68,
129 0xb1, 0x44, 0xb2, 0x88, 0xbb, 0x86, 0xbd, 0x40,
130 0xbe, 0x26, 0xc1, 0x05, 0xc2, 0x88, 0xc5, 0xc0,
131 0xda, 0x8e, 0xdb, 0xca, 0xdc, 0xa8, 0xdd, 0x8c,
132 0xde, 0x44, 0xdf, 0x0c, 0xe9, 0x80
135 static const struct additional_sensor_data sensor_data
[] = {
138 {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04},
140 .n4sz
= sizeof n4_om6802
,
143 .nset8
= {0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00},
145 {0xc2, 0x28, 0x0f, 0x22, 0xcd, 0x27, 0x2c, 0x06,
148 {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
151 {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
153 .data5
= /* this could be removed later */
154 {0x0c, 0x03, 0xab, 0x13, 0x81, 0x23},
156 {0x0b, 0x04, 0x0a, 0x78},
160 {0x61, 0xc2, 0x65, 0x88, 0x60, 0x00},
162 .n4sz
= sizeof n4_other
,
165 .nset8
= {0xa8, 0xa8, 0xc6, 0xda, 0xc0, 0x00},
167 {0xc1, 0x48, 0x04, 0x1b, 0xca, 0x2e, 0x33, 0x3a,
170 {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
173 {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
176 {0x0c, 0x03, 0xab, 0x29, 0x81, 0x69},
178 {0x0b, 0x04, 0x0a, 0x00},
180 [SENSOR_TAS5130A
] = {
182 {0x61, 0xc2, 0x65, 0x0d, 0x60, 0x08},
184 .n4sz
= sizeof n4_tas5130a
,
187 .nset8
= {0xa8, 0xf0, 0xc6, 0xda, 0xc0, 0x00},
189 {0xbb, 0x28, 0x10, 0x10, 0xbb, 0x28, 0x1e, 0x27,
192 {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
195 {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
198 {0x0c, 0x03, 0xab, 0x10, 0x81, 0x20},
200 {0x0b, 0x04, 0x0a, 0x40},
203 .n3
= {0x61, 0xc2, 0x65, 0x68, 0x60, 0x00},
205 .n4sz
= sizeof n4_lt168g
,
208 .nset8
= {0xa8, 0xf0, 0xc6, 0xba, 0xc0, 0x00},
209 .data1
= {0xc0, 0x38, 0x08, 0x10, 0xc0, 0x30, 0x10, 0x40,
211 .data2
= {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
213 .data3
= {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
215 .data5
= {0x0c, 0x03, 0xab, 0x4b, 0x81, 0x2b},
216 .stream
= {0x0b, 0x04, 0x0a, 0x28},
220 #define MAX_EFFECTS 7
221 static const u8 effects_table
[MAX_EFFECTS
][6] = {
222 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00}, /* Normal */
223 {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04}, /* Repujar */
224 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x20}, /* Monochrome */
225 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x80}, /* Sepia */
226 {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x02}, /* Croquis */
227 {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x10}, /* Sun Effect */
228 {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40}, /* Negative */
231 #define GAMMA_MAX (15)
232 static const u8 gamma_table
[GAMMA_MAX
+1][17] = {
233 /* gamma table from cam1690.ini */
234 {0x00, 0x00, 0x01, 0x04, 0x08, 0x0e, 0x16, 0x21, /* 0 */
235 0x2e, 0x3d, 0x50, 0x65, 0x7d, 0x99, 0xb8, 0xdb,
237 {0x00, 0x01, 0x03, 0x08, 0x0e, 0x16, 0x21, 0x2d, /* 1 */
238 0x3c, 0x4d, 0x60, 0x75, 0x8d, 0xa6, 0xc2, 0xe1,
240 {0x00, 0x01, 0x05, 0x0b, 0x12, 0x1c, 0x28, 0x35, /* 2 */
241 0x45, 0x56, 0x69, 0x7e, 0x95, 0xad, 0xc7, 0xe3,
243 {0x00, 0x02, 0x07, 0x0f, 0x18, 0x24, 0x30, 0x3f, /* 3 */
244 0x4f, 0x61, 0x73, 0x88, 0x9d, 0xb4, 0xcd, 0xe6,
246 {0x00, 0x04, 0x0b, 0x15, 0x20, 0x2d, 0x3b, 0x4a, /* 4 */
247 0x5b, 0x6c, 0x7f, 0x92, 0xa7, 0xbc, 0xd2, 0xe9,
249 {0x00, 0x07, 0x11, 0x15, 0x20, 0x2d, 0x48, 0x58, /* 5 */
250 0x68, 0x79, 0x8b, 0x9d, 0xb0, 0xc4, 0xd7, 0xec,
252 {0x00, 0x0c, 0x1a, 0x29, 0x38, 0x47, 0x57, 0x67, /* 6 */
253 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
255 {0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, /* 7 */
256 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
258 {0x00, 0x15, 0x27, 0x38, 0x49, 0x59, 0x69, 0x79, /* 8 */
259 0x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe2, 0xf0,
261 {0x00, 0x1c, 0x30, 0x43, 0x54, 0x65, 0x75, 0x84, /* 9 */
262 0x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd8, 0xe5, 0xf2,
264 {0x00, 0x24, 0x3b, 0x4f, 0x60, 0x70, 0x80, 0x8e, /* 10 */
265 0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xdc, 0xe8, 0xf3,
267 {0x00, 0x2a, 0x3c, 0x5d, 0x6e, 0x7e, 0x8d, 0x9b, /* 11 */
268 0xa8, 0xb4, 0xc0, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
270 {0x00, 0x3f, 0x5a, 0x6e, 0x7f, 0x8e, 0x9c, 0xa8, /* 12 */
271 0xb4, 0xbf, 0xc9, 0xd3, 0xdc, 0xe5, 0xee, 0xf6,
273 {0x00, 0x54, 0x6f, 0x83, 0x93, 0xa0, 0xad, 0xb7, /* 13 */
274 0xc2, 0xcb, 0xd4, 0xdc, 0xe4, 0xeb, 0xf2, 0xf9,
276 {0x00, 0x6e, 0x88, 0x9a, 0xa8, 0xb3, 0xbd, 0xc6, /* 14 */
277 0xcf, 0xd6, 0xdd, 0xe3, 0xe9, 0xef, 0xf4, 0xfa,
279 {0x00, 0x93, 0xa8, 0xb7, 0xc1, 0xca, 0xd2, 0xd8, /* 15 */
280 0xde, 0xe3, 0xe8, 0xed, 0xf1, 0xf5, 0xf8, 0xfc,
284 static const u8 tas5130a_sensor_init
[][8] = {
285 {0x62, 0x08, 0x63, 0x70, 0x64, 0x1d, 0x60, 0x09},
286 {0x62, 0x20, 0x63, 0x01, 0x64, 0x02, 0x60, 0x09},
287 {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
290 static u8 sensor_reset
[] = {0x61, 0x68, 0x62, 0xff, 0x60, 0x07};
293 static u8
reg_r(struct gspca_dev
*gspca_dev
,
296 usb_control_msg(gspca_dev
->dev
,
297 usb_rcvctrlpipe(gspca_dev
->dev
, 0),
299 USB_DIR_IN
| USB_TYPE_VENDOR
| USB_RECIP_DEVICE
,
302 gspca_dev
->usb_buf
, 1, 500);
303 return gspca_dev
->usb_buf
[0];
306 static void reg_w(struct gspca_dev
*gspca_dev
,
309 usb_control_msg(gspca_dev
->dev
,
310 usb_sndctrlpipe(gspca_dev
->dev
, 0),
312 USB_DIR_OUT
| USB_TYPE_VENDOR
| USB_RECIP_DEVICE
,
317 static void reg_w_buf(struct gspca_dev
*gspca_dev
,
318 const u8
*buffer
, u16 len
)
320 if (len
<= USB_BUF_SZ
) {
321 memcpy(gspca_dev
->usb_buf
, buffer
, len
);
322 usb_control_msg(gspca_dev
->dev
,
323 usb_sndctrlpipe(gspca_dev
->dev
, 0),
325 USB_DIR_OUT
| USB_TYPE_VENDOR
| USB_RECIP_DEVICE
,
327 gspca_dev
->usb_buf
, len
, 500);
331 tmpbuf
= kmemdup(buffer
, len
, GFP_KERNEL
);
333 pr_err("Out of memory\n");
336 usb_control_msg(gspca_dev
->dev
,
337 usb_sndctrlpipe(gspca_dev
->dev
, 0),
339 USB_DIR_OUT
| USB_TYPE_VENDOR
| USB_RECIP_DEVICE
,
346 /* write values to consecutive registers */
347 static void reg_w_ixbuf(struct gspca_dev
*gspca_dev
,
349 const u8
*buffer
, u16 len
)
354 if (len
* 2 <= USB_BUF_SZ
) {
355 p
= tmpbuf
= gspca_dev
->usb_buf
;
357 p
= tmpbuf
= kmalloc_array(len
, 2, GFP_KERNEL
);
359 pr_err("Out of memory\n");
368 usb_control_msg(gspca_dev
->dev
,
369 usb_sndctrlpipe(gspca_dev
->dev
, 0),
371 USB_DIR_OUT
| USB_TYPE_VENDOR
| USB_RECIP_DEVICE
,
373 tmpbuf
, len
* 2, 500);
374 if (len
* 2 > USB_BUF_SZ
)
378 static void om6802_sensor_init(struct gspca_dev
*gspca_dev
)
383 u8 val
[6] = {0x62, 0, 0x64, 0, 0x60, 0x05};
384 static const u8 sensor_init
[] = {
402 reg_w_buf(gspca_dev
, sensor_reset
, sizeof sensor_reset
);
406 byte
= reg_r(gspca_dev
, 0x0060);
411 byte
= reg_r(gspca_dev
, 0x0063);
413 pr_err("Bad sensor reset %02x\n", byte
);
422 reg_w(gspca_dev
, 0x3c80);
423 reg_w_buf(gspca_dev
, val
, sizeof val
);
427 byte
= reg_r(gspca_dev
, 0x60);
433 reg_w(gspca_dev
, 0x3c80);
436 /* this function is called at probe time */
437 static int sd_config(struct gspca_dev
*gspca_dev
,
438 const struct usb_device_id
*id
)
440 struct cam
*cam
= &gspca_dev
->cam
;
442 cam
->cam_mode
= vga_mode_t16
;
443 cam
->nmodes
= ARRAY_SIZE(vga_mode_t16
);
448 static void setbrightness(struct gspca_dev
*gspca_dev
, s32 brightness
)
450 u8 set6
[4] = { 0x8f, 0x24, 0xc3, 0x00 };
452 if (brightness
< 7) {
454 set6
[3] = 0x70 - brightness
* 0x10;
456 set6
[3] = 0x00 + ((brightness
- 7) * 0x10);
459 reg_w_buf(gspca_dev
, set6
, sizeof set6
);
462 static void setcontrast(struct gspca_dev
*gspca_dev
, s32 contrast
)
467 reg_to_write
= 0x8ea9 - contrast
* 0x200;
469 reg_to_write
= 0x00a9 + (contrast
- 7) * 0x200;
471 reg_w(gspca_dev
, reg_to_write
);
474 static void setcolors(struct gspca_dev
*gspca_dev
, s32 val
)
478 reg_to_write
= 0x80bb + val
* 0x100; /* was 0xc0 */
479 reg_w(gspca_dev
, reg_to_write
);
482 static void setgamma(struct gspca_dev
*gspca_dev
, s32 val
)
484 gspca_dbg(gspca_dev
, D_CONF
, "Gamma: %d\n", val
);
485 reg_w_ixbuf(gspca_dev
, 0x90,
486 gamma_table
[val
], sizeof gamma_table
[0]);
489 static void setawb_n_RGB(struct gspca_dev
*gspca_dev
)
491 struct sd
*sd
= (struct sd
*) gspca_dev
;
492 u8 all_gain_reg
[8] = {
493 0x87, 0x00, 0x88, 0x00, 0x89, 0x00, 0x80, 0x00 };
494 s32 red_gain
, blue_gain
, green_gain
;
496 green_gain
= sd
->gain
->val
;
498 red_gain
= green_gain
+ sd
->red_balance
->val
;
501 else if (red_gain
< 0x10)
504 blue_gain
= green_gain
+ sd
->blue_balance
->val
;
505 if (blue_gain
> 0x40)
507 else if (blue_gain
< 0x10)
510 all_gain_reg
[1] = red_gain
;
511 all_gain_reg
[3] = blue_gain
;
512 all_gain_reg
[5] = green_gain
;
513 all_gain_reg
[7] = sensor_data
[sd
->sensor
].reg80
;
515 all_gain_reg
[7] &= ~0x04; /* AWB off */
517 reg_w_buf(gspca_dev
, all_gain_reg
, sizeof all_gain_reg
);
520 static void setsharpness(struct gspca_dev
*gspca_dev
, s32 val
)
524 reg_to_write
= 0x0aa6 + 0x1000 * val
;
526 reg_w(gspca_dev
, reg_to_write
);
529 static void setfreq(struct gspca_dev
*gspca_dev
, s32 val
)
531 struct sd
*sd
= (struct sd
*) gspca_dev
;
533 u8 freq
[4] = { 0x66, 0x00, 0xa8, 0xe8 };
535 switch (sd
->sensor
) {
549 case 0: /* no flicker */
558 reg_w_buf(gspca_dev
, freq
, sizeof freq
);
561 /* this function is called at probe and resume time */
562 static int sd_init(struct gspca_dev
*gspca_dev
)
564 /* some of this registers are not really needed, because
565 * they are overridden by setbrigthness, setcontrast, etc.,
566 * but won't hurt anyway, and can help someone with similar webcam
567 * to see the initial parameters.*/
568 struct sd
*sd
= (struct sd
*) gspca_dev
;
569 const struct additional_sensor_data
*sensor
;
574 static const u8 read_indexs
[] =
575 { 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
576 0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00 };
577 static const u8 n1
[] =
578 {0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
579 static const u8 n2
[] =
582 sensor_id
= (reg_r(gspca_dev
, 0x06) << 8)
583 | reg_r(gspca_dev
, 0x07);
584 switch (sensor_id
& 0xff0f) {
586 gspca_dbg(gspca_dev
, D_PROBE
, "sensor tas5130a\n");
587 sd
->sensor
= SENSOR_TAS5130A
;
590 gspca_dbg(gspca_dev
, D_PROBE
, "sensor lt168g\n");
591 sd
->sensor
= SENSOR_LT168G
;
594 gspca_dbg(gspca_dev
, D_PROBE
, "sensor 'other'\n");
595 sd
->sensor
= SENSOR_OTHER
;
598 gspca_dbg(gspca_dev
, D_PROBE
, "sensor om6802\n");
599 sd
->sensor
= SENSOR_OM6802
;
602 pr_err("unknown sensor %04x\n", sensor_id
);
606 if (sd
->sensor
== SENSOR_OM6802
) {
607 reg_w_buf(gspca_dev
, n1
, sizeof n1
);
610 reg_w_buf(gspca_dev
, sensor_reset
, sizeof sensor_reset
);
611 test_byte
= reg_r(gspca_dev
, 0x0063);
613 if (test_byte
== 0x17)
617 pr_err("Bad sensor reset %02x\n", test_byte
);
620 reg_w_buf(gspca_dev
, n2
, sizeof n2
);
624 while (read_indexs
[i
] != 0x00) {
625 test_byte
= reg_r(gspca_dev
, read_indexs
[i
]);
626 gspca_dbg(gspca_dev
, D_STREAM
, "Reg 0x%02x = 0x%02x\n",
627 read_indexs
[i
], test_byte
);
631 sensor
= &sensor_data
[sd
->sensor
];
632 reg_w_buf(gspca_dev
, sensor
->n3
, sizeof sensor
->n3
);
633 reg_w_buf(gspca_dev
, sensor
->n4
, sensor
->n4sz
);
635 if (sd
->sensor
== SENSOR_LT168G
) {
636 test_byte
= reg_r(gspca_dev
, 0x80);
637 gspca_dbg(gspca_dev
, D_STREAM
, "Reg 0x%02x = 0x%02x\n", 0x80,
639 reg_w(gspca_dev
, 0x6c80);
642 reg_w_ixbuf(gspca_dev
, 0xd0, sensor
->data1
, sizeof sensor
->data1
);
643 reg_w_ixbuf(gspca_dev
, 0xc7, sensor
->data2
, sizeof sensor
->data2
);
644 reg_w_ixbuf(gspca_dev
, 0xe0, sensor
->data3
, sizeof sensor
->data3
);
646 reg_w(gspca_dev
, (sensor
->reg80
<< 8) + 0x80);
647 reg_w(gspca_dev
, (sensor
->reg80
<< 8) + 0x80);
648 reg_w(gspca_dev
, (sensor
->reg8e
<< 8) + 0x8e);
649 reg_w(gspca_dev
, (0x20 << 8) + 0x87);
650 reg_w(gspca_dev
, (0x20 << 8) + 0x88);
651 reg_w(gspca_dev
, (0x20 << 8) + 0x89);
653 reg_w_buf(gspca_dev
, sensor
->data5
, sizeof sensor
->data5
);
654 reg_w_buf(gspca_dev
, sensor
->nset8
, sizeof sensor
->nset8
);
655 reg_w_buf(gspca_dev
, sensor
->stream
, sizeof sensor
->stream
);
657 if (sd
->sensor
== SENSOR_LT168G
) {
658 test_byte
= reg_r(gspca_dev
, 0x80);
659 gspca_dbg(gspca_dev
, D_STREAM
, "Reg 0x%02x = 0x%02x\n", 0x80,
661 reg_w(gspca_dev
, 0x6c80);
664 reg_w_ixbuf(gspca_dev
, 0xd0, sensor
->data1
, sizeof sensor
->data1
);
665 reg_w_ixbuf(gspca_dev
, 0xc7, sensor
->data2
, sizeof sensor
->data2
);
666 reg_w_ixbuf(gspca_dev
, 0xe0, sensor
->data3
, sizeof sensor
->data3
);
671 static void setmirror(struct gspca_dev
*gspca_dev
, s32 val
)
674 {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09};
679 reg_w_buf(gspca_dev
, hflipcmd
, sizeof hflipcmd
);
682 static void seteffect(struct gspca_dev
*gspca_dev
, s32 val
)
687 case V4L2_COLORFX_NONE
:
689 case V4L2_COLORFX_BW
:
692 case V4L2_COLORFX_SEPIA
:
695 case V4L2_COLORFX_SKETCH
:
698 case V4L2_COLORFX_NEGATIVE
:
705 reg_w_buf(gspca_dev
, effects_table
[idx
],
706 sizeof effects_table
[0]);
708 if (val
== V4L2_COLORFX_SKETCH
)
709 reg_w(gspca_dev
, 0x4aa6);
711 reg_w(gspca_dev
, 0xfaa6);
714 /* Is this really needed?
715 * i added some module parameters for test with some users */
716 static void poll_sensor(struct gspca_dev
*gspca_dev
)
718 static const u8 poll1
[] =
719 {0x67, 0x05, 0x68, 0x81, 0x69, 0x80, 0x6a, 0x82,
720 0x6b, 0x68, 0x6c, 0x69, 0x72, 0xd9, 0x73, 0x34,
721 0x74, 0x32, 0x75, 0x92, 0x76, 0x00, 0x09, 0x01,
723 static const u8 poll2
[] =
724 {0x67, 0x02, 0x68, 0x71, 0x69, 0x72, 0x72, 0xa9,
725 0x73, 0x02, 0x73, 0x02, 0x60, 0x14};
726 static const u8 noise03
[] = /* (some differences / ms-drv) */
727 {0xa6, 0x0a, 0xea, 0xcf, 0xbe, 0x26, 0xb1, 0x5f,
728 0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c,
729 0xc2, 0x80, 0xc3, 0x10};
731 gspca_dbg(gspca_dev
, D_STREAM
, "[Sensor requires polling]\n");
732 reg_w_buf(gspca_dev
, poll1
, sizeof poll1
);
733 reg_w_buf(gspca_dev
, poll2
, sizeof poll2
);
734 reg_w_buf(gspca_dev
, noise03
, sizeof noise03
);
737 static int sd_start(struct gspca_dev
*gspca_dev
)
739 struct sd
*sd
= (struct sd
*) gspca_dev
;
740 const struct additional_sensor_data
*sensor
;
742 u8 t2
[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
743 static const u8 t3
[] =
744 { 0x07, 0x00, 0x88, 0x02, 0x06, 0x00, 0xe7, 0x01 };
746 mode
= gspca_dev
->cam
.cam_mode
[gspca_dev
->curr_mode
].priv
;
748 case 0: /* 640x480 (0x00) */
750 case 1: /* 352x288 */
753 case 2: /* 320x240 */
756 case 3: /* 176x144 */
760 /* case 4: * 160x120 */
765 switch (sd
->sensor
) {
767 om6802_sensor_init(gspca_dev
);
769 case SENSOR_TAS5130A
:
772 reg_w_buf(gspca_dev
, tas5130a_sensor_init
[i
],
773 sizeof tas5130a_sensor_init
[0]);
774 if (i
>= ARRAY_SIZE(tas5130a_sensor_init
) - 1)
778 reg_w(gspca_dev
, 0x3c80);
779 /* just in case and to keep sync with logs (for mine) */
780 reg_w_buf(gspca_dev
, tas5130a_sensor_init
[i
],
781 sizeof tas5130a_sensor_init
[0]);
782 reg_w(gspca_dev
, 0x3c80);
785 sensor
= &sensor_data
[sd
->sensor
];
786 setfreq(gspca_dev
, v4l2_ctrl_g_ctrl(sd
->freq
));
787 reg_r(gspca_dev
, 0x0012);
788 reg_w_buf(gspca_dev
, t2
, sizeof t2
);
789 reg_w_ixbuf(gspca_dev
, 0xb3, t3
, sizeof t3
);
790 reg_w(gspca_dev
, 0x0013);
792 reg_w_buf(gspca_dev
, sensor
->stream
, sizeof sensor
->stream
);
793 reg_w_buf(gspca_dev
, sensor
->stream
, sizeof sensor
->stream
);
795 if (sd
->sensor
== SENSOR_OM6802
)
796 poll_sensor(gspca_dev
);
801 static void sd_stopN(struct gspca_dev
*gspca_dev
)
803 struct sd
*sd
= (struct sd
*) gspca_dev
;
805 reg_w_buf(gspca_dev
, sensor_data
[sd
->sensor
].stream
,
806 sizeof sensor_data
[sd
->sensor
].stream
);
807 reg_w_buf(gspca_dev
, sensor_data
[sd
->sensor
].stream
,
808 sizeof sensor_data
[sd
->sensor
].stream
);
809 if (sd
->sensor
== SENSOR_OM6802
) {
811 reg_w(gspca_dev
, 0x0309);
813 #if IS_ENABLED(CONFIG_INPUT)
814 /* If the last button state is pressed, release it now! */
815 if (sd
->button_pressed
) {
816 input_report_key(gspca_dev
->input_dev
, KEY_CAMERA
, 0);
817 input_sync(gspca_dev
->input_dev
);
818 sd
->button_pressed
= 0;
823 static void sd_pkt_scan(struct gspca_dev
*gspca_dev
,
824 u8
*data
, /* isoc packet */
825 int len
) /* iso packet length */
827 struct sd
*sd __maybe_unused
= (struct sd
*) gspca_dev
;
830 if (data
[0] == 0x5a) {
831 #if IS_ENABLED(CONFIG_INPUT)
833 u8 state
= (data
[20] & 0x80) ? 1 : 0;
834 if (sd
->button_pressed
!= state
) {
835 input_report_key(gspca_dev
->input_dev
,
837 input_sync(gspca_dev
->input_dev
);
838 sd
->button_pressed
= state
;
842 /* Control Packet, after this came the header again,
843 * but extra bytes came in the packet before this,
844 * sometimes an EOF arrives, sometimes not... */
849 if (data
[0] == 0xff && data
[1] == 0xd8)
850 pkt_type
= FIRST_PACKET
;
851 else if (data
[len
- 2] == 0xff && data
[len
- 1] == 0xd9)
852 pkt_type
= LAST_PACKET
;
854 pkt_type
= INTER_PACKET
;
855 gspca_frame_add(gspca_dev
, pkt_type
, data
, len
);
858 static int sd_g_volatile_ctrl(struct v4l2_ctrl
*ctrl
)
860 struct gspca_dev
*gspca_dev
=
861 container_of(ctrl
->handler
, struct gspca_dev
, ctrl_handler
);
862 struct sd
*sd
= (struct sd
*)gspca_dev
;
863 s32 red_gain
, blue_gain
, green_gain
;
865 gspca_dev
->usb_err
= 0;
868 case V4L2_CID_AUTO_WHITE_BALANCE
:
869 red_gain
= reg_r(gspca_dev
, 0x0087);
872 else if (red_gain
< 0x10)
875 blue_gain
= reg_r(gspca_dev
, 0x0088);
876 if (blue_gain
> 0x40)
878 else if (blue_gain
< 0x10)
881 green_gain
= reg_r(gspca_dev
, 0x0089);
882 if (green_gain
> 0x40)
884 else if (green_gain
< 0x10)
887 sd
->gain
->val
= green_gain
;
888 sd
->red_balance
->val
= red_gain
- green_gain
;
889 sd
->blue_balance
->val
= blue_gain
- green_gain
;
895 static int sd_s_ctrl(struct v4l2_ctrl
*ctrl
)
897 struct gspca_dev
*gspca_dev
=
898 container_of(ctrl
->handler
, struct gspca_dev
, ctrl_handler
);
900 gspca_dev
->usb_err
= 0;
902 if (!gspca_dev
->streaming
)
906 case V4L2_CID_BRIGHTNESS
:
907 setbrightness(gspca_dev
, ctrl
->val
);
909 case V4L2_CID_CONTRAST
:
910 setcontrast(gspca_dev
, ctrl
->val
);
912 case V4L2_CID_SATURATION
:
913 setcolors(gspca_dev
, ctrl
->val
);
916 setgamma(gspca_dev
, ctrl
->val
);
919 setmirror(gspca_dev
, ctrl
->val
);
921 case V4L2_CID_SHARPNESS
:
922 setsharpness(gspca_dev
, ctrl
->val
);
924 case V4L2_CID_POWER_LINE_FREQUENCY
:
925 setfreq(gspca_dev
, ctrl
->val
);
927 case V4L2_CID_BACKLIGHT_COMPENSATION
:
928 reg_w(gspca_dev
, ctrl
->val
? 0xf48e : 0xb48e);
930 case V4L2_CID_AUTO_WHITE_BALANCE
:
931 setawb_n_RGB(gspca_dev
);
933 case V4L2_CID_COLORFX
:
934 seteffect(gspca_dev
, ctrl
->val
);
937 return gspca_dev
->usb_err
;
940 static const struct v4l2_ctrl_ops sd_ctrl_ops
= {
941 .g_volatile_ctrl
= sd_g_volatile_ctrl
,
945 static int sd_init_controls(struct gspca_dev
*gspca_dev
)
947 struct sd
*sd
= (struct sd
*)gspca_dev
;
948 struct v4l2_ctrl_handler
*hdl
= &gspca_dev
->ctrl_handler
;
950 gspca_dev
->vdev
.ctrl_handler
= hdl
;
951 v4l2_ctrl_handler_init(hdl
, 12);
952 v4l2_ctrl_new_std(hdl
, &sd_ctrl_ops
,
953 V4L2_CID_BRIGHTNESS
, 0, 14, 1, 8);
954 v4l2_ctrl_new_std(hdl
, &sd_ctrl_ops
,
955 V4L2_CID_CONTRAST
, 0, 0x0d, 1, 7);
956 v4l2_ctrl_new_std(hdl
, &sd_ctrl_ops
,
957 V4L2_CID_SATURATION
, 0, 0xf, 1, 5);
958 v4l2_ctrl_new_std(hdl
, &sd_ctrl_ops
,
959 V4L2_CID_GAMMA
, 0, GAMMA_MAX
, 1, 10);
960 /* Activate lowlight, some apps don't bring up the
961 backlight_compensation control) */
962 v4l2_ctrl_new_std(hdl
, &sd_ctrl_ops
,
963 V4L2_CID_BACKLIGHT_COMPENSATION
, 0, 1, 1, 1);
964 if (sd
->sensor
== SENSOR_TAS5130A
)
965 v4l2_ctrl_new_std(hdl
, &sd_ctrl_ops
,
966 V4L2_CID_HFLIP
, 0, 1, 1, 0);
967 sd
->awb
= v4l2_ctrl_new_std(hdl
, &sd_ctrl_ops
,
968 V4L2_CID_AUTO_WHITE_BALANCE
, 0, 1, 1, 1);
969 sd
->gain
= v4l2_ctrl_new_std(hdl
, &sd_ctrl_ops
,
970 V4L2_CID_GAIN
, 0x10, 0x40, 1, 0x20);
971 sd
->blue_balance
= v4l2_ctrl_new_std(hdl
, &sd_ctrl_ops
,
972 V4L2_CID_BLUE_BALANCE
, -0x30, 0x30, 1, 0);
973 sd
->red_balance
= v4l2_ctrl_new_std(hdl
, &sd_ctrl_ops
,
974 V4L2_CID_RED_BALANCE
, -0x30, 0x30, 1, 0);
975 v4l2_ctrl_new_std(hdl
, &sd_ctrl_ops
,
976 V4L2_CID_SHARPNESS
, 0, 15, 1, 6);
977 v4l2_ctrl_new_std_menu(hdl
, &sd_ctrl_ops
,
978 V4L2_CID_COLORFX
, V4L2_COLORFX_SKETCH
,
979 ~((1 << V4L2_COLORFX_NONE
) |
980 (1 << V4L2_COLORFX_BW
) |
981 (1 << V4L2_COLORFX_SEPIA
) |
982 (1 << V4L2_COLORFX_SKETCH
) |
983 (1 << V4L2_COLORFX_NEGATIVE
)),
985 sd
->freq
= v4l2_ctrl_new_std_menu(hdl
, &sd_ctrl_ops
,
986 V4L2_CID_POWER_LINE_FREQUENCY
,
987 V4L2_CID_POWER_LINE_FREQUENCY_60HZ
, 1,
988 V4L2_CID_POWER_LINE_FREQUENCY_50HZ
);
991 pr_err("Could not initialize controls\n");
995 v4l2_ctrl_auto_cluster(4, &sd
->awb
, 0, true);
1000 /* sub-driver description */
1001 static const struct sd_desc sd_desc
= {
1002 .name
= MODULE_NAME
,
1003 .config
= sd_config
,
1005 .init_controls
= sd_init_controls
,
1008 .pkt_scan
= sd_pkt_scan
,
1009 #if IS_ENABLED(CONFIG_INPUT)
1014 /* -- module initialisation -- */
1015 static const struct usb_device_id device_table
[] = {
1016 {USB_DEVICE(0x17a1, 0x0128)},
1019 MODULE_DEVICE_TABLE(usb
, device_table
);
1021 /* -- device connect -- */
1022 static int sd_probe(struct usb_interface
*intf
,
1023 const struct usb_device_id
*id
)
1025 return gspca_dev_probe(intf
, id
, &sd_desc
, sizeof(struct sd
),
1029 static struct usb_driver sd_driver
= {
1030 .name
= MODULE_NAME
,
1031 .id_table
= device_table
,
1033 .disconnect
= gspca_disconnect
,
1035 .suspend
= gspca_suspend
,
1036 .resume
= gspca_resume
,
1037 .reset_resume
= gspca_resume
,
1041 module_usb_driver(sd_driver
);