blob: 42667710af92279dba54b777b9aa4827237f9340 [file] [log] [blame]
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001/*
Jean-François Moinecd8955b2010-06-04 07:22:57 -03002 * T613 subdriver
3 *
4 * Copyright (C) 2010 Jean-Francois Moine (http://moinejf.free.fr)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
Jean-Francois Moine10b0e962008-07-22 05:35:10 -030016 *Notes: * t613 + tas5130A
17 * * Focus to light do not balance well as in win.
18 * Quality in win is not good, but its kinda better.
19 * * Fix some "extraneous bytes", most of apps will show the image anyway
20 * * Gamma table, is there, but its really doing something?
21 * * 7~8 Fps, its ok, max on win its 10.
22 * Costantino Leandro
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030023 */
24
Joe Perches1b19e4292011-08-21 19:56:56 -030025#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
26
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030027#define MODULE_NAME "t613"
Jean-Francois Moine10b0e962008-07-22 05:35:10 -030028
Hans de Goedeee186fd2012-01-01 16:09:17 -030029#include <linux/input.h>
Jean-François Moinebe2a9fa2010-06-04 06:42:32 -030030#include <linux/slab.h>
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030031#include "gspca.h"
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030032
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030033MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>");
34MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver");
35MODULE_LICENSE("GPL");
36
37struct sd {
38 struct gspca_dev gspca_dev; /* !! must be the first item */
Hans Verkuil9bf81642012-05-18 03:41:58 -030039 struct v4l2_ctrl *freq;
40 struct { /* awb / color gains control cluster */
41 struct v4l2_ctrl *awb;
42 struct v4l2_ctrl *gain;
43 struct v4l2_ctrl *red_balance;
44 struct v4l2_ctrl *blue_balance;
45 };
Jean-Francois Moinefadc7992008-10-08 08:06:08 -030046
Jean-Francois Moine82e25492009-01-22 07:18:48 -030047 u8 sensor;
Hans de Goedeee186fd2012-01-01 16:09:17 -030048 u8 button_pressed;
Jean-François Moine11ce8842010-07-26 06:39:40 -030049};
50enum sensors {
Jean-François Moinecd8955b2010-06-04 07:22:57 -030051 SENSOR_OM6802,
52 SENSOR_OTHER,
53 SENSOR_TAS5130A,
54 SENSOR_LT168G, /* must verify if this is the actual model */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030055};
56
Jean-Francois Moinecc611b82008-12-29 07:49:41 -030057static const struct v4l2_pix_format vga_mode_t16[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -030058 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
59 .bytesperline = 160,
Jean-Francois Moine5d052942008-09-03 16:48:09 -030060 .sizeimage = 160 * 120 * 4 / 8 + 590,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -030061 .colorspace = V4L2_COLORSPACE_JPEG,
62 .priv = 4},
Hans de Goede1ea172d2012-07-07 08:55:06 -030063#if 0 /* HDG: broken with my test cam, so lets disable it */
Jean-Francois Moinec2446b32008-07-05 11:49:20 -030064 {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
65 .bytesperline = 176,
66 .sizeimage = 176 * 144 * 3 / 8 + 590,
67 .colorspace = V4L2_COLORSPACE_JPEG,
68 .priv = 3},
Hans de Goede1ea172d2012-07-07 08:55:06 -030069#endif
Jean-Francois Moinec2446b32008-07-05 11:49:20 -030070 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
71 .bytesperline = 320,
72 .sizeimage = 320 * 240 * 3 / 8 + 590,
73 .colorspace = V4L2_COLORSPACE_JPEG,
74 .priv = 2},
Hans de Goede1ea172d2012-07-07 08:55:06 -030075#if 0 /* HDG: broken with my test cam, so lets disable it */
Jean-Francois Moinec2446b32008-07-05 11:49:20 -030076 {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
77 .bytesperline = 352,
78 .sizeimage = 352 * 288 * 3 / 8 + 590,
79 .colorspace = V4L2_COLORSPACE_JPEG,
80 .priv = 1},
Hans de Goede1ea172d2012-07-07 08:55:06 -030081#endif
Jean-Francois Moinec2446b32008-07-05 11:49:20 -030082 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
83 .bytesperline = 640,
84 .sizeimage = 640 * 480 * 3 / 8 + 590,
85 .colorspace = V4L2_COLORSPACE_JPEG,
86 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030087};
88
Leandro Costantinoad62fb02008-10-17 05:27:04 -030089/* sensor specific data */
90struct additional_sensor_data {
Jean-Francois Moine78a6d742009-07-07 04:03:24 -030091 const u8 n3[6];
92 const u8 *n4, n4sz;
93 const u8 reg80, reg8e;
94 const u8 nset8[6];
Jean-Francois Moine82e25492009-01-22 07:18:48 -030095 const u8 data1[10];
96 const u8 data2[9];
97 const u8 data3[9];
Jean-Francois Moine82e25492009-01-22 07:18:48 -030098 const u8 data5[6];
99 const u8 stream[4];
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300100};
101
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300102static const u8 n4_om6802[] = {
103 0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,
104 0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,
105 0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,
106 0xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8,
107 0xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48,
108 0xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0,
109 0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
110 0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
111 0xac, 0x84, 0xad, 0x86, 0xaf, 0x46
112};
113static const u8 n4_other[] = {
114 0x66, 0x00, 0x7f, 0x00, 0x80, 0xac, 0x81, 0x69,
115 0x84, 0x40, 0x85, 0x70, 0x86, 0x20, 0x8a, 0x68,
116 0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xff, 0x8e, 0xb8,
117 0x8f, 0x28, 0xa2, 0x60, 0xa5, 0x40, 0xa8, 0xa8,
118 0xac, 0x84, 0xad, 0x84, 0xae, 0x24, 0xaf, 0x56,
119 0xb0, 0x68, 0xb1, 0x00, 0xb2, 0x88, 0xbb, 0xc5,
120 0xbc, 0x4a, 0xbe, 0x36, 0xc2, 0x88, 0xc5, 0xc0,
121 0xc6, 0xda, 0xe9, 0x26, 0xeb, 0x00
122};
123static const u8 n4_tas5130a[] = {
124 0x80, 0x3c, 0x81, 0x68, 0x83, 0xa0, 0x84, 0x20,
125 0x8a, 0x68, 0x8b, 0x58, 0x8c, 0x88, 0x8e, 0xb4,
126 0x8f, 0x24, 0xa1, 0xb1, 0xa2, 0x30, 0xa5, 0x10,
127 0xa6, 0x4a, 0xae, 0x03, 0xb1, 0x44, 0xb2, 0x08,
128 0xb7, 0x06, 0xb9, 0xe7, 0xbb, 0xc4, 0xbc, 0x4a,
129 0xbe, 0x36, 0xbf, 0xff, 0xc2, 0x88, 0xc5, 0xc8,
130 0xc6, 0xda
131};
Nicolau Werneck00e80062010-01-30 16:00:15 -0300132static const u8 n4_lt168g[] = {
133 0x66, 0x01, 0x7f, 0x00, 0x80, 0x7c, 0x81, 0x28,
134 0x83, 0x44, 0x84, 0x20, 0x86, 0x20, 0x8a, 0x70,
135 0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xa0, 0x8e, 0xb3,
136 0x8f, 0x24, 0xa1, 0xb0, 0xa2, 0x38, 0xa5, 0x20,
137 0xa6, 0x4a, 0xa8, 0xe8, 0xaf, 0x38, 0xb0, 0x68,
138 0xb1, 0x44, 0xb2, 0x88, 0xbb, 0x86, 0xbd, 0x40,
139 0xbe, 0x26, 0xc1, 0x05, 0xc2, 0x88, 0xc5, 0xc0,
140 0xda, 0x8e, 0xdb, 0xca, 0xdc, 0xa8, 0xdd, 0x8c,
141 0xde, 0x44, 0xdf, 0x0c, 0xe9, 0x80
142};
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300143
Tobias Klausere23b2902009-02-09 18:06:49 -0300144static const struct additional_sensor_data sensor_data[] = {
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300145[SENSOR_OM6802] = {
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300146 .n3 =
147 {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04},
148 .n4 = n4_om6802,
149 .n4sz = sizeof n4_om6802,
150 .reg80 = 0x3c,
151 .reg8e = 0x33,
152 .nset8 = {0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00},
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300153 .data1 =
154 {0xc2, 0x28, 0x0f, 0x22, 0xcd, 0x27, 0x2c, 0x06,
155 0xb3, 0xfc},
156 .data2 =
157 {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
158 0xff},
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300159 .data3 =
160 {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
161 0xff},
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300162 .data5 = /* this could be removed later */
163 {0x0c, 0x03, 0xab, 0x13, 0x81, 0x23},
164 .stream =
165 {0x0b, 0x04, 0x0a, 0x78},
166 },
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300167[SENSOR_OTHER] = {
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300168 .n3 =
169 {0x61, 0xc2, 0x65, 0x88, 0x60, 0x00},
170 .n4 = n4_other,
171 .n4sz = sizeof n4_other,
172 .reg80 = 0xac,
173 .reg8e = 0xb8,
174 .nset8 = {0xa8, 0xa8, 0xc6, 0xda, 0xc0, 0x00},
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300175 .data1 =
176 {0xc1, 0x48, 0x04, 0x1b, 0xca, 0x2e, 0x33, 0x3a,
177 0xe8, 0xfc},
178 .data2 =
179 {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
180 0xd9},
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300181 .data3 =
182 {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
183 0xd9},
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300184 .data5 =
185 {0x0c, 0x03, 0xab, 0x29, 0x81, 0x69},
186 .stream =
187 {0x0b, 0x04, 0x0a, 0x00},
188 },
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300189[SENSOR_TAS5130A] = {
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300190 .n3 =
191 {0x61, 0xc2, 0x65, 0x0d, 0x60, 0x08},
192 .n4 = n4_tas5130a,
193 .n4sz = sizeof n4_tas5130a,
194 .reg80 = 0x3c,
195 .reg8e = 0xb4,
196 .nset8 = {0xa8, 0xf0, 0xc6, 0xda, 0xc0, 0x00},
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300197 .data1 =
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300198 {0xbb, 0x28, 0x10, 0x10, 0xbb, 0x28, 0x1e, 0x27,
199 0xc8, 0xfc},
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300200 .data2 =
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300201 {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
202 0xe0},
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300203 .data3 =
204 {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
205 0xe0},
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300206 .data5 =
207 {0x0c, 0x03, 0xab, 0x10, 0x81, 0x20},
208 .stream =
209 {0x0b, 0x04, 0x0a, 0x40},
210 },
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300211[SENSOR_LT168G] = {
Nicolau Werneck00e80062010-01-30 16:00:15 -0300212 .n3 = {0x61, 0xc2, 0x65, 0x68, 0x60, 0x00},
213 .n4 = n4_lt168g,
214 .n4sz = sizeof n4_lt168g,
215 .reg80 = 0x7c,
216 .reg8e = 0xb3,
217 .nset8 = {0xa8, 0xf0, 0xc6, 0xba, 0xc0, 0x00},
218 .data1 = {0xc0, 0x38, 0x08, 0x10, 0xc0, 0x30, 0x10, 0x40,
219 0xb0, 0xf4},
220 .data2 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
221 0xff},
222 .data3 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
223 0xff},
Nicolau Werneck00e80062010-01-30 16:00:15 -0300224 .data5 = {0x0c, 0x03, 0xab, 0x4b, 0x81, 0x2b},
225 .stream = {0x0b, 0x04, 0x0a, 0x28},
226 },
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300227};
228
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300229#define MAX_EFFECTS 7
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300230static const u8 effects_table[MAX_EFFECTS][6] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300231 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00}, /* Normal */
232 {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04}, /* Repujar */
233 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x20}, /* Monochrome */
234 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x80}, /* Sepia */
235 {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x02}, /* Croquis */
236 {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x10}, /* Sun Effect */
237 {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40}, /* Negative */
238};
239
Hans Verkuil9bf81642012-05-18 03:41:58 -0300240#define GAMMA_MAX (15)
241static const u8 gamma_table[GAMMA_MAX+1][17] = {
Jean-François Moine79960d32010-06-04 07:24:53 -0300242/* gamma table from cam1690.ini */
243 {0x00, 0x00, 0x01, 0x04, 0x08, 0x0e, 0x16, 0x21, /* 0 */
244 0x2e, 0x3d, 0x50, 0x65, 0x7d, 0x99, 0xb8, 0xdb,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300245 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300246 {0x00, 0x01, 0x03, 0x08, 0x0e, 0x16, 0x21, 0x2d, /* 1 */
247 0x3c, 0x4d, 0x60, 0x75, 0x8d, 0xa6, 0xc2, 0xe1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300248 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300249 {0x00, 0x01, 0x05, 0x0b, 0x12, 0x1c, 0x28, 0x35, /* 2 */
250 0x45, 0x56, 0x69, 0x7e, 0x95, 0xad, 0xc7, 0xe3,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300251 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300252 {0x00, 0x02, 0x07, 0x0f, 0x18, 0x24, 0x30, 0x3f, /* 3 */
253 0x4f, 0x61, 0x73, 0x88, 0x9d, 0xb4, 0xcd, 0xe6,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300254 0xff},
Jean-François Moine1d00d6c2010-10-29 13:58:22 -0300255 {0x00, 0x04, 0x0b, 0x15, 0x20, 0x2d, 0x3b, 0x4a, /* 4 */
Jean-François Moine79960d32010-06-04 07:24:53 -0300256 0x5b, 0x6c, 0x7f, 0x92, 0xa7, 0xbc, 0xd2, 0xe9,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300257 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300258 {0x00, 0x07, 0x11, 0x15, 0x20, 0x2d, 0x48, 0x58, /* 5 */
259 0x68, 0x79, 0x8b, 0x9d, 0xb0, 0xc4, 0xd7, 0xec,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300260 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300261 {0x00, 0x0c, 0x1a, 0x29, 0x38, 0x47, 0x57, 0x67, /* 6 */
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300262 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
263 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300264 {0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, /* 7 */
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300265 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
266 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300267 {0x00, 0x15, 0x27, 0x38, 0x49, 0x59, 0x69, 0x79, /* 8 */
268 0x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe2, 0xf0,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300269 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300270 {0x00, 0x1c, 0x30, 0x43, 0x54, 0x65, 0x75, 0x84, /* 9 */
271 0x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd8, 0xe5, 0xf2,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300272 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300273 {0x00, 0x24, 0x3b, 0x4f, 0x60, 0x70, 0x80, 0x8e, /* 10 */
274 0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xdc, 0xe8, 0xf3,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300275 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300276 {0x00, 0x2a, 0x3c, 0x5d, 0x6e, 0x7e, 0x8d, 0x9b, /* 11 */
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300277 0xa8, 0xb4, 0xc0, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
278 0xff},
279 {0x00, 0x3f, 0x5a, 0x6e, 0x7f, 0x8e, 0x9c, 0xa8, /* 12 */
280 0xb4, 0xbf, 0xc9, 0xd3, 0xdc, 0xe5, 0xee, 0xf6,
281 0xff},
282 {0x00, 0x54, 0x6f, 0x83, 0x93, 0xa0, 0xad, 0xb7, /* 13 */
283 0xc2, 0xcb, 0xd4, 0xdc, 0xe4, 0xeb, 0xf2, 0xf9,
284 0xff},
285 {0x00, 0x6e, 0x88, 0x9a, 0xa8, 0xb3, 0xbd, 0xc6, /* 14 */
286 0xcf, 0xd6, 0xdd, 0xe3, 0xe9, 0xef, 0xf4, 0xfa,
287 0xff},
288 {0x00, 0x93, 0xa8, 0xb7, 0xc1, 0xca, 0xd2, 0xd8, /* 15 */
289 0xde, 0xe3, 0xe8, 0xed, 0xf1, 0xf5, 0xf8, 0xfc,
290 0xff}
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300291};
292
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300293static const u8 tas5130a_sensor_init[][8] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300294 {0x62, 0x08, 0x63, 0x70, 0x64, 0x1d, 0x60, 0x09},
295 {0x62, 0x20, 0x63, 0x01, 0x64, 0x02, 0x60, 0x09},
296 {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300297};
298
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300299static u8 sensor_reset[] = {0x61, 0x68, 0x62, 0xff, 0x60, 0x07};
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300300
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300301/* read 1 byte */
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300302static u8 reg_r(struct gspca_dev *gspca_dev,
303 u16 index)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300304{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300305 usb_control_msg(gspca_dev->dev,
306 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300307 0, /* request */
308 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
309 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300310 index,
311 gspca_dev->usb_buf, 1, 500);
312 return gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300313}
314
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300315static void reg_w(struct gspca_dev *gspca_dev,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300316 u16 index)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300317{
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300318 usb_control_msg(gspca_dev->dev,
319 usb_sndctrlpipe(gspca_dev->dev, 0),
320 0,
Jean-Francois Moine0bc99b52008-10-17 04:45:27 -0300321 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300322 0, index,
323 NULL, 0, 500);
324}
325
Jean-Francois Moinef89be032008-10-17 04:42:29 -0300326static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300327 const u8 *buffer, u16 len)
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300328{
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300329 if (len <= USB_BUF_SZ) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300330 memcpy(gspca_dev->usb_buf, buffer, len);
331 usb_control_msg(gspca_dev->dev,
332 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300333 0,
Jean-Francois Moine0bc99b52008-10-17 04:45:27 -0300334 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300335 0x01, 0,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300336 gspca_dev->usb_buf, len, 500);
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300337 } else {
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300338 u8 *tmpbuf;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300339
Julia Lawallfeda79b2010-07-01 01:30:11 -0300340 tmpbuf = kmemdup(buffer, len, GFP_KERNEL);
Jean-François Moine24f222e2010-03-07 05:58:55 -0300341 if (!tmpbuf) {
Joe Perches1b19e4292011-08-21 19:56:56 -0300342 pr_err("Out of memory\n");
Jean-François Moine24f222e2010-03-07 05:58:55 -0300343 return;
344 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300345 usb_control_msg(gspca_dev->dev,
346 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300347 0,
Jean-Francois Moine0bc99b52008-10-17 04:45:27 -0300348 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300349 0x01, 0,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300350 tmpbuf, len, 500);
351 kfree(tmpbuf);
352 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300353}
354
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300355/* write values to consecutive registers */
356static void reg_w_ixbuf(struct gspca_dev *gspca_dev,
357 u8 reg,
358 const u8 *buffer, u16 len)
359{
360 int i;
361 u8 *p, *tmpbuf;
362
Jean-François Moine24f222e2010-03-07 05:58:55 -0300363 if (len * 2 <= USB_BUF_SZ) {
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300364 p = tmpbuf = gspca_dev->usb_buf;
Jean-François Moine24f222e2010-03-07 05:58:55 -0300365 } else {
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300366 p = tmpbuf = kmalloc(len * 2, GFP_KERNEL);
Jean-François Moine24f222e2010-03-07 05:58:55 -0300367 if (!tmpbuf) {
Joe Perches1b19e4292011-08-21 19:56:56 -0300368 pr_err("Out of memory\n");
Jean-François Moine24f222e2010-03-07 05:58:55 -0300369 return;
370 }
371 }
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300372 i = len;
373 while (--i >= 0) {
374 *p++ = reg++;
375 *p++ = *buffer++;
376 }
377 usb_control_msg(gspca_dev->dev,
378 usb_sndctrlpipe(gspca_dev->dev, 0),
379 0,
380 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
381 0x01, 0,
382 tmpbuf, len * 2, 500);
383 if (len * 2 > USB_BUF_SZ)
384 kfree(tmpbuf);
385}
386
Jean-Francois Moine236088d2008-10-17 04:53:02 -0300387static void om6802_sensor_init(struct gspca_dev *gspca_dev)
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300388{
389 int i;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300390 const u8 *p;
391 u8 byte;
392 u8 val[6] = {0x62, 0, 0x64, 0, 0x60, 0x05};
393 static const u8 sensor_init[] = {
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300394 0xdf, 0x6d,
395 0xdd, 0x18,
396 0x5a, 0xe0,
397 0x5c, 0x07,
398 0x5d, 0xb0,
399 0x5e, 0x1e,
400 0x60, 0x71,
401 0xef, 0x00,
402 0xe9, 0x00,
403 0xea, 0x00,
404 0x90, 0x24,
405 0x91, 0xb2,
406 0x82, 0x32,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300407 0xfd, 0x41,
408 0x00 /* table end */
409 };
410
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300411 reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
Jean-Francois Moinee30bdc62009-03-22 16:31:32 -0300412 msleep(100);
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300413 i = 4;
Roel Kluin97a53a02008-12-21 11:58:05 -0300414 while (--i > 0) {
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300415 byte = reg_r(gspca_dev, 0x0060);
416 if (!(byte & 0x01))
417 break;
418 msleep(100);
419 }
420 byte = reg_r(gspca_dev, 0x0063);
421 if (byte != 0x17) {
Joe Perches1b19e4292011-08-21 19:56:56 -0300422 pr_err("Bad sensor reset %02x\n", byte);
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300423 /* continue? */
424 }
425
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300426 p = sensor_init;
427 while (*p != 0) {
428 val[1] = *p++;
429 val[3] = *p++;
430 if (*p == 0)
431 reg_w(gspca_dev, 0x3c80);
Jean-Francois Moinef89be032008-10-17 04:42:29 -0300432 reg_w_buf(gspca_dev, val, sizeof val);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300433 i = 4;
434 while (--i >= 0) {
435 msleep(15);
436 byte = reg_r(gspca_dev, 0x60);
437 if (!(byte & 0x01))
438 break;
439 }
440 }
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300441 msleep(15);
442 reg_w(gspca_dev, 0x3c80);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300443}
444
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300445/* this function is called at probe time */
446static int sd_config(struct gspca_dev *gspca_dev,
447 const struct usb_device_id *id)
448{
Hans Verkuil9bf81642012-05-18 03:41:58 -0300449 struct cam *cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300450
451 cam->cam_mode = vga_mode_t16;
452 cam->nmodes = ARRAY_SIZE(vga_mode_t16);
453
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300454 return 0;
455}
456
Hans Verkuil9bf81642012-05-18 03:41:58 -0300457static void setbrightness(struct gspca_dev *gspca_dev, s32 brightness)
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300458{
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300459 u8 set6[4] = { 0x8f, 0x24, 0xc3, 0x00 };
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300460
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300461 if (brightness < 7) {
462 set6[1] = 0x26;
463 set6[3] = 0x70 - brightness * 0x10;
464 } else {
465 set6[3] = 0x00 + ((brightness - 7) * 0x10);
466 }
467
468 reg_w_buf(gspca_dev, set6, sizeof set6);
469}
470
Hans Verkuil9bf81642012-05-18 03:41:58 -0300471static void setcontrast(struct gspca_dev *gspca_dev, s32 contrast)
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300472{
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300473 u16 reg_to_write;
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300474
475 if (contrast < 7)
476 reg_to_write = 0x8ea9 - contrast * 0x200;
477 else
478 reg_to_write = 0x00a9 + (contrast - 7) * 0x200;
479
480 reg_w(gspca_dev, reg_to_write);
481}
482
Hans Verkuil9bf81642012-05-18 03:41:58 -0300483static void setcolors(struct gspca_dev *gspca_dev, s32 val)
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300484{
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300485 u16 reg_to_write;
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300486
Hans Verkuil9bf81642012-05-18 03:41:58 -0300487 reg_to_write = 0x80bb + val * 0x100; /* was 0xc0 */
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300488 reg_w(gspca_dev, reg_to_write);
489}
490
Hans Verkuil9bf81642012-05-18 03:41:58 -0300491static void setgamma(struct gspca_dev *gspca_dev, s32 val)
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300492{
Hans de Goede8547fd12012-12-21 11:01:48 -0300493 PDEBUG(D_CONF, "Gamma: %d", val);
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300494 reg_w_ixbuf(gspca_dev, 0x90,
Hans Verkuil9bf81642012-05-18 03:41:58 -0300495 gamma_table[val], sizeof gamma_table[0]);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300496}
497
Hans Verkuil9bf81642012-05-18 03:41:58 -0300498static void setawb_n_RGB(struct gspca_dev *gspca_dev)
Jean-François Moinee9b15652010-06-05 07:07:56 -0300499{
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300500 struct sd *sd = (struct sd *) gspca_dev;
Hans Verkuil9bf81642012-05-18 03:41:58 -0300501 u8 all_gain_reg[8] = {
502 0x87, 0x00, 0x88, 0x00, 0x89, 0x00, 0x80, 0x00 };
503 s32 red_gain, blue_gain, green_gain;
Jean-François Moinee9b15652010-06-05 07:07:56 -0300504
Hans Verkuil9bf81642012-05-18 03:41:58 -0300505 green_gain = sd->gain->val;
506
507 red_gain = green_gain + sd->red_balance->val;
508 if (red_gain > 0x40)
509 red_gain = 0x40;
510 else if (red_gain < 0x10)
511 red_gain = 0x10;
512
513 blue_gain = green_gain + sd->blue_balance->val;
514 if (blue_gain > 0x40)
515 blue_gain = 0x40;
516 else if (blue_gain < 0x10)
517 blue_gain = 0x10;
518
519 all_gain_reg[1] = red_gain;
520 all_gain_reg[3] = blue_gain;
521 all_gain_reg[5] = green_gain;
522 all_gain_reg[7] = sensor_data[sd->sensor].reg80;
523 if (!sd->awb->val)
524 all_gain_reg[7] &= ~0x04; /* AWB off */
525
Jean-François Moinee9b15652010-06-05 07:07:56 -0300526 reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg);
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300527}
528
Hans Verkuil9bf81642012-05-18 03:41:58 -0300529static void setsharpness(struct gspca_dev *gspca_dev, s32 val)
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300530{
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300531 u16 reg_to_write;
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300532
Hans Verkuil9bf81642012-05-18 03:41:58 -0300533 reg_to_write = 0x0aa6 + 0x1000 * val;
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300534
535 reg_w(gspca_dev, reg_to_write);
536}
537
Hans Verkuil9bf81642012-05-18 03:41:58 -0300538static void setfreq(struct gspca_dev *gspca_dev, s32 val)
Jean-François Moine78b98cb2010-06-05 07:01:46 -0300539{
540 struct sd *sd = (struct sd *) gspca_dev;
541 u8 reg66;
542 u8 freq[4] = { 0x66, 0x00, 0xa8, 0xe8 };
543
544 switch (sd->sensor) {
545 case SENSOR_LT168G:
Hans Verkuil9bf81642012-05-18 03:41:58 -0300546 if (val != 0)
Jean-François Moine78b98cb2010-06-05 07:01:46 -0300547 freq[3] = 0xa8;
548 reg66 = 0x41;
549 break;
550 case SENSOR_OM6802:
551 reg66 = 0xca;
552 break;
553 default:
554 reg66 = 0x40;
555 break;
556 }
Hans Verkuil9bf81642012-05-18 03:41:58 -0300557 switch (val) {
Jean-François Moine78b98cb2010-06-05 07:01:46 -0300558 case 0: /* no flicker */
559 freq[3] = 0xf0;
560 break;
561 case 2: /* 60Hz */
562 reg66 &= ~0x40;
563 break;
564 }
565 freq[1] = reg66;
566
567 reg_w_buf(gspca_dev, freq, sizeof freq);
568}
569
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300570/* this function is called at probe and resume time */
571static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300572{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300573 /* some of this registers are not really neded, because
574 * they are overriden by setbrigthness, setcontrast, etc,
575 * but wont hurt anyway, and can help someone with similar webcam
576 * to see the initial parameters.*/
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300577 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300578 const struct additional_sensor_data *sensor;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300579 int i;
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300580 u16 sensor_id;
Hans Verkuild9ddd3b2009-01-29 06:23:18 -0300581 u8 test_byte = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300582
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300583 static const u8 read_indexs[] =
Jean-Francois Moine249fe882009-03-22 16:30:42 -0300584 { 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300585 0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00 };
586 static const u8 n1[] =
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300587 {0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300588 static const u8 n2[] =
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300589 {0x08, 0x00};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300590
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300591 sensor_id = (reg_r(gspca_dev, 0x06) << 8)
592 | reg_r(gspca_dev, 0x07);
Jean-Francois Moine3da37e42009-03-22 16:29:36 -0300593 switch (sensor_id & 0xff0f) {
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300594 case 0x0801:
Jean-Francois Moine748c0142009-02-06 14:11:58 -0300595 PDEBUG(D_PROBE, "sensor tas5130a");
Jean-Francois Moine236088d2008-10-17 04:53:02 -0300596 sd->sensor = SENSOR_TAS5130A;
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300597 break;
Nicolau Werneck00e80062010-01-30 16:00:15 -0300598 case 0x0802:
599 PDEBUG(D_PROBE, "sensor lt168g");
600 sd->sensor = SENSOR_LT168G;
601 break;
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300602 case 0x0803:
Jean-Francois Moine748c0142009-02-06 14:11:58 -0300603 PDEBUG(D_PROBE, "sensor 'other'");
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300604 sd->sensor = SENSOR_OTHER;
605 break;
606 case 0x0807:
Jean-Francois Moine748c0142009-02-06 14:11:58 -0300607 PDEBUG(D_PROBE, "sensor om6802");
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300608 sd->sensor = SENSOR_OM6802;
609 break;
610 default:
Joe Perches1b19e4292011-08-21 19:56:56 -0300611 pr_err("unknown sensor %04x\n", sensor_id);
Jean-Francois Moine409b11d2009-01-22 12:53:56 -0300612 return -EINVAL;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300613 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300614
Jean-Francois Moinedd72cb32009-03-12 04:40:19 -0300615 if (sd->sensor == SENSOR_OM6802) {
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300616 reg_w_buf(gspca_dev, n1, sizeof n1);
617 i = 5;
618 while (--i >= 0) {
619 reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
620 test_byte = reg_r(gspca_dev, 0x0063);
621 msleep(100);
622 if (test_byte == 0x17)
623 break; /* OK */
624 }
625 if (i < 0) {
Joe Perches1b19e4292011-08-21 19:56:56 -0300626 pr_err("Bad sensor reset %02x\n", test_byte);
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300627 return -EIO;
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300628 }
629 reg_w_buf(gspca_dev, n2, sizeof n2);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300630 }
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300631
632 i = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300633 while (read_indexs[i] != 0x00) {
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300634 test_byte = reg_r(gspca_dev, read_indexs[i]);
635 PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", read_indexs[i],
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300636 test_byte);
637 i++;
638 }
639
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300640 sensor = &sensor_data[sd->sensor];
641 reg_w_buf(gspca_dev, sensor->n3, sizeof sensor->n3);
642 reg_w_buf(gspca_dev, sensor->n4, sensor->n4sz);
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300643
Nicolau Werneck00e80062010-01-30 16:00:15 -0300644 if (sd->sensor == SENSOR_LT168G) {
645 test_byte = reg_r(gspca_dev, 0x80);
646 PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", 0x80,
647 test_byte);
648 reg_w(gspca_dev, 0x6c80);
649 }
650
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300651 reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);
652 reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);
653 reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300654
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300655 reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80);
656 reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80);
657 reg_w(gspca_dev, (sensor->reg8e << 8) + 0x8e);
Hans Verkuil9bf81642012-05-18 03:41:58 -0300658 reg_w(gspca_dev, (0x20 << 8) + 0x87);
659 reg_w(gspca_dev, (0x20 << 8) + 0x88);
660 reg_w(gspca_dev, (0x20 << 8) + 0x89);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300661
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300662 reg_w_buf(gspca_dev, sensor->data5, sizeof sensor->data5);
663 reg_w_buf(gspca_dev, sensor->nset8, sizeof sensor->nset8);
664 reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300665
Nicolau Werneck00e80062010-01-30 16:00:15 -0300666 if (sd->sensor == SENSOR_LT168G) {
667 test_byte = reg_r(gspca_dev, 0x80);
668 PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", 0x80,
669 test_byte);
670 reg_w(gspca_dev, 0x6c80);
671 }
672
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300673 reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);
674 reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);
675 reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300676
677 return 0;
678}
679
Hans Verkuil9bf81642012-05-18 03:41:58 -0300680static void setmirror(struct gspca_dev *gspca_dev, s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300681{
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300682 u8 hflipcmd[8] =
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300683 {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300684
Hans Verkuil9bf81642012-05-18 03:41:58 -0300685 if (val)
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300686 hflipcmd[3] = 0x01;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300687
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300688 reg_w_buf(gspca_dev, hflipcmd, sizeof hflipcmd);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300689}
690
Hans Verkuil9bf81642012-05-18 03:41:58 -0300691static void seteffect(struct gspca_dev *gspca_dev, s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300692{
Hans Verkuil9bf81642012-05-18 03:41:58 -0300693 int idx = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300694
Hans Verkuil9bf81642012-05-18 03:41:58 -0300695 switch (val) {
696 case V4L2_COLORFX_NONE:
697 break;
698 case V4L2_COLORFX_BW:
699 idx = 2;
700 break;
701 case V4L2_COLORFX_SEPIA:
702 idx = 3;
703 break;
704 case V4L2_COLORFX_SKETCH:
705 idx = 4;
706 break;
707 case V4L2_COLORFX_NEGATIVE:
708 idx = 6;
709 break;
710 default:
711 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300712 }
713
Hans Verkuil9bf81642012-05-18 03:41:58 -0300714 reg_w_buf(gspca_dev, effects_table[idx],
715 sizeof effects_table[0]);
716
717 if (val == V4L2_COLORFX_SKETCH)
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300718 reg_w(gspca_dev, 0x4aa6);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300719 else
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300720 reg_w(gspca_dev, 0xfaa6);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300721}
722
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300723/* Is this really needed?
724 * i added some module parameters for test with some users */
725static void poll_sensor(struct gspca_dev *gspca_dev)
726{
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300727 static const u8 poll1[] =
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300728 {0x67, 0x05, 0x68, 0x81, 0x69, 0x80, 0x6a, 0x82,
729 0x6b, 0x68, 0x6c, 0x69, 0x72, 0xd9, 0x73, 0x34,
730 0x74, 0x32, 0x75, 0x92, 0x76, 0x00, 0x09, 0x01,
731 0x60, 0x14};
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300732 static const u8 poll2[] =
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300733 {0x67, 0x02, 0x68, 0x71, 0x69, 0x72, 0x72, 0xa9,
734 0x73, 0x02, 0x73, 0x02, 0x60, 0x14};
Jean-François Moine98388242010-06-04 07:30:21 -0300735 static const u8 noise03[] = /* (some differences / ms-drv) */
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300736 {0xa6, 0x0a, 0xea, 0xcf, 0xbe, 0x26, 0xb1, 0x5f,
737 0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c,
738 0xc2, 0x80, 0xc3, 0x10};
739
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300740 PDEBUG(D_STREAM, "[Sensor requires polling]");
741 reg_w_buf(gspca_dev, poll1, sizeof poll1);
742 reg_w_buf(gspca_dev, poll2, sizeof poll2);
Jean-François Moine98388242010-06-04 07:30:21 -0300743 reg_w_buf(gspca_dev, noise03, sizeof noise03);
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300744}
745
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300746static int sd_start(struct gspca_dev *gspca_dev)
747{
748 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300749 const struct additional_sensor_data *sensor;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300750 int i, mode;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300751 u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
752 static const u8 t3[] =
753 { 0x07, 0x00, 0x88, 0x02, 0x06, 0x00, 0xe7, 0x01 };
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300754
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300755 mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300756 switch (mode) {
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300757 case 0: /* 640x480 (0x00) */
758 break;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300759 case 1: /* 352x288 */
760 t2[1] = 0x40;
761 break;
762 case 2: /* 320x240 */
763 t2[1] = 0x10;
764 break;
765 case 3: /* 176x144 */
766 t2[1] = 0x50;
767 break;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300768 default:
769/* case 4: * 160x120 */
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300770 t2[1] = 0x20;
771 break;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300772 }
773
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300774 switch (sd->sensor) {
775 case SENSOR_OM6802:
776 om6802_sensor_init(gspca_dev);
777 break;
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300778 case SENSOR_TAS5130A:
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300779 i = 0;
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300780 for (;;) {
Jean-Francois Moinef89be032008-10-17 04:42:29 -0300781 reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300782 sizeof tas5130a_sensor_init[0]);
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300783 if (i >= ARRAY_SIZE(tas5130a_sensor_init) - 1)
784 break;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300785 i++;
786 }
787 reg_w(gspca_dev, 0x3c80);
788 /* just in case and to keep sync with logs (for mine) */
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300789 reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300790 sizeof tas5130a_sensor_init[0]);
791 reg_w(gspca_dev, 0x3c80);
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300792 break;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300793 }
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300794 sensor = &sensor_data[sd->sensor];
Hans Verkuil9bf81642012-05-18 03:41:58 -0300795 setfreq(gspca_dev, v4l2_ctrl_g_ctrl(sd->freq));
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300796 reg_r(gspca_dev, 0x0012);
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300797 reg_w_buf(gspca_dev, t2, sizeof t2);
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300798 reg_w_ixbuf(gspca_dev, 0xb3, t3, sizeof t3);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300799 reg_w(gspca_dev, 0x0013);
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300800 msleep(15);
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300801 reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
802 reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300803
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300804 if (sd->sensor == SENSOR_OM6802)
805 poll_sensor(gspca_dev);
806
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300807 return 0;
808}
809
Jean-Francois Moineeb229b22008-10-17 05:28:40 -0300810static void sd_stopN(struct gspca_dev *gspca_dev)
811{
812 struct sd *sd = (struct sd *) gspca_dev;
813
814 reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
815 sizeof sensor_data[sd->sensor].stream);
Jean-Francois Moineeb229b22008-10-17 05:28:40 -0300816 reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
817 sizeof sensor_data[sd->sensor].stream);
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300818 if (sd->sensor == SENSOR_OM6802) {
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300819 msleep(20);
820 reg_w(gspca_dev, 0x0309);
821 }
Peter Senna Tschudinf8d26872013-01-24 19:29:11 -0300822#if IS_ENABLED(CONFIG_INPUT)
Hans de Goedeee186fd2012-01-01 16:09:17 -0300823 /* If the last button state is pressed, release it now! */
824 if (sd->button_pressed) {
825 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
826 input_sync(gspca_dev->input_dev);
827 sd->button_pressed = 0;
828 }
829#endif
Jean-Francois Moineeb229b22008-10-17 05:28:40 -0300830}
831
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300832static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300833 u8 *data, /* isoc packet */
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300834 int len) /* iso packet length */
835{
Arnd Bergmannd7e92e12016-07-04 10:21:40 -0300836 struct sd *sd __maybe_unused = (struct sd *) gspca_dev;
Jean-François Moineebb78c52010-06-05 06:56:48 -0300837 int pkt_type;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300838
839 if (data[0] == 0x5a) {
Peter Senna Tschudinf8d26872013-01-24 19:29:11 -0300840#if IS_ENABLED(CONFIG_INPUT)
Hans de Goedeee186fd2012-01-01 16:09:17 -0300841 if (len > 20) {
842 u8 state = (data[20] & 0x80) ? 1 : 0;
843 if (sd->button_pressed != state) {
844 input_report_key(gspca_dev->input_dev,
845 KEY_CAMERA, state);
846 input_sync(gspca_dev->input_dev);
847 sd->button_pressed = state;
848 }
849 }
850#endif
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300851 /* Control Packet, after this came the header again,
852 * but extra bytes came in the packet before this,
853 * sometimes an EOF arrives, sometimes not... */
854 return;
855 }
856 data += 2;
857 len -= 2;
Jean-François Moineebb78c52010-06-05 06:56:48 -0300858 if (data[0] == 0xff && data[1] == 0xd8)
859 pkt_type = FIRST_PACKET;
860 else if (data[len - 2] == 0xff && data[len - 1] == 0xd9)
861 pkt_type = LAST_PACKET;
862 else
863 pkt_type = INTER_PACKET;
864 gspca_frame_add(gspca_dev, pkt_type, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300865}
866
Hans Verkuil9bf81642012-05-18 03:41:58 -0300867static int sd_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300868{
Hans Verkuil9bf81642012-05-18 03:41:58 -0300869 struct gspca_dev *gspca_dev =
870 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
871 struct sd *sd = (struct sd *)gspca_dev;
872 s32 red_gain, blue_gain, green_gain;
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300873
Hans Verkuil9bf81642012-05-18 03:41:58 -0300874 gspca_dev->usb_err = 0;
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300875
Hans Verkuil9bf81642012-05-18 03:41:58 -0300876 switch (ctrl->id) {
877 case V4L2_CID_AUTO_WHITE_BALANCE:
878 red_gain = reg_r(gspca_dev, 0x0087);
879 if (red_gain > 0x40)
880 red_gain = 0x40;
881 else if (red_gain < 0x10)
882 red_gain = 0x10;
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300883
Hans Verkuil9bf81642012-05-18 03:41:58 -0300884 blue_gain = reg_r(gspca_dev, 0x0088);
885 if (blue_gain > 0x40)
886 blue_gain = 0x40;
887 else if (blue_gain < 0x10)
888 blue_gain = 0x10;
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300889
Hans Verkuil9bf81642012-05-18 03:41:58 -0300890 green_gain = reg_r(gspca_dev, 0x0089);
891 if (green_gain > 0x40)
892 green_gain = 0x40;
893 else if (green_gain < 0x10)
894 green_gain = 0x10;
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300895
Hans Verkuil9bf81642012-05-18 03:41:58 -0300896 sd->gain->val = green_gain;
897 sd->red_balance->val = red_gain - green_gain;
898 sd->blue_balance->val = blue_gain - green_gain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300899 break;
900 }
Hans Verkuil9bf81642012-05-18 03:41:58 -0300901 return 0;
902}
903
904static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
905{
906 struct gspca_dev *gspca_dev =
907 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
908
909 gspca_dev->usb_err = 0;
910
911 if (!gspca_dev->streaming)
912 return 0;
913
914 switch (ctrl->id) {
915 case V4L2_CID_BRIGHTNESS:
916 setbrightness(gspca_dev, ctrl->val);
917 break;
918 case V4L2_CID_CONTRAST:
919 setcontrast(gspca_dev, ctrl->val);
920 break;
921 case V4L2_CID_SATURATION:
922 setcolors(gspca_dev, ctrl->val);
923 break;
924 case V4L2_CID_GAMMA:
925 setgamma(gspca_dev, ctrl->val);
926 break;
927 case V4L2_CID_HFLIP:
928 setmirror(gspca_dev, ctrl->val);
929 break;
930 case V4L2_CID_SHARPNESS:
931 setsharpness(gspca_dev, ctrl->val);
932 break;
933 case V4L2_CID_POWER_LINE_FREQUENCY:
934 setfreq(gspca_dev, ctrl->val);
935 break;
936 case V4L2_CID_BACKLIGHT_COMPENSATION:
937 reg_w(gspca_dev, ctrl->val ? 0xf48e : 0xb48e);
938 break;
939 case V4L2_CID_AUTO_WHITE_BALANCE:
940 setawb_n_RGB(gspca_dev);
941 break;
942 case V4L2_CID_COLORFX:
943 seteffect(gspca_dev, ctrl->val);
944 break;
945 }
946 return gspca_dev->usb_err;
947}
948
949static const struct v4l2_ctrl_ops sd_ctrl_ops = {
950 .g_volatile_ctrl = sd_g_volatile_ctrl,
951 .s_ctrl = sd_s_ctrl,
952};
953
954static int sd_init_controls(struct gspca_dev *gspca_dev)
955{
956 struct sd *sd = (struct sd *)gspca_dev;
957 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
958
959 gspca_dev->vdev.ctrl_handler = hdl;
960 v4l2_ctrl_handler_init(hdl, 12);
961 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
962 V4L2_CID_BRIGHTNESS, 0, 14, 1, 8);
963 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
964 V4L2_CID_CONTRAST, 0, 0x0d, 1, 7);
965 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
966 V4L2_CID_SATURATION, 0, 0xf, 1, 5);
967 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
968 V4L2_CID_GAMMA, 0, GAMMA_MAX, 1, 10);
969 /* Activate lowlight, some apps dont bring up the
970 backlight_compensation control) */
971 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
972 V4L2_CID_BACKLIGHT_COMPENSATION, 0, 1, 1, 1);
973 if (sd->sensor == SENSOR_TAS5130A)
974 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
975 V4L2_CID_HFLIP, 0, 1, 1, 0);
976 sd->awb = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
977 V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
978 sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
979 V4L2_CID_GAIN, 0x10, 0x40, 1, 0x20);
980 sd->blue_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
981 V4L2_CID_BLUE_BALANCE, -0x30, 0x30, 1, 0);
982 sd->red_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
983 V4L2_CID_RED_BALANCE, -0x30, 0x30, 1, 0);
984 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
985 V4L2_CID_SHARPNESS, 0, 15, 1, 6);
986 v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops,
987 V4L2_CID_COLORFX, V4L2_COLORFX_SKETCH,
988 ~((1 << V4L2_COLORFX_NONE) |
989 (1 << V4L2_COLORFX_BW) |
990 (1 << V4L2_COLORFX_SEPIA) |
991 (1 << V4L2_COLORFX_SKETCH) |
992 (1 << V4L2_COLORFX_NEGATIVE)),
993 V4L2_COLORFX_NONE);
994 sd->freq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops,
995 V4L2_CID_POWER_LINE_FREQUENCY,
996 V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 1,
997 V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
998
999 if (hdl->error) {
1000 pr_err("Could not initialize controls\n");
1001 return hdl->error;
1002 }
1003
1004 v4l2_ctrl_auto_cluster(4, &sd->awb, 0, true);
1005
1006 return 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001007}
1008
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001009/* sub-driver description */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001010static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001011 .name = MODULE_NAME,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001012 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -03001013 .init = sd_init,
Hans Verkuil9bf81642012-05-18 03:41:58 -03001014 .init_controls = sd_init_controls,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001015 .start = sd_start,
Jean-Francois Moineeb229b22008-10-17 05:28:40 -03001016 .stopN = sd_stopN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001017 .pkt_scan = sd_pkt_scan,
Peter Senna Tschudinf8d26872013-01-24 19:29:11 -03001018#if IS_ENABLED(CONFIG_INPUT)
Hans de Goedeee186fd2012-01-01 16:09:17 -03001019 .other_input = 1,
1020#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001021};
1022
1023/* -- module initialisation -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -03001024static const struct usb_device_id device_table[] = {
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001025 {USB_DEVICE(0x17a1, 0x0128)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001026 {}
1027};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001028MODULE_DEVICE_TABLE(usb, device_table);
1029
1030/* -- device connect -- */
1031static int sd_probe(struct usb_interface *intf,
1032 const struct usb_device_id *id)
1033{
1034 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1035 THIS_MODULE);
1036}
1037
1038static struct usb_driver sd_driver = {
1039 .name = MODULE_NAME,
1040 .id_table = device_table,
1041 .probe = sd_probe,
1042 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001043#ifdef CONFIG_PM
1044 .suspend = gspca_suspend,
1045 .resume = gspca_resume,
Hans de Goede8bb58962012-06-30 06:44:47 -03001046 .reset_resume = gspca_resume,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001047#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001048};
1049
Greg Kroah-Hartmanecb3b2b2011-11-18 09:46:12 -08001050module_usb_driver(sd_driver);