blob: 245a30ec5fb13438218e402259ac7ec19455c28b [file] [log] [blame]
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001/*
2 * Sonix sn9c102p sn9c105 sn9c120 (jpeg) library
3 * Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr
4 *
5 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#define MODULE_NAME "sonixj"
23
24#include "gspca.h"
25#include "jpeg.h"
26
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030027MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
28MODULE_DESCRIPTION("GSPCA/SONIX JPEG USB Camera Driver");
29MODULE_LICENSE("GPL");
30
31/* specific webcam descriptor */
32struct sd {
33 struct gspca_dev gspca_dev; /* !! must be the first item */
34
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -030035 atomic_t avg_lum;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030036 unsigned int exposure;
37
38 unsigned short brightness;
39 unsigned char contrast;
40 unsigned char colors;
41 unsigned char autogain;
42
43 signed char ag_cnt;
44#define AG_CNT_START 13
45
46 char qindex;
Hans de Goede3647fea2008-07-15 05:36:30 -030047 unsigned char bridge;
48#define BRIDGE_SN9C102P 0
49#define BRIDGE_SN9C105 1
50#define BRIDGE_SN9C110 2
51#define BRIDGE_SN9C120 3
52#define BRIDGE_SN9C325 4
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030053 char sensor; /* Type of image sensor chip */
54#define SENSOR_HV7131R 0
55#define SENSOR_MI0360 1
56#define SENSOR_MO4000 2
57#define SENSOR_OV7648 3
58#define SENSOR_OV7660 4
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030059 unsigned char i2c_base;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030060};
61
62/* V4L2 controls supported by the driver */
63static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
64static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
65static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
66static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
67static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
68static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
69static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
70static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
71
72static struct ctrl sd_ctrls[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030073 {
74 {
75 .id = V4L2_CID_BRIGHTNESS,
76 .type = V4L2_CTRL_TYPE_INTEGER,
77 .name = "Brightness",
78 .minimum = 0,
79 .maximum = 0xffff,
80 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030081#define BRIGHTNESS_DEF 0x7fff
82 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030083 },
84 .set = sd_setbrightness,
85 .get = sd_getbrightness,
86 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030087 {
88 {
89 .id = V4L2_CID_CONTRAST,
90 .type = V4L2_CTRL_TYPE_INTEGER,
91 .name = "Contrast",
92 .minimum = 0,
93 .maximum = 127,
94 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030095#define CONTRAST_DEF 63
96 .default_value = CONTRAST_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030097 },
98 .set = sd_setcontrast,
99 .get = sd_getcontrast,
100 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300101 {
102 {
103 .id = V4L2_CID_SATURATION,
104 .type = V4L2_CTRL_TYPE_INTEGER,
105 .name = "Color",
106 .minimum = 0,
107 .maximum = 255,
108 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300109#define COLOR_DEF 127
110 .default_value = COLOR_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300111 },
112 .set = sd_setcolors,
113 .get = sd_getcolors,
114 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300115 {
116 {
117 .id = V4L2_CID_AUTOGAIN,
118 .type = V4L2_CTRL_TYPE_BOOLEAN,
119 .name = "Auto Gain",
120 .minimum = 0,
121 .maximum = 1,
122 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300123#define AUTOGAIN_DEF 1
124 .default_value = AUTOGAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300125 },
126 .set = sd_setautogain,
127 .get = sd_getautogain,
128 },
129};
130
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300131static struct v4l2_pix_format vga_mode[] = {
132 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
133 .bytesperline = 160,
134 .sizeimage = 160 * 120 * 3 / 8 + 590,
135 .colorspace = V4L2_COLORSPACE_JPEG,
136 .priv = 2},
137 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
138 .bytesperline = 320,
139 .sizeimage = 320 * 240 * 3 / 8 + 590,
140 .colorspace = V4L2_COLORSPACE_JPEG,
141 .priv = 1},
142 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
143 .bytesperline = 640,
144 .sizeimage = 640 * 480 * 3 / 8 + 590,
145 .colorspace = V4L2_COLORSPACE_JPEG,
146 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300147};
148
149/*Data from sn9c102p+hv71331r */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300150static const __u8 sn_hv7131[] = {
Jean-Francois Moine8f47a3c2008-07-29 14:14:04 -0300151/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
152 0x00, 0x03, 0x64, 0x00, 0x1a, 0x20, 0x20, 0x20,
153/* reg8 reg9 rega regb regc regd rege regf */
154 0xa1, 0x11, 0x02, 0x09, 0x00, 0x00, 0x00, 0x10,
155/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
156 0x03, 0x00, 0x00, 0x01, 0x03, 0x28, 0x1e, 0x41,
157/* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */
158 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300159};
160
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300161static const __u8 sn_mi0360[] = {
Jean-Francois Moine8f47a3c2008-07-29 14:14:04 -0300162/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
163 0x00, 0x61, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20,
164/* reg8 reg9 rega regb regc regd rege regf */
165 0xb1, 0x5d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10,
166/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
167 0x03, 0x00, 0x00, 0x02, 0x0a, 0x28, 0x1e, 0x61,
168/* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */
169 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300170};
171
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300172static const __u8 sn_mo4000[] = {
Jean-Francois Moine8f47a3c2008-07-29 14:14:04 -0300173/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
174 0x12, 0x23, 0x60, 0x00, 0x1a, 0x00, 0x20, 0x18,
175/* reg8 reg9 rega regb regc regd rege regf */
176 0x81, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
177/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
178 0x03, 0x00, 0x0b, 0x0f, 0x14, 0x28, 0x1e, 0x40,
179/* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */
180 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300181};
182
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300183static const __u8 sn_ov7648[] = {
Jean-Francois Moine8f47a3c2008-07-29 14:14:04 -0300184/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
185 0x00, 0x21, 0x62, 0x00, 0x1a, 0x20, 0x20, 0x20,
186/* reg8 reg9 rega regb regc regd rege regf */
187 0xa1, 0x6e, 0x18, 0x65, 0x00, 0x00, 0x00, 0x10,
188/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
189 0x03, 0x00, 0x00, 0x06, 0x06, 0x28, 0x1e, 0x82,
190/* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */
191 0x07, 0x00, 0x00, 0x00, 0x00, 0x00
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300192};
193
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300194static const __u8 sn_ov7660[] = {
Jean-Francois Moine8f47a3c2008-07-29 14:14:04 -0300195/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
196 0x00, 0x61, 0x40, 0x00, 0x1a, 0x20, 0x20, 0x20,
197/* reg8 reg9 rega regb regc regd rege regf */
198 0x81, 0x21, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10,
199/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
200 0x03, 0x00, 0x01, 0x01, 0x08, 0x28, 0x1e, 0x20,
201/* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */
202 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300203};
204
205/* sequence specific to the sensors - !! index = SENSOR_xxx */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300206static const __u8 *sn_tb[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300207 sn_hv7131,
208 sn_mi0360,
209 sn_mo4000,
210 sn_ov7648,
211 sn_ov7660
212};
213
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300214static const __u8 regsn20[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300215 0x00, 0x2d, 0x46, 0x5a, 0x6c, 0x7c, 0x8b, 0x99,
216 0xa6, 0xb2, 0xbf, 0xca, 0xd5, 0xe0, 0xeb, 0xf5, 0xff
217};
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300218static const __u8 regsn20_sn9c325[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300219 0x0a, 0x3a, 0x56, 0x6c, 0x7e, 0x8d, 0x9a, 0xa4,
220 0xaf, 0xbb, 0xc5, 0xcd, 0xd5, 0xde, 0xe8, 0xed, 0xf5
221};
222
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300223static const __u8 reg84[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300224 0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe5, 0x0f,
225 0xe4, 0x0f, 0x38, 0x00, 0x3e, 0x00, 0xc3, 0x0f,
226/* 0x00, 0x00, 0x00, 0x00, 0x00 */
227 0xf7, 0x0f, 0x0a, 0x00, 0x00
228};
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300229static const __u8 reg84_sn9c325[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300230 0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe4, 0x0f,
231 0xd3, 0x0f, 0x4b, 0x00, 0x48, 0x00, 0xc0, 0x0f,
232 0xf8, 0x0f, 0x00, 0x00, 0x00
233};
234
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300235static const __u8 hv7131r_sensor_init[][8] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300236 {0xC1, 0x11, 0x01, 0x08, 0x01, 0x00, 0x00, 0x10},
237 {0xB1, 0x11, 0x34, 0x17, 0x7F, 0x00, 0x00, 0x10},
238 {0xD1, 0x11, 0x40, 0xFF, 0x7F, 0x7F, 0x7F, 0x10},
239 {0x91, 0x11, 0x44, 0x00, 0x00, 0x00, 0x00, 0x10},
240 {0xD1, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
241 {0xD1, 0x11, 0x14, 0x01, 0xE2, 0x02, 0x82, 0x10},
242 {0x91, 0x11, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10},
243
244 {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
245 {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
246 {0xC1, 0x11, 0x25, 0x00, 0x61, 0xA8, 0x00, 0x10},
247 {0xA1, 0x11, 0x30, 0x22, 0x00, 0x00, 0x00, 0x10},
248 {0xC1, 0x11, 0x31, 0x20, 0x2E, 0x20, 0x00, 0x10},
249 {0xC1, 0x11, 0x25, 0x00, 0xC3, 0x50, 0x00, 0x10},
250 {0xA1, 0x11, 0x30, 0x07, 0x00, 0x00, 0x00, 0x10}, /* gain14 */
251 {0xC1, 0x11, 0x31, 0x10, 0x10, 0x10, 0x00, 0x10}, /* r g b 101a10 */
252
253 {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
254 {0xA1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
255 {0xA1, 0x11, 0x21, 0xD0, 0x00, 0x00, 0x00, 0x10},
256 {0xA1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
257 {0xA1, 0x11, 0x23, 0x09, 0x00, 0x00, 0x00, 0x10},
258
259 {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
260 {0xA1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
261 {0xA1, 0x11, 0x21, 0xD0, 0x00, 0x00, 0x00, 0x10},
262 {0xA1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
263 {0xA1, 0x11, 0x23, 0x10, 0x00, 0x00, 0x00, 0x10},
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300264 {}
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300265};
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300266static const __u8 mi0360_sensor_init[][8] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300267 {0xB1, 0x5D, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10},
268 {0xB1, 0x5D, 0x0D, 0x00, 0x01, 0x00, 0x00, 0x10},
269 {0xB1, 0x5D, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x10},
270 {0xD1, 0x5D, 0x01, 0x00, 0x08, 0x00, 0x16, 0x10},
271 {0xD1, 0x5D, 0x03, 0x01, 0xE2, 0x02, 0x82, 0x10},
272 {0xD1, 0x5D, 0x05, 0x00, 0x09, 0x00, 0x53, 0x10},
273 {0xB1, 0x5D, 0x0D, 0x00, 0x02, 0x00, 0x00, 0x10},
274 {0xD1, 0x5D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x10},
275 {0xD1, 0x5D, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x10},
276 {0xD1, 0x5D, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x10},
277 {0xD1, 0x5D, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
278 {0xD1, 0x5D, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
279 {0xD1, 0x5D, 0x14, 0x00, 0x00, 0x00, 0x00, 0x10},
280 {0xD1, 0x5D, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10},
281 {0xD1, 0x5D, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10},
282 {0xD1, 0x5D, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x10},
283 {0xD1, 0x5D, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x10},
284 {0xB1, 0x5D, 0x32, 0x00, 0x00, 0x00, 0x00, 0x10},
285 {0xD1, 0x5D, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10},
286 {0xD1, 0x5D, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
287 {0xD1, 0x5D, 0x24, 0x00, 0x00, 0x00, 0x00, 0x10},
288 {0xD1, 0x5D, 0x26, 0x00, 0x00, 0x00, 0x24, 0x10},
289 {0xD1, 0x5D, 0x2F, 0xF7, 0xB0, 0x00, 0x04, 0x10},
290 {0xD1, 0x5D, 0x31, 0x00, 0x00, 0x00, 0x00, 0x10},
291 {0xD1, 0x5D, 0x33, 0x00, 0x00, 0x01, 0x00, 0x10},
292 {0xB1, 0x5D, 0x3D, 0x06, 0x8F, 0x00, 0x00, 0x10},
293 {0xD1, 0x5D, 0x40, 0x01, 0xE0, 0x00, 0xD1, 0x10},
294 {0xB1, 0x5D, 0x44, 0x00, 0x82, 0x00, 0x00, 0x10},
295 {0xD1, 0x5D, 0x58, 0x00, 0x78, 0x00, 0x43, 0x10},
296 {0xD1, 0x5D, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x10},
297 {0xD1, 0x5D, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x10},
298 {0xD1, 0x5D, 0x5E, 0x00, 0x00, 0xA3, 0x1D, 0x10},
299 {0xB1, 0x5D, 0x62, 0x04, 0x11, 0x00, 0x00, 0x10},
300
301 {0xB1, 0x5D, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10},
302 {0xB1, 0x5D, 0x20, 0x11, 0x01, 0x00, 0x00, 0x10},
303 {0xB1, 0x5D, 0x09, 0x00, 0x64, 0x00, 0x00, 0x10},
304 {0xD1, 0x5D, 0x2B, 0x00, 0xA0, 0x00, 0xB0, 0x10},
305 {0xD1, 0x5D, 0x2D, 0x00, 0xA0, 0x00, 0xA0, 0x10},
306
307 {0xB1, 0x5D, 0x0A, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor clck ?2 */
308 {0xB1, 0x5D, 0x06, 0x00, 0x30, 0x00, 0x00, 0x10},
309 {0xB1, 0x5D, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x10},
310 {0xB1, 0x5D, 0x09, 0x02, 0x35, 0x00, 0x00, 0x10}, /* exposure 2 */
311
312 {0xD1, 0x5D, 0x2B, 0x00, 0xB9, 0x00, 0xE3, 0x10},
313 {0xD1, 0x5D, 0x2D, 0x00, 0x5f, 0x00, 0xB9, 0x10}, /* 42 */
314/* {0xB1, 0x5D, 0x35, 0x00, 0x67, 0x00, 0x00, 0x10}, * gain orig */
315/* {0xB1, 0x5D, 0x35, 0x00, 0x20, 0x00, 0x00, 0x10}, * gain */
316 {0xB1, 0x5D, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10}, /* update */
317 {0xB1, 0x5D, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor on */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300318 {}
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300319};
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300320static const __u8 mo4000_sensor_init[][8] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300321 {0xa1, 0x21, 0x01, 0x02, 0x00, 0x00, 0x00, 0x10},
322 {0xa1, 0x21, 0x02, 0x00, 0x00, 0x00, 0x00, 0x10},
323 {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10},
324 {0xa1, 0x21, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10},
325 {0xa1, 0x21, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10},
326 {0xa1, 0x21, 0x05, 0x04, 0x00, 0x00, 0x00, 0x10},
327 {0xa1, 0x21, 0x06, 0x80, 0x00, 0x00, 0x00, 0x10},
328 {0xa1, 0x21, 0x06, 0x81, 0x00, 0x00, 0x00, 0x10},
329 {0xa1, 0x21, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x10},
330 {0xa1, 0x21, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10},
331 {0xa1, 0x21, 0x11, 0x20, 0x00, 0x00, 0x00, 0x10},
332 {0xa1, 0x21, 0x11, 0x30, 0x00, 0x00, 0x00, 0x10},
333 {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
334 {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
335 {0xa1, 0x21, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
336 {0xa1, 0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
337 {0xa1, 0x21, 0x0f, 0x20, 0x00, 0x00, 0x00, 0x10},
338 {0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10},
339 {0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
340 {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300341 {}
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300342};
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300343static const __u8 ov7660_sensor_init[][8] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300344 {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */
Jean-Francois Moine60017612008-07-18 08:46:19 -0300345/* (delay 20ms) */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300346 {0xa1, 0x21, 0x12, 0x05, 0x00, 0x00, 0x00, 0x10},
Jean-Francois Moine738608a2008-07-28 06:41:51 -0300347 /* Outformat = rawRGB */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300348 {0xa1, 0x21, 0x13, 0xb8, 0x00, 0x00, 0x00, 0x10}, /* init COM8 */
Jean-Francois Moine738608a2008-07-28 06:41:51 -0300349 {0xd1, 0x21, 0x00, 0x01, 0x74, 0x74, 0x00, 0x10},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300350 /* GAIN BLUE RED VREF */
351 {0xd1, 0x21, 0x04, 0x00, 0x7d, 0x62, 0x00, 0x10},
352 /* COM 1 BAVE GEAVE AECHH */
353 {0xb1, 0x21, 0x08, 0x83, 0x01, 0x00, 0x00, 0x10}, /* RAVE COM2 */
354 {0xd1, 0x21, 0x0c, 0x00, 0x08, 0x04, 0x4f, 0x10}, /* COM 3 4 5 6 */
Jean-Francois Moine738608a2008-07-28 06:41:51 -0300355 {0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xff, 0x10},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300356 /* AECH CLKRC COM7 COM8 */
357 {0xc1, 0x21, 0x14, 0x2c, 0x00, 0x02, 0x00, 0x10}, /* COM9 COM10 */
358 {0xd1, 0x21, 0x17, 0x10, 0x60, 0x02, 0x7b, 0x10},
359 /* HSTART HSTOP VSTRT VSTOP */
360 {0xa1, 0x21, 0x1b, 0x02, 0x00, 0x00, 0x00, 0x10}, /* PSHFT */
361 {0xb1, 0x21, 0x1e, 0x01, 0x0e, 0x00, 0x00, 0x10}, /* MVFP LAEC */
362 {0xd1, 0x21, 0x20, 0x07, 0x07, 0x07, 0x07, 0x10},
363 /* BOS GBOS GROS ROS (BGGR offset) */
Jean-Francois Moine738608a2008-07-28 06:41:51 -0300364/* {0xd1, 0x21, 0x24, 0x68, 0x58, 0xd4, 0x80, 0x10}, */
365 {0xd1, 0x21, 0x24, 0x78, 0x68, 0xd4, 0x80, 0x10},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300366 /* AEW AEB VPT BBIAS */
367 {0xd1, 0x21, 0x28, 0x80, 0x30, 0x00, 0x00, 0x10},
368 /* GbBIAS RSVD EXHCH EXHCL */
369 {0xd1, 0x21, 0x2c, 0x80, 0x00, 0x00, 0x62, 0x10},
370 /* RBIAS ADVFL ASDVFH YAVE */
371 {0xc1, 0x21, 0x30, 0x08, 0x30, 0xb4, 0x00, 0x10},
372 /* HSYST HSYEN HREF */
373 {0xd1, 0x21, 0x33, 0x00, 0x07, 0x84, 0x00, 0x10}, /* reserved */
374 {0xd1, 0x21, 0x37, 0x0c, 0x02, 0x43, 0x00, 0x10},
375 /* ADC ACOM OFON TSLB */
376 {0xd1, 0x21, 0x3b, 0x02, 0x6c, 0x19, 0x0e, 0x10},
377 /* COM11 COM12 COM13 COM14 */
378 {0xd1, 0x21, 0x3f, 0x41, 0xc1, 0x22, 0x08, 0x10},
379 /* EDGE COM15 COM16 COM17 */
380 {0xd1, 0x21, 0x43, 0xf0, 0x10, 0x78, 0xa8, 0x10}, /* reserved */
381 {0xd1, 0x21, 0x47, 0x60, 0x80, 0x00, 0x00, 0x10}, /* reserved */
382 {0xd1, 0x21, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x10}, /* reserved */
383 {0xd1, 0x21, 0x4f, 0x46, 0x36, 0x0f, 0x17, 0x10}, /* MTX 1 2 3 4 */
384 {0xd1, 0x21, 0x53, 0x7f, 0x96, 0x40, 0x40, 0x10}, /* MTX 5 6 7 8 */
385 {0xb1, 0x21, 0x57, 0x40, 0x0f, 0x00, 0x00, 0x10}, /* MTX9 MTXS */
386 {0xd1, 0x21, 0x59, 0xba, 0x9a, 0x22, 0xb9, 0x10}, /* reserved */
387 {0xd1, 0x21, 0x5d, 0x9b, 0x10, 0xf0, 0x05, 0x10}, /* reserved */
388 {0xa1, 0x21, 0x61, 0x60, 0x00, 0x00, 0x00, 0x10}, /* reserved */
389 {0xd1, 0x21, 0x62, 0x00, 0x00, 0x50, 0x30, 0x10},
390 /* LCC1 LCC2 LCC3 LCC4 */
391 {0xa1, 0x21, 0x66, 0x00, 0x00, 0x00, 0x00, 0x10}, /* LCC5 */
Jean-Francois Moine738608a2008-07-28 06:41:51 -0300392 {0xd1, 0x21, 0x67, 0x80, 0x7a, 0x90, 0x80, 0x10}, /* MANU */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300393 {0xa1, 0x21, 0x6b, 0x0a, 0x00, 0x00, 0x00, 0x10},
Jean-Francois Moine738608a2008-07-28 06:41:51 -0300394 /* band gap reference [0:3] DBLV */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300395 {0xd1, 0x21, 0x6c, 0x30, 0x48, 0x80, 0x74, 0x10}, /* gamma curve */
396 {0xd1, 0x21, 0x70, 0x64, 0x60, 0x5c, 0x58, 0x10}, /* gamma curve */
397 {0xd1, 0x21, 0x74, 0x54, 0x4c, 0x40, 0x38, 0x10}, /* gamma curve */
398 {0xd1, 0x21, 0x78, 0x34, 0x30, 0x2f, 0x2b, 0x10}, /* gamma curve */
399 {0xd1, 0x21, 0x7c, 0x03, 0x07, 0x17, 0x34, 0x10}, /* gamma curve */
400 {0xd1, 0x21, 0x80, 0x41, 0x4d, 0x58, 0x63, 0x10}, /* gamma curve */
401 {0xd1, 0x21, 0x84, 0x6e, 0x77, 0x87, 0x95, 0x10}, /* gamma curve */
402 {0xc1, 0x21, 0x88, 0xaf, 0xc7, 0xdf, 0x00, 0x10}, /* gamma curve */
403 {0xc1, 0x21, 0x8b, 0x99, 0x99, 0xcf, 0x00, 0x10}, /* reserved */
Jean-Francois Moine738608a2008-07-28 06:41:51 -0300404 {0xb1, 0x21, 0x92, 0x00, 0x00, 0x00, 0x00, 0x10}, /* DM_LNL/H */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300405/****** (some exchanges in the win trace) ******/
Jean-Francois Moine738608a2008-07-28 06:41:51 -0300406 {0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10}, /* MVFP */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300407 /* bits[3..0]reserved */
408 {0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10},
409 {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10},
410 /* VREF vertical frame ctrl */
411 {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10},
Jean-Francois Moine738608a2008-07-28 06:41:51 -0300412 {0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10}, /* AECH 0x20 */
413 {0xa1, 0x21, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x10}, /* ADVFL */
414 {0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10}, /* ADVFH */
415 {0xa1, 0x21, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x10}, /* GAIN */
416/* {0xb1, 0x21, 0x01, 0x78, 0x78, 0x00, 0x00, 0x10}, * BLUE */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300417/****** (some exchanges in the win trace) ******/
418 {0xa1, 0x21, 0x93, 0x00, 0x00, 0x00, 0x00, 0x10},/* dummy line hight */
Jean-Francois Moine738608a2008-07-28 06:41:51 -0300419 {0xa1, 0x21, 0x92, 0x25, 0x00, 0x00, 0x00, 0x10}, /* dummy line low */
420 {0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10}, /* EXHCH */
421 {0xa1, 0x21, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10}, /* EXHCL */
422/* {0xa1, 0x21, 0x02, 0x90, 0x00, 0x00, 0x00, 0x10}, * RED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300423/****** (some exchanges in the win trace) ******/
Jean-Francois Moine738608a2008-07-28 06:41:51 -0300424/******!! startsensor KO if changed !!****/
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300425 {0xa1, 0x21, 0x93, 0x01, 0x00, 0x00, 0x00, 0x10},
426 {0xa1, 0x21, 0x92, 0xff, 0x00, 0x00, 0x00, 0x10},
427 {0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10},
428 {0xa1, 0x21, 0x2b, 0xc3, 0x00, 0x00, 0x00, 0x10},
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300429 {}
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300430};
Jean-Francois Moine738608a2008-07-28 06:41:51 -0300431/* reg 0x04 reg 0x07 reg 0x10 */
432/* expo = (COM1 & 0x02) | ((AECHH & 0x2f) << 10) | (AECh << 2) */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300433
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300434static const __u8 ov7648_sensor_init[][8] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300435 {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00},
436 {0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00},
437 {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00},
438 {0xA1, 0x6E, 0x3F, 0x20, 0x00, 0x00, 0x00, 0x10},
439 {0xA1, 0x6E, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x10},
440 {0xA1, 0x6E, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x10},
441 {0xD1, 0x6E, 0x04, 0x02, 0xB1, 0x02, 0x39, 0x10},
442 {0xD1, 0x6E, 0x08, 0x00, 0x01, 0x00, 0x00, 0x10},
443 {0xD1, 0x6E, 0x0C, 0x02, 0x7F, 0x01, 0xE0, 0x10},
444 {0xD1, 0x6E, 0x12, 0x03, 0x02, 0x00, 0x03, 0x10},
445 {0xD1, 0x6E, 0x16, 0x85, 0x40, 0x4A, 0x40, 0x10},
446 {0xC1, 0x6E, 0x1A, 0x00, 0x80, 0x00, 0x00, 0x10},
447 {0xD1, 0x6E, 0x1D, 0x08, 0x03, 0x00, 0x00, 0x10},
448 {0xD1, 0x6E, 0x23, 0x00, 0xB0, 0x00, 0x94, 0x10},
449 {0xD1, 0x6E, 0x27, 0x58, 0x00, 0x00, 0x00, 0x10},
450 {0xD1, 0x6E, 0x2D, 0x14, 0x35, 0x61, 0x84, 0x10},
451 {0xD1, 0x6E, 0x31, 0xA2, 0xBD, 0xD8, 0xFF, 0x10},
452 {0xD1, 0x6E, 0x35, 0x06, 0x1E, 0x12, 0x02, 0x10},
453 {0xD1, 0x6E, 0x39, 0xAA, 0x53, 0x37, 0xD5, 0x10},
454 {0xA1, 0x6E, 0x3D, 0xF2, 0x00, 0x00, 0x00, 0x10},
455 {0xD1, 0x6E, 0x3E, 0x00, 0x00, 0x80, 0x03, 0x10},
456 {0xD1, 0x6E, 0x42, 0x03, 0x00, 0x00, 0x00, 0x10},
457 {0xC1, 0x6E, 0x46, 0x00, 0x80, 0x80, 0x00, 0x10},
458 {0xD1, 0x6E, 0x4B, 0x02, 0xEF, 0x08, 0xCD, 0x10},
459 {0xD1, 0x6E, 0x4F, 0x00, 0xD0, 0x00, 0xA0, 0x10},
460 {0xD1, 0x6E, 0x53, 0x01, 0xAA, 0x01, 0x40, 0x10},
461 {0xD1, 0x6E, 0x5A, 0x50, 0x04, 0x30, 0x03, 0x10},
462 {0xA1, 0x6E, 0x5E, 0x00, 0x00, 0x00, 0x00, 0x10},
463 {0xD1, 0x6E, 0x5F, 0x10, 0x40, 0xFF, 0x00, 0x10},
464 /* {0xD1, 0x6E, 0x63, 0x40, 0x40, 0x00, 0x00, 0x10},
465 {0xD1, 0x6E, 0x67, 0x00, 0x00, 0x00, 0x00, 0x10},
466 * This is currently setting a
467 * blue tint, and some things more , i leave it here for future test if
468 * somene is having problems with color on this sensor
469 {0xD1, 0x6E, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x10},
470 {0xD1, 0x6E, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x10},
471 {0xC1, 0x6E, 0x73, 0x10, 0x80, 0xEB, 0x00, 0x10},
472 {0xA1, 0x6E, 0x1E, 0x03, 0x00, 0x00, 0x00, 0x10},
473 {0xA1, 0x6E, 0x15, 0x01, 0x00, 0x00, 0x00, 0x10},
474 {0xC1, 0x6E, 0x16, 0x40, 0x40, 0x40, 0x00, 0x10},
475 {0xA1, 0x6E, 0x1D, 0x08, 0x00, 0x00, 0x00, 0x10},
476 {0xA1, 0x6E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10},
477 {0xA1, 0x6E, 0x07, 0xB5, 0x00, 0x00, 0x00, 0x10},
478 {0xA1, 0x6E, 0x18, 0x6B, 0x00, 0x00, 0x00, 0x10},
479 {0xA1, 0x6E, 0x1D, 0x08, 0x00, 0x00, 0x00, 0x10},
480 {0xA1, 0x6E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10},
481 {0xA1, 0x6E, 0x07, 0xB8, 0x00, 0x00, 0x00, 0x10}, */
482 {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00},
483 {0xA1, 0x6E, 0x06, 0x03, 0x00, 0x00, 0x00, 0x10}, /* Bright... */
484 {0xA1, 0x6E, 0x07, 0x66, 0x00, 0x00, 0x00, 0x10}, /* B.. */
485 {0xC1, 0x6E, 0x1A, 0x03, 0x65, 0x90, 0x00, 0x10}, /* Bright/Witen....*/
486/* {0xC1, 0x6E, 0x16, 0x45, 0x40, 0x60, 0x00, 0x10}, * Bright/Witene */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300487 {}
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300488};
489
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300490static const __u8 qtable4[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300491 0x06, 0x04, 0x04, 0x06, 0x04, 0x04, 0x06, 0x06, 0x06, 0x06, 0x08, 0x06,
492 0x06, 0x08, 0x0A, 0x11,
493 0x0A, 0x0A, 0x08, 0x08, 0x0A, 0x15, 0x0F, 0x0F, 0x0C, 0x11, 0x19, 0x15,
494 0x19, 0x19, 0x17, 0x15,
495 0x17, 0x17, 0x1B, 0x1D, 0x25, 0x21, 0x1B, 0x1D, 0x23, 0x1D, 0x17, 0x17,
496 0x21, 0x2E, 0x21, 0x23,
497 0x27, 0x29, 0x2C, 0x2C, 0x2C, 0x19, 0x1F, 0x30, 0x32, 0x2E, 0x29, 0x32,
498 0x25, 0x29, 0x2C, 0x29,
499 0x06, 0x08, 0x08, 0x0A, 0x08, 0x0A, 0x13, 0x0A, 0x0A, 0x13, 0x29, 0x1B,
500 0x17, 0x1B, 0x29, 0x29,
501 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
502 0x29, 0x29, 0x29, 0x29,
503 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
504 0x29, 0x29, 0x29, 0x29,
505 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
506 0x29, 0x29, 0x29, 0x29
507};
508
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300509/* read <len> bytes (len < sizeof gspca_dev->usb_buf) to gspca_dev->usb_buf */
510static void reg_r(struct gspca_dev *gspca_dev,
511 __u16 value, int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300512{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300513 usb_control_msg(gspca_dev->dev,
514 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300515 0,
516 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
517 value, 0,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300518 gspca_dev->usb_buf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300519 500);
Jean-Francois Moine60017612008-07-18 08:46:19 -0300520 PDEBUG(D_USBI, "reg_r [%02x] -> %02x", value, gspca_dev->usb_buf[0]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300521}
522
Jean-Francois Moine60017612008-07-18 08:46:19 -0300523static void reg_w1(struct gspca_dev *gspca_dev,
524 __u16 value,
525 __u8 data)
526{
527 PDEBUG(D_USBO, "reg_w1 [%02x] = %02x", value, data);
528 gspca_dev->usb_buf[0] = data;
529 usb_control_msg(gspca_dev->dev,
530 usb_sndctrlpipe(gspca_dev->dev, 0),
531 0x08,
532 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
533 value,
534 0,
535 gspca_dev->usb_buf, 1,
536 500);
537}
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300538static void reg_w(struct gspca_dev *gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300539 __u16 value,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300540 const __u8 *buffer,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300541 int len)
542{
Jean-Francois Moine60017612008-07-18 08:46:19 -0300543 PDEBUG(D_USBO, "reg_w [%02x] = %02x %02x ..",
544 value, buffer[0], buffer[1]);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300545 if (len <= sizeof gspca_dev->usb_buf) {
546 memcpy(gspca_dev->usb_buf, buffer, len);
547 usb_control_msg(gspca_dev->dev,
548 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300549 0x08,
550 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
551 value, 0,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300552 gspca_dev->usb_buf, len,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300553 500);
554 } else {
555 __u8 *tmpbuf;
556
557 tmpbuf = kmalloc(len, GFP_KERNEL);
558 memcpy(tmpbuf, buffer, len);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300559 usb_control_msg(gspca_dev->dev,
560 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300561 0x08,
562 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
563 value, 0,
564 tmpbuf, len,
565 500);
566 kfree(tmpbuf);
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300567 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300568}
569
Jean-Francois Moine60017612008-07-18 08:46:19 -0300570/* I2C write 1 byte */
571static void i2c_w1(struct gspca_dev *gspca_dev, __u8 reg, __u8 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300572{
573 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300574
Jean-Francois Moine60017612008-07-18 08:46:19 -0300575 PDEBUG(D_USBO, "i2c_w2 [%02x] = %02x", reg, val);
576 gspca_dev->usb_buf[0] = 0x81 | (2 << 4); /* = a1 */
577 gspca_dev->usb_buf[1] = sd->i2c_base;
578 gspca_dev->usb_buf[2] = reg;
579 gspca_dev->usb_buf[3] = val;
580 gspca_dev->usb_buf[4] = 0;
581 gspca_dev->usb_buf[5] = 0;
582 gspca_dev->usb_buf[6] = 0;
583 gspca_dev->usb_buf[7] = 0x10;
584 usb_control_msg(gspca_dev->dev,
585 usb_sndctrlpipe(gspca_dev->dev, 0),
586 0x08,
587 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
588 0x08, /* value = i2c */
589 0,
590 gspca_dev->usb_buf, 8,
591 500);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300592}
593
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300594/* I2C write 8 bytes */
595static void i2c_w8(struct gspca_dev *gspca_dev,
596 const __u8 *buffer)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300597{
Jean-Francois Moine60017612008-07-18 08:46:19 -0300598 memcpy(gspca_dev->usb_buf, buffer, 8);
599 usb_control_msg(gspca_dev->dev,
600 usb_sndctrlpipe(gspca_dev->dev, 0),
601 0x08,
602 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
603 0x08, 0, /* value, index */
604 gspca_dev->usb_buf, 8,
605 500);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300606}
607
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300608/* read 5 bytes in gspca_dev->usb_buf */
609static void i2c_r5(struct gspca_dev *gspca_dev, __u8 reg)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300610{
611 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300612 __u8 mode[8];
613
Hans de Goede3647fea2008-07-15 05:36:30 -0300614 mode[0] = 0x81 | 0x10;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300615 mode[1] = sd->i2c_base;
616 mode[2] = reg;
617 mode[3] = 0;
618 mode[4] = 0;
619 mode[5] = 0;
620 mode[6] = 0;
621 mode[7] = 0x10;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300622 i2c_w8(gspca_dev, mode);
Jean-Francois Moine60017612008-07-18 08:46:19 -0300623 msleep(2);
Hans de Goede3647fea2008-07-15 05:36:30 -0300624 mode[0] = 0x81 | (5 << 4) | 0x02;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300625 mode[2] = 0;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300626 i2c_w8(gspca_dev, mode);
Jean-Francois Moine60017612008-07-18 08:46:19 -0300627 msleep(2);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300628 reg_r(gspca_dev, 0x0a, 5);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300629}
630
631static int probesensor(struct gspca_dev *gspca_dev)
632{
633 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300634
Jean-Francois Moine60017612008-07-18 08:46:19 -0300635 i2c_w1(gspca_dev, 0x02, 0); /* sensor wakeup */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300636 msleep(10);
Jean-Francois Moine60017612008-07-18 08:46:19 -0300637 reg_w1(gspca_dev, 0x02, 0x66); /* Gpio on */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300638 msleep(10);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300639 i2c_r5(gspca_dev, 0); /* read sensor id */
640 if (gspca_dev->usb_buf[0] == 0x02
641 && gspca_dev->usb_buf[1] == 0x09
642 && gspca_dev->usb_buf[2] == 0x01
643 && gspca_dev->usb_buf[3] == 0x00
644 && gspca_dev->usb_buf[4] == 0x00) {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300645 PDEBUG(D_PROBE, "Find Sensor sn9c102P HV7131R");
646 sd->sensor = SENSOR_HV7131R;
647 return SENSOR_HV7131R;
648 }
Jean-Francois Moine60017612008-07-18 08:46:19 -0300649 PDEBUG(D_PROBE, "Find Sensor 0x%02x 0x%02x 0x%02x",
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300650 gspca_dev->usb_buf[0], gspca_dev->usb_buf[1],
651 gspca_dev->usb_buf[2]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300652 PDEBUG(D_PROBE, "Sensor sn9c102P Not found");
653 return -ENODEV;
654}
655
656static int configure_gpio(struct gspca_dev *gspca_dev,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300657 const __u8 *sn9c1xx)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300658{
659 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300660 const __u8 *reg9a;
661 static const __u8 reg9a_def[] =
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300662 {0x08, 0x40, 0x20, 0x10, 0x00, 0x04};
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300663 static const __u8 reg9a_sn9c325[] =
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300664 {0x0a, 0x40, 0x38, 0x30, 0x00, 0x20};
Jean-Francois Moine8f47a3c2008-07-29 14:14:04 -0300665 static const __u8 regd4[] = {0x60, 0x00, 0x00};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300666
Jean-Francois Moine60017612008-07-18 08:46:19 -0300667 reg_w1(gspca_dev, 0xf1, 0x00);
Jean-Francois Moine8f47a3c2008-07-29 14:14:04 -0300668 reg_w1(gspca_dev, 0x01, 0x00); /*jfm was sn9c1xx[1] in v1*/
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300669
670 /* configure gpio */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300671 reg_w(gspca_dev, 0x01, &sn9c1xx[1], 2);
672 reg_w(gspca_dev, 0x08, &sn9c1xx[8], 2);
Jean-Francois Moine60017612008-07-18 08:46:19 -0300673 reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5); /* jfm len was 3 */
Hans de Goede3647fea2008-07-15 05:36:30 -0300674 switch (sd->bridge) {
675 case BRIDGE_SN9C325:
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300676 reg9a = reg9a_sn9c325;
677 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300678 default:
679 reg9a = reg9a_def;
680 break;
681 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300682 reg_w(gspca_dev, 0x9a, reg9a, 6);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300683
Jean-Francois Moine8f47a3c2008-07-29 14:14:04 -0300684 reg_w(gspca_dev, 0xd4, regd4, sizeof regd4); /*fixme:jfm was 60 only*/
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300685
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300686 reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300687
Hans de Goede3647fea2008-07-15 05:36:30 -0300688 switch (sd->bridge) {
Hans de Goede3647fea2008-07-15 05:36:30 -0300689 case BRIDGE_SN9C325:
Jean-Francois Moine60017612008-07-18 08:46:19 -0300690 reg_w1(gspca_dev, 0x01, 0x43);
691 reg_w1(gspca_dev, 0x17, 0xae);
692 reg_w1(gspca_dev, 0x01, 0x42);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300693 break;
694 default:
Jean-Francois Moine60017612008-07-18 08:46:19 -0300695 reg_w1(gspca_dev, 0x01, 0x43);
696 reg_w1(gspca_dev, 0x17, 0x61);
697 reg_w1(gspca_dev, 0x01, 0x42);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300698 }
699
700 if (sd->sensor == SENSOR_HV7131R) {
701 if (probesensor(gspca_dev) < 0)
702 return -ENODEV;
703 }
704 return 0;
705}
706
707static void hv7131R_InitSensor(struct gspca_dev *gspca_dev)
708{
709 int i = 0;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300710 static const __u8 SetSensorClk[] = /* 0x08 Mclk */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300711 { 0xa1, 0x11, 0x01, 0x18, 0x00, 0x00, 0x00, 0x10 };
712
713 while (hv7131r_sensor_init[i][0]) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300714 i2c_w8(gspca_dev, hv7131r_sensor_init[i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300715 i++;
716 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300717 i2c_w8(gspca_dev, SetSensorClk);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300718}
719
720static void mi0360_InitSensor(struct gspca_dev *gspca_dev)
721{
722 int i = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300723
724 while (mi0360_sensor_init[i][0]) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300725 i2c_w8(gspca_dev, mi0360_sensor_init[i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300726 i++;
727 }
728}
729
730static void mo4000_InitSensor(struct gspca_dev *gspca_dev)
731{
732 int i = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300733
734 while (mo4000_sensor_init[i][0]) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300735 i2c_w8(gspca_dev, mo4000_sensor_init[i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300736 i++;
737 }
738}
739
740static void ov7648_InitSensor(struct gspca_dev *gspca_dev)
741{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300742 int i = 0;
743
744 while (ov7648_sensor_init[i][0]) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300745 i2c_w8(gspca_dev, ov7648_sensor_init[i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300746 i++;
747 }
748}
749
750static void ov7660_InitSensor(struct gspca_dev *gspca_dev)
751{
752 int i = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300753
Jean-Francois Moine60017612008-07-18 08:46:19 -0300754 i2c_w8(gspca_dev, ov7660_sensor_init[i]); /* reset SCCB */
755 i++;
756 msleep(20);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300757 while (ov7660_sensor_init[i][0]) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300758 i2c_w8(gspca_dev, ov7660_sensor_init[i]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300759 i++;
760 }
761}
762
763/* this function is called at probe time */
764static int sd_config(struct gspca_dev *gspca_dev,
765 const struct usb_device_id *id)
766{
767 struct sd *sd = (struct sd *) gspca_dev;
768 struct cam *cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300769
770 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300771 cam->epaddr = 0x01;
772 cam->cam_mode = vga_mode;
773 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300774
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300775 sd->bridge = id->driver_info >> 16;
776 sd->sensor = id->driver_info >> 8;
777 sd->i2c_base = id->driver_info;
778
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300779 sd->qindex = 4; /* set the quantization table */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300780 sd->brightness = BRIGHTNESS_DEF;
781 sd->contrast = CONTRAST_DEF;
782 sd->colors = COLOR_DEF;
783 sd->autogain = AUTOGAIN_DEF;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300784 sd->ag_cnt = -1;
785
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300786 return 0;
787}
788
789/* this function is called at open time */
790static int sd_open(struct gspca_dev *gspca_dev)
791{
792 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300793/* const __u8 *sn9c1xx; */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300794 __u8 regGpio[] = { 0x29, 0x74 };
Jean-Francois Moine60017612008-07-18 08:46:19 -0300795 __u8 regF1;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300796
Hans de Goede3647fea2008-07-15 05:36:30 -0300797 /* setup a selector by bridge */
Jean-Francois Moine60017612008-07-18 08:46:19 -0300798 reg_w1(gspca_dev, 0xf1, 0x01);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300799 reg_r(gspca_dev, 0x00, 1);
Jean-Francois Moine8f47a3c2008-07-29 14:14:04 -0300800 reg_w1(gspca_dev, 0xf1, gspca_dev->usb_buf[0]);
801 reg_r(gspca_dev, 0x00, 1); /* get sonix chip id */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300802 regF1 = gspca_dev->usb_buf[0];
Jean-Francois Moine8f47a3c2008-07-29 14:14:04 -0300803 PDEBUG(D_PROBE, "Sonix chip id: %02x", regF1);
Hans de Goede3647fea2008-07-15 05:36:30 -0300804 switch (sd->bridge) {
805 case BRIDGE_SN9C102P:
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300806 if (regF1 != 0x11)
807 return -ENODEV;
Jean-Francois Moine60017612008-07-18 08:46:19 -0300808 reg_w1(gspca_dev, 0x02, regGpio[1]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300809 break;
Hans de Goede3647fea2008-07-15 05:36:30 -0300810 case BRIDGE_SN9C105:
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300811 if (regF1 != 0x11)
812 return -ENODEV;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300813 reg_w(gspca_dev, 0x02, regGpio, 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300814 break;
Hans de Goede3647fea2008-07-15 05:36:30 -0300815 case BRIDGE_SN9C120:
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300816 if (regF1 != 0x12)
817 return -ENODEV;
818 regGpio[1] = 0x70;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300819 reg_w(gspca_dev, 0x02, regGpio, 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300820 break;
821 default:
Jean-Francois Moine60017612008-07-18 08:46:19 -0300822/* case BRIDGE_SN9C110: */
Hans de Goede3647fea2008-07-15 05:36:30 -0300823/* case BRIDGE_SN9C325: */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300824 if (regF1 != 0x12)
825 return -ENODEV;
Jean-Francois Moine60017612008-07-18 08:46:19 -0300826 reg_w1(gspca_dev, 0x02, 0x62);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300827 break;
828 }
829
Jean-Francois Moine60017612008-07-18 08:46:19 -0300830 reg_w1(gspca_dev, 0xf1, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300831
832 return 0;
833}
834
835static unsigned int setexposure(struct gspca_dev *gspca_dev,
836 unsigned int expo)
837{
838 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300839 static const __u8 doit[] = /* update sensor */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300840 { 0xb1, 0x5d, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10 };
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300841 static const __u8 sensorgo[] = /* sensor on */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300842 { 0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10 };
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300843 static const __u8 gainMo[] =
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300844 { 0xa1, 0x21, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1d };
845
846 switch (sd->sensor) {
847 case SENSOR_HV7131R: {
848 __u8 Expodoit[] =
849 { 0xc1, 0x11, 0x25, 0x07, 0x27, 0xc0, 0x00, 0x16 };
850
851 Expodoit[3] = expo >> 16;
852 Expodoit[4] = expo >> 8;
853 Expodoit[5] = expo;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300854 i2c_w8(gspca_dev, Expodoit);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300855 break;
856 }
857 case SENSOR_MI0360: {
858 __u8 expoMi[] = /* exposure 0x0635 -> 4 fp/s 0x10 */
859 { 0xb1, 0x5d, 0x09, 0x06, 0x35, 0x00, 0x00, 0x16 };
860
861 if (expo > 0x0635)
862 expo = 0x0635;
863 else if (expo < 0x0001)
864 expo = 0x0001;
865 expoMi[3] = expo >> 8;
866 expoMi[4] = expo;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300867 i2c_w8(gspca_dev, expoMi);
868 i2c_w8(gspca_dev, doit);
869 i2c_w8(gspca_dev, sensorgo);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300870 break;
871 }
872 case SENSOR_MO4000: {
873 __u8 expoMof[] =
874 { 0xa1, 0x21, 0x0f, 0x20, 0x00, 0x00, 0x00, 0x10 };
875 __u8 expoMo10[] =
876 { 0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10 };
877
878 if (expo > 0x1fff)
879 expo = 0x1fff;
880 else if (expo < 0x0001)
881 expo = 0x0001;
882 expoMof[3] = (expo & 0x03fc) >> 2;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300883 i2c_w8(gspca_dev, expoMof);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300884 expoMo10[3] = ((expo & 0x1c00) >> 10)
885 | ((expo & 0x0003) << 4);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300886 i2c_w8(gspca_dev, expoMo10);
887 i2c_w8(gspca_dev, gainMo);
Jean-Francois Moine956e42d2008-07-01 10:03:42 -0300888 PDEBUG(D_CONF, "set exposure %d",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300889 ((expoMo10[3] & 0x07) << 10)
890 | (expoMof[3] << 2)
891 | ((expoMo10[3] & 0x30) >> 4));
892 break;
893 }
894 }
895 return expo;
896}
897
898static void setbrightness(struct gspca_dev *gspca_dev)
899{
900 struct sd *sd = (struct sd *) gspca_dev;
901 unsigned int expo;
902 __u8 k2;
903
904 switch (sd->sensor) {
905 case SENSOR_HV7131R:
906 expo = sd->brightness << 4;
907 if (expo > 0x002dc6c0)
908 expo = 0x002dc6c0;
909 else if (expo < 0x02a0)
910 expo = 0x02a0;
911 sd->exposure = setexposure(gspca_dev, expo);
912 break;
913 case SENSOR_MI0360:
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300914 case SENSOR_MO4000:
915 expo = sd->brightness >> 4;
916 sd->exposure = setexposure(gspca_dev, expo);
917 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300918 }
919
920 k2 = sd->brightness >> 10;
Jean-Francois Moine60017612008-07-18 08:46:19 -0300921 reg_w1(gspca_dev, 0x96, k2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300922}
923
924static void setcontrast(struct gspca_dev *gspca_dev)
925{
926 struct sd *sd = (struct sd *) gspca_dev;
927 __u8 k2;
928 __u8 contrast[] = { 0x00, 0x00, 0x28, 0x00, 0x07, 0x00 };
929
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300930 k2 = sd->contrast;
931 contrast[2] = k2;
932 contrast[0] = (k2 + 1) >> 1;
933 contrast[4] = (k2 + 1) / 5;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300934 reg_w(gspca_dev, 0x84, contrast, 6);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300935}
936
937static void setcolors(struct gspca_dev *gspca_dev)
938{
939 struct sd *sd = (struct sd *) gspca_dev;
940 __u8 data;
941 int colour;
942
943 colour = sd->colors - 128;
944 if (colour > 0)
945 data = (colour + 32) & 0x7f; /* blue */
946 else
947 data = (-colour + 32) & 0x7f; /* red */
Jean-Francois Moine60017612008-07-18 08:46:19 -0300948 reg_w1(gspca_dev, 0x05, data);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300949}
950
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300951static void setautogain(struct gspca_dev *gspca_dev)
952{
953 struct sd *sd = (struct sd *) gspca_dev;
954
955 switch (sd->sensor) {
956 case SENSOR_HV7131R:
957 case SENSOR_MO4000:
958 case SENSOR_MI0360:
959 if (sd->autogain)
960 sd->ag_cnt = AG_CNT_START;
961 else
962 sd->ag_cnt = -1;
963 break;
964 }
965}
966
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300967/* -- start the camera -- */
968static void sd_start(struct gspca_dev *gspca_dev)
969{
970 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300971 int i;
Jean-Francois Moine8f47a3c2008-07-29 14:14:04 -0300972 __u8 reg1, reg17, reg18;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300973 const __u8 *sn9c1xx;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300974 int mode;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300975 static const __u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f };
976 static const __u8 CA[] = { 0x28, 0xd8, 0x14, 0xec };
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300977 static const __u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd }; /* MI0360 */
978 static const __u8 CE_sn9c325[] =
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300979 { 0x32, 0xdd, 0x32, 0xdd }; /* OV7648 - SN9C325 */
980
981 sn9c1xx = sn_tb[(int) sd->sensor];
982 configure_gpio(gspca_dev, sn9c1xx);
983
Jean-Francois Moine8f47a3c2008-07-29 14:14:04 -0300984/* reg_w1(gspca_dev, 0x01, 0x44); jfm from win trace*/
Jean-Francois Moine60017612008-07-18 08:46:19 -0300985 reg_w1(gspca_dev, 0x15, sn9c1xx[0x15]);
986 reg_w1(gspca_dev, 0x16, sn9c1xx[0x16]);
987 reg_w1(gspca_dev, 0x12, sn9c1xx[0x12]);
988 reg_w1(gspca_dev, 0x13, sn9c1xx[0x13]);
989 reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]);
990 reg_w1(gspca_dev, 0xd2, 0x6a); /* DC29 */
991 reg_w1(gspca_dev, 0xd3, 0x50);
992 reg_w1(gspca_dev, 0xc6, 0x00);
993 reg_w1(gspca_dev, 0xc7, 0x00);
994 reg_w1(gspca_dev, 0xc8, 0x50);
995 reg_w1(gspca_dev, 0xc9, 0x3c);
Jean-Francois Moine60017612008-07-18 08:46:19 -0300996 reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]);
Jean-Francois Moine568788a2008-07-15 11:46:06 -0300997 switch (sd->bridge) {
998 case BRIDGE_SN9C325:
Jean-Francois Moine8f47a3c2008-07-29 14:14:04 -0300999 reg17 = 0xae;
Jean-Francois Moine568788a2008-07-15 11:46:06 -03001000 break;
1001 default:
Jean-Francois Moine8f47a3c2008-07-29 14:14:04 -03001002 reg17 = 0x60;
Jean-Francois Moine568788a2008-07-15 11:46:06 -03001003 break;
1004 }
Jean-Francois Moine8f47a3c2008-07-29 14:14:04 -03001005 reg_w1(gspca_dev, 0x17, reg17);
Jean-Francois Moine60017612008-07-18 08:46:19 -03001006 reg_w1(gspca_dev, 0x05, sn9c1xx[5]);
1007 reg_w1(gspca_dev, 0x07, sn9c1xx[7]);
1008 reg_w1(gspca_dev, 0x06, sn9c1xx[6]);
1009 reg_w1(gspca_dev, 0x14, sn9c1xx[0x14]);
Jean-Francois Moine568788a2008-07-15 11:46:06 -03001010 switch (sd->bridge) {
1011 case BRIDGE_SN9C325:
1012 reg_w(gspca_dev, 0x20, regsn20_sn9c325,
1013 sizeof regsn20_sn9c325);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001014 for (i = 0; i < 8; i++)
Jean-Francois Moine568788a2008-07-15 11:46:06 -03001015 reg_w(gspca_dev, 0x84, reg84_sn9c325,
1016 sizeof reg84_sn9c325);
Jean-Francois Moine60017612008-07-18 08:46:19 -03001017 reg_w1(gspca_dev, 0x9a, 0x0a);
1018 reg_w1(gspca_dev, 0x99, 0x60);
Jean-Francois Moine568788a2008-07-15 11:46:06 -03001019 break;
Jean-Francois Moine568788a2008-07-15 11:46:06 -03001020 default:
1021 reg_w(gspca_dev, 0x20, regsn20, sizeof regsn20);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001022 for (i = 0; i < 8; i++)
Jean-Francois Moine568788a2008-07-15 11:46:06 -03001023 reg_w(gspca_dev, 0x84, reg84, sizeof reg84);
Jean-Francois Moine60017612008-07-18 08:46:19 -03001024 reg_w1(gspca_dev, 0x9a, 0x08);
1025 reg_w1(gspca_dev, 0x99, 0x59);
Jean-Francois Moine568788a2008-07-15 11:46:06 -03001026 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001027 }
1028
Jean-Francois Moinec2446b32008-07-05 11:49:20 -03001029 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Jean-Francois Moine60017612008-07-18 08:46:19 -03001030 if (mode)
1031 reg1 = 0x46; /* 320 clk 48Mhz */
1032 else
1033 reg1 = 0x06; /* 640 clk 24Mz */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001034 reg17 = 0x61;
1035 switch (sd->sensor) {
1036 case SENSOR_HV7131R:
1037 hv7131R_InitSensor(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001038 break;
1039 case SENSOR_MI0360:
1040 mi0360_InitSensor(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001041 break;
1042 case SENSOR_MO4000:
1043 mo4000_InitSensor(gspca_dev);
1044 if (mode) {
1045/* reg1 = 0x46; * 320 clk 48Mhz 60fp/s */
1046 reg1 = 0x06; /* clk 24Mz */
1047 } else {
1048 reg17 = 0x22; /* 640 MCKSIZE */
Jean-Francois Moine60017612008-07-18 08:46:19 -03001049/* reg1 = 0x06; * 640 clk 24Mz (done) */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001050 }
1051 break;
1052 case SENSOR_OV7648:
Jean-Francois Moine60017612008-07-18 08:46:19 -03001053 ov7648_InitSensor(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001054 reg17 = 0xa2;
1055 reg1 = 0x44;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001056/* if (mode)
1057 ; * 320x2...
1058 else
1059 ; * 640x... */
1060 break;
1061 default:
1062/* case SENSOR_OV7660: */
1063 ov7660_InitSensor(gspca_dev);
1064 if (mode) {
1065/* reg17 = 0x21; * 320 */
1066/* reg1 = 0x44; */
Jean-Francois Moine60017612008-07-18 08:46:19 -03001067/* reg1 = 0x46; (done) */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001068 } else {
Jean-Francois Moine8f47a3c2008-07-29 14:14:04 -03001069 reg17 = 0x22; /* 640 MCKSIZE */
1070 reg1 = 0x06;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001071 }
1072 break;
1073 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001074 reg_w(gspca_dev, 0xc0, C0, 6);
Jean-Francois Moine8f47a3c2008-07-29 14:14:04 -03001075 reg_w(gspca_dev, 0xca, CA, 4);
Hans de Goede3647fea2008-07-15 05:36:30 -03001076 switch (sd->bridge) {
Hans de Goede3647fea2008-07-15 05:36:30 -03001077 case BRIDGE_SN9C325:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001078 reg_w(gspca_dev, 0xce, CE_sn9c325, 4);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001079 break;
1080 default:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001081 reg_w(gspca_dev, 0xce, CE, 4);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001082 /* ?? {0x1e, 0xdd, 0x2d, 0xe7} */
1083 break;
1084 }
1085
1086 /* here change size mode 0 -> VGA; 1 -> CIF */
Jean-Francois Moine8f47a3c2008-07-29 14:14:04 -03001087 reg18 = sn9c1xx[0x18] | (mode << 4);
1088 reg_w1(gspca_dev, 0x18, reg18 | 0x40);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001089
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001090 reg_w(gspca_dev, 0x100, qtable4, 0x40);
1091 reg_w(gspca_dev, 0x140, qtable4 + 0x40, 0x40);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001092
Jean-Francois Moine8f47a3c2008-07-29 14:14:04 -03001093 reg_w1(gspca_dev, 0x18, reg18);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001094
Jean-Francois Moine60017612008-07-18 08:46:19 -03001095 reg_w1(gspca_dev, 0x17, reg17);
1096 reg_w1(gspca_dev, 0x01, reg1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001097 setbrightness(gspca_dev);
1098 setcontrast(gspca_dev);
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -03001099 setautogain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001100}
1101
1102static void sd_stopN(struct gspca_dev *gspca_dev)
1103{
1104 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001105 static const __u8 stophv7131[] =
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001106 { 0xa1, 0x11, 0x02, 0x09, 0x00, 0x00, 0x00, 0x10 };
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001107 static const __u8 stopmi0360[] =
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001108 { 0xb1, 0x5d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10 };
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001109 __u8 data;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001110 const __u8 *sn9c1xx;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001111
1112 data = 0x0b;
1113 switch (sd->sensor) {
1114 case SENSOR_HV7131R:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001115 i2c_w8(gspca_dev, stophv7131);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001116 data = 0x2b;
1117 break;
1118 case SENSOR_MI0360:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001119 i2c_w8(gspca_dev, stopmi0360);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001120 data = 0x29;
1121 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001122 case SENSOR_OV7648:
1123 data = 0x29;
1124 break;
1125 default:
Jean-Francois Moine8f47a3c2008-07-29 14:14:04 -03001126/* case SENSOR_MO4000: */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001127/* case SENSOR_OV7660: */
1128 break;
1129 }
1130 sn9c1xx = sn_tb[(int) sd->sensor];
Jean-Francois Moine60017612008-07-18 08:46:19 -03001131 reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
1132 reg_w1(gspca_dev, 0x17, sn9c1xx[0x17]);
1133 reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
1134 reg_w1(gspca_dev, 0x01, data);
1135 reg_w1(gspca_dev, 0xf1, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001136}
1137
1138static void sd_stop0(struct gspca_dev *gspca_dev)
1139{
1140}
1141
1142static void sd_close(struct gspca_dev *gspca_dev)
1143{
1144}
1145
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -03001146static void do_autogain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001147{
1148 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001149 int delta;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -03001150 int expotimes;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001151 __u8 luma_mean = 130;
1152 __u8 luma_delta = 20;
1153
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -03001154 /* Thanks S., without your advice, autobright should not work :) */
1155 if (sd->ag_cnt < 0)
1156 return;
1157 if (--sd->ag_cnt >= 0)
1158 return;
1159 sd->ag_cnt = AG_CNT_START;
1160
1161 delta = atomic_read(&sd->avg_lum);
1162 PDEBUG(D_FRAM, "mean lum %d", delta);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001163 if (delta < luma_mean - luma_delta ||
1164 delta > luma_mean + luma_delta) {
1165 switch (sd->sensor) {
1166 case SENSOR_HV7131R:
1167 expotimes = sd->exposure >> 8;
1168 expotimes += (luma_mean - delta) >> 4;
1169 if (expotimes < 0)
1170 expotimes = 0;
1171 sd->exposure = setexposure(gspca_dev,
1172 (unsigned int) (expotimes << 8));
1173 break;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -03001174 default:
1175/* case SENSOR_MO4000: */
1176/* case SENSOR_MI0360: */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001177 expotimes = sd->exposure;
1178 expotimes += (luma_mean - delta) >> 6;
1179 if (expotimes < 0)
1180 expotimes = 0;
1181 sd->exposure = setexposure(gspca_dev,
1182 (unsigned int) expotimes);
1183 setcolors(gspca_dev);
1184 break;
1185 }
1186 }
1187}
1188
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -03001189/* scan the URB packets */
1190/* This function is run at interrupt level. */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001191static void sd_pkt_scan(struct gspca_dev *gspca_dev,
1192 struct gspca_frame *frame, /* target */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001193 __u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001194 int len) /* iso packet length */
1195{
1196 struct sd *sd = (struct sd *) gspca_dev;
1197 int sof, avg_lum;
1198
1199 sof = len - 64;
1200 if (sof >= 0 && data[sof] == 0xff && data[sof + 1] == 0xd9) {
1201
1202 /* end of frame */
1203 gspca_frame_add(gspca_dev, LAST_PACKET,
1204 frame, data, sof + 2);
1205 if (sd->ag_cnt < 0)
1206 return;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001207/* w1 w2 w3 */
1208/* w4 w5 w6 */
1209/* w7 w8 */
1210/* w4 */
1211 avg_lum = ((data[sof + 29] << 8) | data[sof + 30]) >> 6;
1212/* w6 */
1213 avg_lum += ((data[sof + 33] << 8) | data[sof + 34]) >> 6;
1214/* w2 */
1215 avg_lum += ((data[sof + 25] << 8) | data[sof + 26]) >> 6;
1216/* w8 */
1217 avg_lum += ((data[sof + 37] << 8) | data[sof + 38]) >> 6;
1218/* w5 */
1219 avg_lum += ((data[sof + 31] << 8) | data[sof + 32]) >> 4;
1220 avg_lum >>= 4;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -03001221 atomic_set(&sd->avg_lum, avg_lum);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001222 return;
1223 }
1224 if (gspca_dev->last_packet_type == LAST_PACKET) {
1225
1226 /* put the JPEG 422 header */
1227 jpeg_put_header(gspca_dev, frame, sd->qindex, 0x21);
1228 }
1229 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
1230}
1231
1232static unsigned int getexposure(struct gspca_dev *gspca_dev)
1233{
1234 struct sd *sd = (struct sd *) gspca_dev;
1235 __u8 hexpo, mexpo, lexpo;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001236
1237 switch (sd->sensor) {
1238 case SENSOR_HV7131R:
1239 /* read sensor exposure */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001240 i2c_r5(gspca_dev, 0x25);
1241 return (gspca_dev->usb_buf[0] << 16)
1242 | (gspca_dev->usb_buf[1] << 8)
1243 | gspca_dev->usb_buf[2];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001244 case SENSOR_MI0360:
1245 /* read sensor exposure */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001246 i2c_r5(gspca_dev, 0x09);
1247 return (gspca_dev->usb_buf[0] << 8)
1248 | gspca_dev->usb_buf[1];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001249 case SENSOR_MO4000:
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001250 i2c_r5(gspca_dev, 0x0e);
1251 hexpo = 0; /* gspca_dev->usb_buf[1] & 0x07; */
1252 mexpo = 0x40; /* gspca_dev->usb_buf[2] & 0xff; */
1253 lexpo = (gspca_dev->usb_buf[1] & 0x30) >> 4;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001254 PDEBUG(D_CONF, "exposure %d",
1255 (hexpo << 10) | (mexpo << 2) | lexpo);
1256 return (hexpo << 10) | (mexpo << 2) | lexpo;
1257 default:
Jean-Francois Moine8f47a3c2008-07-29 14:14:04 -03001258/* case SENSOR_OV7648: * jfm: is it ok for 7648? */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001259/* case SENSOR_OV7660: */
1260 /* read sensor exposure */
Jean-Francois Moine739570b2008-07-14 09:38:29 -03001261 i2c_r5(gspca_dev, 0x04);
1262 hexpo = gspca_dev->usb_buf[3] & 0x2f;
1263 lexpo = gspca_dev->usb_buf[0] & 0x02;
1264 i2c_r5(gspca_dev, 0x08);
1265 mexpo = gspca_dev->usb_buf[2];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001266 return (hexpo << 10) | (mexpo << 2) | lexpo;
1267 }
1268}
1269
1270static void getbrightness(struct gspca_dev *gspca_dev)
1271{
1272 struct sd *sd = (struct sd *) gspca_dev;
1273
1274 /* hardcoded registers seem not readable */
1275 switch (sd->sensor) {
1276 case SENSOR_HV7131R:
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001277 sd->brightness = getexposure(gspca_dev) >> 4;
1278 break;
1279 case SENSOR_MI0360:
1280 sd->brightness = getexposure(gspca_dev) << 4;
1281 break;
1282 case SENSOR_MO4000:
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001283 sd->brightness = getexposure(gspca_dev) << 4;
1284 break;
1285 }
1286}
1287
1288static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1289{
1290 struct sd *sd = (struct sd *) gspca_dev;
1291
1292 sd->brightness = val;
1293 if (gspca_dev->streaming)
1294 setbrightness(gspca_dev);
1295 return 0;
1296}
1297
1298static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1299{
1300 struct sd *sd = (struct sd *) gspca_dev;
1301
1302 getbrightness(gspca_dev);
1303 *val = sd->brightness;
1304 return 0;
1305}
1306
1307static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
1308{
1309 struct sd *sd = (struct sd *) gspca_dev;
1310
1311 sd->contrast = val;
1312 if (gspca_dev->streaming)
1313 setcontrast(gspca_dev);
1314 return 0;
1315}
1316
1317static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
1318{
1319 struct sd *sd = (struct sd *) gspca_dev;
1320
1321 *val = sd->contrast;
1322 return 0;
1323}
1324
1325static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
1326{
1327 struct sd *sd = (struct sd *) gspca_dev;
1328
1329 sd->colors = val;
1330 if (gspca_dev->streaming)
1331 setcolors(gspca_dev);
1332 return 0;
1333}
1334
1335static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
1336{
1337 struct sd *sd = (struct sd *) gspca_dev;
1338
1339 *val = sd->colors;
1340 return 0;
1341}
1342
1343static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1344{
1345 struct sd *sd = (struct sd *) gspca_dev;
1346
1347 sd->autogain = val;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -03001348 if (gspca_dev->streaming)
1349 setautogain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001350 return 0;
1351}
1352
1353static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1354{
1355 struct sd *sd = (struct sd *) gspca_dev;
1356
1357 *val = sd->autogain;
1358 return 0;
1359}
1360
1361/* sub-driver description */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001362static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001363 .name = MODULE_NAME,
1364 .ctrls = sd_ctrls,
1365 .nctrls = ARRAY_SIZE(sd_ctrls),
1366 .config = sd_config,
1367 .open = sd_open,
1368 .start = sd_start,
1369 .stopN = sd_stopN,
1370 .stop0 = sd_stop0,
1371 .close = sd_close,
1372 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -03001373 .dq_callback = do_autogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001374};
1375
1376/* -- module initialisation -- */
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001377#define BSI(bridge, sensor, i2c_addr) \
1378 .driver_info = (BRIDGE_ ## bridge << 16) \
1379 | (SENSOR_ ## sensor << 8) \
1380 | (i2c_addr)
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001381static const __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001382#ifndef CONFIG_USB_SN9C102
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001383 {USB_DEVICE(0x0458, 0x7025), BSI(SN9C120, MI0360, 0x5d)},
1384 {USB_DEVICE(0x045e, 0x00f5), BSI(SN9C105, OV7660, 0x21)},
1385 {USB_DEVICE(0x045e, 0x00f7), BSI(SN9C105, OV7660, 0x21)},
1386 {USB_DEVICE(0x0471, 0x0327), BSI(SN9C105, MI0360, 0x5d)},
1387 {USB_DEVICE(0x0471, 0x0328), BSI(SN9C105, MI0360, 0x5d)},
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001388#endif
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001389 {USB_DEVICE(0x0471, 0x0330), BSI(SN9C105, MI0360, 0x5d)},
1390 {USB_DEVICE(0x0c45, 0x6040), BSI(SN9C102P, HV7131R, 0x11)},
1391/* bw600.inf:
1392 {USB_DEVICE(0x0c45, 0x6040), BSI(SN9C102P, MI0360, 0x5d)}, */
1393/* {USB_DEVICE(0x0c45, 0x603a), BSI(SN9C102P, OV7648, 0x??)}, */
1394/* {USB_DEVICE(0x0c45, 0x607a), BSI(SN9C102P, OV7648, 0x??)}, */
1395 {USB_DEVICE(0x0c45, 0x607c), BSI(SN9C102P, HV7131R, 0x11)},
1396/* {USB_DEVICE(0x0c45, 0x607e), BSI(SN9C102P, OV7630, 0x??)}, */
1397 {USB_DEVICE(0x0c45, 0x60c0), BSI(SN9C105, MI0360, 0x5d)},
1398/* {USB_DEVICE(0x0c45, 0x60c8), BSI(SN9C105, OM6801, 0x??)}, */
1399/* {USB_DEVICE(0x0c45, 0x60cc), BSI(SN9C105, HV7131GP, 0x??)}, */
1400 {USB_DEVICE(0x0c45, 0x60ec), BSI(SN9C105, MO4000, 0x21)},
1401/* {USB_DEVICE(0x0c45, 0x60ef), BSI(SN9C105, ICM105C, 0x??)}, */
1402/* {USB_DEVICE(0x0c45, 0x60fa), BSI(SN9C105, OV7648, 0x??)}, */
1403 {USB_DEVICE(0x0c45, 0x60fb), BSI(SN9C105, OV7660, 0x21)},
1404 {USB_DEVICE(0x0c45, 0x60fc), BSI(SN9C105, HV7131R, 0x11)},
1405/* {USB_DEVICE(0x0c45, 0x60fe), BSI(SN9C105, OV7630, 0x??)}, */
1406/* {USB_DEVICE(0x0c45, 0x6108), BSI(SN9C120, OM6801, 0x??)}, */
1407/* {USB_DEVICE(0x0c45, 0x6122), BSI(SN9C110, ICM105C, 0x??)}, */
1408/* {USB_DEVICE(0x0c45, 0x6123), BSI(SN9C110, SanyoCCD, 0x??)}, */
1409 {USB_DEVICE(0x0c45, 0x612a), BSI(SN9C325, OV7648, 0x21)},
1410/* bw600.inf:
1411 {USB_DEVICE(0x0c45, 0x612a), BSI(SN9C110, OV7648, 0x21)}, */
1412 {USB_DEVICE(0x0c45, 0x612c), BSI(SN9C110, MO4000, 0x21)},
1413/* {USB_DEVICE(0x0c45, 0x612e), BSI(SN9C110, OV7630, 0x??)}, */
1414/* {USB_DEVICE(0x0c45, 0x612f), BSI(SN9C110, ICM105C, 0x??)}, */
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001415#ifndef CONFIG_USB_SN9C102
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001416 {USB_DEVICE(0x0c45, 0x6130), BSI(SN9C120, MI0360, 0x5d)},
1417 {USB_DEVICE(0x0c45, 0x6138), BSI(SN9C120, MO4000, 0x21)},
1418/* {USB_DEVICE(0x0c45, 0x613a), BSI(SN9C120, OV7648, 0x??)}, */
1419 {USB_DEVICE(0x0c45, 0x613b), BSI(SN9C120, OV7660, 0x21)},
1420 {USB_DEVICE(0x0c45, 0x613c), BSI(SN9C120, HV7131R, 0x11)},
1421/* {USB_DEVICE(0x0c45, 0x613e), BSI(SN9C120, OV7630, 0x??)}, */
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001422#endif
Jean-Francois Moinee546f4b2008-07-26 03:43:59 -03001423 {USB_DEVICE(0x0c45, 0x6143), BSI(SN9C120, MI0360, 0x5d)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001424 {}
1425};
1426MODULE_DEVICE_TABLE(usb, device_table);
1427
1428/* -- device connect -- */
1429static int sd_probe(struct usb_interface *intf,
1430 const struct usb_device_id *id)
1431{
1432 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1433 THIS_MODULE);
1434}
1435
1436static struct usb_driver sd_driver = {
1437 .name = MODULE_NAME,
1438 .id_table = device_table,
1439 .probe = sd_probe,
1440 .disconnect = gspca_disconnect,
1441};
1442
1443/* -- module insert / remove -- */
1444static int __init sd_mod_init(void)
1445{
1446 if (usb_register(&sd_driver) < 0)
1447 return -1;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -03001448 info("registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001449 return 0;
1450}
1451static void __exit sd_mod_exit(void)
1452{
1453 usb_deregister(&sd_driver);
1454 info("deregistered");
1455}
1456
1457module_init(sd_mod_init);
1458module_exit(sd_mod_exit);