1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Driver for the s5k4aa sensor
4 *
5 * Copyright (C) 2008 Erik Andrén
6 * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
7 * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
8 *
9 * Portions of code to USB interface and ALi driver software,
10 * Copyright (c) 2006 Willem Duinker
11 * v4l2 interface modeled after the V4L2 driver
12 * for SN9C10x PC Camera Controllers
13 */
14
15 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
16
17 #include "m5602_s5k4aa.h"
18
19 static const unsigned char preinit_s5k4aa[][4] = {
20 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
21 {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
22 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
23 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
24 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
25 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00},
26 {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00},
27
28 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
29 {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
30 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
31 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
32 {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
33 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
34 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
35 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
36 {BRIDGE, M5602_XB_GPIO_DAT, 0x00, 0x00},
37 {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
38 {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
39 {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
40 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
41 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
42 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
43 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00},
44
45 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
46 {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
47 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
48 {BRIDGE, M5602_XB_GPIO_DAT, 0x14, 0x00},
49 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
50 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
51 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
52 {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00},
53 {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
54 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
55 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
56 {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
57 {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
58
59 {SENSOR, S5K4AA_PAGE_MAP, 0x00, 0x00}
60 };
61
62 static const unsigned char init_s5k4aa[][4] = {
63 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
64 {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
65 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
66 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
67 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
68 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00},
69 {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00},
70
71 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
72 {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
73 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
74 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
75 {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
76 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
77 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
78 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
79 {BRIDGE, M5602_XB_GPIO_DAT, 0x00, 0x00},
80 {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
81 {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
82 {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
83 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
84 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
85 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
86 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00},
87
88 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
89 {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
90 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
91 {BRIDGE, M5602_XB_GPIO_DAT, 0x14, 0x00},
92 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
93 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
94 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
95 {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00},
96 {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
97 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
98 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
99 {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
100 {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
101
102 {SENSOR, S5K4AA_PAGE_MAP, 0x07, 0x00},
103 {SENSOR, 0x36, 0x01, 0x00},
104 {SENSOR, S5K4AA_PAGE_MAP, 0x00, 0x00},
105 {SENSOR, 0x7b, 0xff, 0x00},
106 {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
107 {SENSOR, 0x0c, 0x05, 0x00},
108 {SENSOR, 0x02, 0x0e, 0x00},
109 {SENSOR, S5K4AA_READ_MODE, 0xa0, 0x00},
110 {SENSOR, 0x37, 0x00, 0x00},
111 };
112
113 static const unsigned char VGA_s5k4aa[][4] = {
114 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
115 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
116 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
117 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00},
118 {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
119 {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
120 {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
121 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
122 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
123 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
124 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
125 /* VSYNC_PARA, VSYNC_PARA : img height 480 = 0x01e0 */
126 {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
127 {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0, 0x00},
128 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
129 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
130 {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
131 {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
132 {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
133 {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
134 /* HSYNC_PARA, HSYNC_PARA : img width 640 = 0x0280 */
135 {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
136 {BRIDGE, M5602_XB_HSYNC_PARA, 0x80, 0x00},
137 {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
138 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
139 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, /* 48 MHz */
140
141 {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
142 {SENSOR, S5K4AA_READ_MODE, S5K4AA_RM_H_FLIP | S5K4AA_RM_ROW_SKIP_2X
143 | S5K4AA_RM_COL_SKIP_2X, 0x00},
144 /* 0x37 : Fix image stability when light is too bright and improves
145 * image quality in 640x480, but worsens it in 1280x1024 */
146 {SENSOR, 0x37, 0x01, 0x00},
147 /* ROWSTART_HI, ROWSTART_LO : 10 + (1024-960)/2 = 42 = 0x002a */
148 {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00},
149 {SENSOR, S5K4AA_ROWSTART_LO, 0x29, 0x00},
150 {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00},
151 {SENSOR, S5K4AA_COLSTART_LO, 0x0c, 0x00},
152 /* window_height_hi, window_height_lo : 960 = 0x03c0 */
153 {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x03, 0x00},
154 {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0xc0, 0x00},
155 /* window_width_hi, window_width_lo : 1280 = 0x0500 */
156 {SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00},
157 {SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x00, 0x00},
158 {SENSOR, S5K4AA_H_BLANK_HI__, 0x00, 0x00},
159 {SENSOR, S5K4AA_H_BLANK_LO__, 0xa8, 0x00}, /* helps to sync... */
160 {SENSOR, S5K4AA_EXPOSURE_HI, 0x01, 0x00},
161 {SENSOR, S5K4AA_EXPOSURE_LO, 0x00, 0x00},
162 {SENSOR, 0x11, 0x04, 0x00},
163 {SENSOR, 0x12, 0xc3, 0x00},
164 {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
165 {SENSOR, 0x02, 0x0e, 0x00},
166 };
167
168 static const unsigned char SXGA_s5k4aa[][4] = {
169 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
170 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
171 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
172 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00},
173 {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
174 {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
175 {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
176 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
177 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
178 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
179 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
180 /* VSYNC_PARA, VSYNC_PARA : img height 1024 = 0x0400 */
181 {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
182 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
183 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
184 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
185 {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
186 {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
187 {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
188 {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
189 /* HSYNC_PARA, HSYNC_PARA : img width 1280 = 0x0500 */
190 {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00},
191 {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
192 {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
193 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
194 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, /* 48 MHz */
195
196 {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
197 {SENSOR, S5K4AA_READ_MODE, S5K4AA_RM_H_FLIP, 0x00},
198 {SENSOR, 0x37, 0x01, 0x00},
199 {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00},
200 {SENSOR, S5K4AA_ROWSTART_LO, 0x09, 0x00},
201 {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00},
202 {SENSOR, S5K4AA_COLSTART_LO, 0x0a, 0x00},
203 {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x04, 0x00},
204 {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0x00, 0x00},
205 {SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00},
206 {SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x00, 0x00},
207 {SENSOR, S5K4AA_H_BLANK_HI__, 0x01, 0x00},
208 {SENSOR, S5K4AA_H_BLANK_LO__, 0xa8, 0x00},
209 {SENSOR, S5K4AA_EXPOSURE_HI, 0x01, 0x00},
210 {SENSOR, S5K4AA_EXPOSURE_LO, 0x00, 0x00},
211 {SENSOR, 0x11, 0x04, 0x00},
212 {SENSOR, 0x12, 0xc3, 0x00},
213 {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
214 {SENSOR, 0x02, 0x0e, 0x00},
215 };
216
217
218 static int s5k4aa_s_ctrl(struct v4l2_ctrl *ctrl);
219 static void s5k4aa_dump_registers(struct sd *sd);
220
221 static const struct v4l2_ctrl_ops s5k4aa_ctrl_ops = {
222 .s_ctrl = s5k4aa_s_ctrl,
223 };
224
225 static
226 const
227 struct dmi_system_id s5k4aa_vflip_dmi_table[] = {
228 {
229 .ident = "BRUNEINIT",
230 .matches = {
231 DMI_MATCH(DMI_SYS_VENDOR, "BRUNENIT"),
232 DMI_MATCH(DMI_PRODUCT_NAME, "BRUNENIT"),
233 DMI_MATCH(DMI_BOARD_VERSION, "00030D0000000001")
234 }
235 }, {
236 .ident = "Fujitsu-Siemens Amilo Xa 2528",
237 .matches = {
238 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
239 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528")
240 }
241 }, {
242 .ident = "Fujitsu-Siemens Amilo Xi 2428",
243 .matches = {
244 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
245 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2428")
246 }
247 }, {
248 .ident = "Fujitsu-Siemens Amilo Xi 2528",
249 .matches = {
250 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
251 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2528")
252 }
253 }, {
254 .ident = "Fujitsu-Siemens Amilo Xi 2550",
255 .matches = {
256 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
257 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550")
258 }
259 }, {
260 .ident = "Fujitsu-Siemens Amilo Pa 2548",
261 .matches = {
262 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
263 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2548")
264 }
265 }, {
266 .ident = "Fujitsu-Siemens Amilo Pi 2530",
267 .matches = {
268 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
269 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 2530")
270 }
271 }, {
272 .ident = "MSI GX700",
273 .matches = {
274 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
275 DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
276 DMI_MATCH(DMI_BIOS_DATE, "12/02/2008")
277 }
278 }, {
279 .ident = "MSI GX700",
280 .matches = {
281 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
282 DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
283 DMI_MATCH(DMI_BIOS_DATE, "07/26/2007")
284 }
285 }, {
286 .ident = "MSI GX700",
287 .matches = {
288 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
289 DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
290 DMI_MATCH(DMI_BIOS_DATE, "07/19/2007")
291 }
292 }, {
293 .ident = "MSI GX700/GX705/EX700",
294 .matches = {
295 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
296 DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700")
297 }
298 }, {
299 .ident = "MSI L735",
300 .matches = {
301 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
302 DMI_MATCH(DMI_PRODUCT_NAME, "MS-1717X")
303 }
304 }, {
305 .ident = "Lenovo Y300",
306 .matches = {
307 DMI_MATCH(DMI_SYS_VENDOR, "L3000 Y300"),
308 DMI_MATCH(DMI_PRODUCT_NAME, "Y300")
309 }
310 },
311 { }
312 };
313
314 static struct v4l2_pix_format s5k4aa_modes[] = {
315 {
316 640,
317 480,
318 V4L2_PIX_FMT_SBGGR8,
319 V4L2_FIELD_NONE,
320 .sizeimage =
321 640 * 480,
322 .bytesperline = 640,
323 .colorspace = V4L2_COLORSPACE_SRGB,
324 .priv = 0
325 },
326 {
327 1280,
328 1024,
329 V4L2_PIX_FMT_SBGGR8,
330 V4L2_FIELD_NONE,
331 .sizeimage =
332 1280 * 1024,
333 .bytesperline = 1280,
334 .colorspace = V4L2_COLORSPACE_SRGB,
335 .priv = 0
336 }
337 };
338
s5k4aa_probe(struct sd * sd)339 int s5k4aa_probe(struct sd *sd)
340 {
341 u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
342 const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
343 struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
344 int i, err = 0;
345
346 if (force_sensor) {
347 if (force_sensor == S5K4AA_SENSOR) {
348 pr_info("Forcing a %s sensor\n", s5k4aa.name);
349 goto sensor_found;
350 }
351 /* If we want to force another sensor, don't try to probe this
352 * one */
353 return -ENODEV;
354 }
355
356 gspca_dbg(gspca_dev, D_PROBE, "Probing for a s5k4aa sensor\n");
357
358 /* Preinit the sensor */
359 for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) {
360 u8 data[2] = {0x00, 0x00};
361
362 switch (preinit_s5k4aa[i][0]) {
363 case BRIDGE:
364 err = m5602_write_bridge(sd,
365 preinit_s5k4aa[i][1],
366 preinit_s5k4aa[i][2]);
367 break;
368
369 case SENSOR:
370 data[0] = preinit_s5k4aa[i][2];
371 err = m5602_write_sensor(sd,
372 preinit_s5k4aa[i][1],
373 data, 1);
374 break;
375
376 case SENSOR_LONG:
377 data[0] = preinit_s5k4aa[i][2];
378 data[1] = preinit_s5k4aa[i][3];
379 err = m5602_write_sensor(sd,
380 preinit_s5k4aa[i][1],
381 data, 2);
382 break;
383 default:
384 pr_info("Invalid stream command, exiting init\n");
385 return -EINVAL;
386 }
387 }
388
389 /* Test some registers, but we don't know their exact meaning yet */
390 if (m5602_read_sensor(sd, 0x00, prod_id, 2))
391 return -ENODEV;
392 if (m5602_read_sensor(sd, 0x02, prod_id+2, 2))
393 return -ENODEV;
394 if (m5602_read_sensor(sd, 0x04, prod_id+4, 2))
395 return -ENODEV;
396
397 if (memcmp(prod_id, expected_prod_id, sizeof(prod_id)))
398 return -ENODEV;
399 else
400 pr_info("Detected a s5k4aa sensor\n");
401
402 sensor_found:
403 sd->gspca_dev.cam.cam_mode = s5k4aa_modes;
404 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes);
405
406 return 0;
407 }
408
s5k4aa_start(struct sd * sd)409 int s5k4aa_start(struct sd *sd)
410 {
411 int i, err = 0;
412 u8 data[2];
413 struct cam *cam = &sd->gspca_dev.cam;
414 struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
415
416 switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) {
417 case 1280:
418 gspca_dbg(gspca_dev, D_CONF, "Configuring camera for SXGA mode\n");
419
420 for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) {
421 switch (SXGA_s5k4aa[i][0]) {
422 case BRIDGE:
423 err = m5602_write_bridge(sd,
424 SXGA_s5k4aa[i][1],
425 SXGA_s5k4aa[i][2]);
426 break;
427
428 case SENSOR:
429 data[0] = SXGA_s5k4aa[i][2];
430 err = m5602_write_sensor(sd,
431 SXGA_s5k4aa[i][1],
432 data, 1);
433 break;
434
435 case SENSOR_LONG:
436 data[0] = SXGA_s5k4aa[i][2];
437 data[1] = SXGA_s5k4aa[i][3];
438 err = m5602_write_sensor(sd,
439 SXGA_s5k4aa[i][1],
440 data, 2);
441 break;
442
443 default:
444 pr_err("Invalid stream command, exiting init\n");
445 return -EINVAL;
446 }
447 }
448 break;
449
450 case 640:
451 gspca_dbg(gspca_dev, D_CONF, "Configuring camera for VGA mode\n");
452
453 for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) {
454 switch (VGA_s5k4aa[i][0]) {
455 case BRIDGE:
456 err = m5602_write_bridge(sd,
457 VGA_s5k4aa[i][1],
458 VGA_s5k4aa[i][2]);
459 break;
460
461 case SENSOR:
462 data[0] = VGA_s5k4aa[i][2];
463 err = m5602_write_sensor(sd,
464 VGA_s5k4aa[i][1],
465 data, 1);
466 break;
467
468 case SENSOR_LONG:
469 data[0] = VGA_s5k4aa[i][2];
470 data[1] = VGA_s5k4aa[i][3];
471 err = m5602_write_sensor(sd,
472 VGA_s5k4aa[i][1],
473 data, 2);
474 break;
475
476 default:
477 pr_err("Invalid stream command, exiting init\n");
478 return -EINVAL;
479 }
480 }
481 break;
482 }
483 if (err < 0)
484 return err;
485
486 return 0;
487 }
488
s5k4aa_init(struct sd * sd)489 int s5k4aa_init(struct sd *sd)
490 {
491 int i, err = 0;
492
493 for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) {
494 u8 data[2] = {0x00, 0x00};
495
496 switch (init_s5k4aa[i][0]) {
497 case BRIDGE:
498 err = m5602_write_bridge(sd,
499 init_s5k4aa[i][1],
500 init_s5k4aa[i][2]);
501 break;
502
503 case SENSOR:
504 data[0] = init_s5k4aa[i][2];
505 err = m5602_write_sensor(sd,
506 init_s5k4aa[i][1], data, 1);
507 break;
508
509 case SENSOR_LONG:
510 data[0] = init_s5k4aa[i][2];
511 data[1] = init_s5k4aa[i][3];
512 err = m5602_write_sensor(sd,
513 init_s5k4aa[i][1], data, 2);
514 break;
515 default:
516 pr_info("Invalid stream command, exiting init\n");
517 return -EINVAL;
518 }
519 }
520
521 if (dump_sensor)
522 s5k4aa_dump_registers(sd);
523
524 return err;
525 }
526
s5k4aa_init_controls(struct sd * sd)527 int s5k4aa_init_controls(struct sd *sd)
528 {
529 struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
530
531 sd->gspca_dev.vdev.ctrl_handler = hdl;
532 v4l2_ctrl_handler_init(hdl, 6);
533
534 v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_BRIGHTNESS,
535 0, 0x1f, 1, S5K4AA_DEFAULT_BRIGHTNESS);
536
537 v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_EXPOSURE,
538 13, 0xfff, 1, 0x100);
539
540 v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_GAIN,
541 0, 127, 1, S5K4AA_DEFAULT_GAIN);
542
543 v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_SHARPNESS,
544 0, 1, 1, 1);
545
546 sd->hflip = v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_HFLIP,
547 0, 1, 1, 0);
548 sd->vflip = v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_VFLIP,
549 0, 1, 1, 0);
550
551 if (hdl->error) {
552 pr_err("Could not initialize controls\n");
553 return hdl->error;
554 }
555
556 v4l2_ctrl_cluster(2, &sd->hflip);
557
558 return 0;
559 }
560
s5k4aa_set_exposure(struct gspca_dev * gspca_dev,__s32 val)561 static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
562 {
563 struct sd *sd = (struct sd *) gspca_dev;
564 u8 data = S5K4AA_PAGE_MAP_2;
565 int err;
566
567 gspca_dbg(gspca_dev, D_CONF, "Set exposure to %d\n", val);
568 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
569 if (err < 0)
570 return err;
571 data = (val >> 8) & 0xff;
572 err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
573 if (err < 0)
574 return err;
575 data = val & 0xff;
576 err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
577
578 return err;
579 }
580
s5k4aa_set_hvflip(struct gspca_dev * gspca_dev)581 static int s5k4aa_set_hvflip(struct gspca_dev *gspca_dev)
582 {
583 struct sd *sd = (struct sd *) gspca_dev;
584 u8 data = S5K4AA_PAGE_MAP_2;
585 int err;
586 int hflip = sd->hflip->val;
587 int vflip = sd->vflip->val;
588
589 gspca_dbg(gspca_dev, D_CONF, "Set hvflip %d %d\n", hflip, vflip);
590 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
591 if (err < 0)
592 return err;
593
594 err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
595 if (err < 0)
596 return err;
597
598 if (dmi_check_system(s5k4aa_vflip_dmi_table)) {
599 hflip = !hflip;
600 vflip = !vflip;
601 }
602
603 data = (data & 0x7f) | (vflip << 7) | (hflip << 6);
604 err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
605 if (err < 0)
606 return err;
607
608 err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
609 if (err < 0)
610 return err;
611 if (hflip)
612 data &= 0xfe;
613 else
614 data |= 0x01;
615 err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
616 if (err < 0)
617 return err;
618
619 err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
620 if (err < 0)
621 return err;
622 if (vflip)
623 data &= 0xfe;
624 else
625 data |= 0x01;
626 err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
627 if (err < 0)
628 return err;
629
630 return 0;
631 }
632
s5k4aa_set_gain(struct gspca_dev * gspca_dev,__s32 val)633 static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
634 {
635 struct sd *sd = (struct sd *) gspca_dev;
636 u8 data = S5K4AA_PAGE_MAP_2;
637 int err;
638
639 gspca_dbg(gspca_dev, D_CONF, "Set gain to %d\n", val);
640 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
641 if (err < 0)
642 return err;
643
644 data = val & 0xff;
645 err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1);
646
647 return err;
648 }
649
s5k4aa_set_brightness(struct gspca_dev * gspca_dev,__s32 val)650 static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
651 {
652 struct sd *sd = (struct sd *) gspca_dev;
653 u8 data = S5K4AA_PAGE_MAP_2;
654 int err;
655
656 gspca_dbg(gspca_dev, D_CONF, "Set brightness to %d\n", val);
657 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
658 if (err < 0)
659 return err;
660
661 data = val & 0xff;
662 return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1);
663 }
664
s5k4aa_set_noise(struct gspca_dev * gspca_dev,__s32 val)665 static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
666 {
667 struct sd *sd = (struct sd *) gspca_dev;
668 u8 data = S5K4AA_PAGE_MAP_2;
669 int err;
670
671 gspca_dbg(gspca_dev, D_CONF, "Set noise to %d\n", val);
672 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
673 if (err < 0)
674 return err;
675
676 data = val & 0x01;
677 return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1);
678 }
679
s5k4aa_s_ctrl(struct v4l2_ctrl * ctrl)680 static int s5k4aa_s_ctrl(struct v4l2_ctrl *ctrl)
681 {
682 struct gspca_dev *gspca_dev =
683 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
684 int err;
685
686 if (!gspca_dev->streaming)
687 return 0;
688
689 switch (ctrl->id) {
690 case V4L2_CID_BRIGHTNESS:
691 err = s5k4aa_set_brightness(gspca_dev, ctrl->val);
692 break;
693 case V4L2_CID_EXPOSURE:
694 err = s5k4aa_set_exposure(gspca_dev, ctrl->val);
695 break;
696 case V4L2_CID_GAIN:
697 err = s5k4aa_set_gain(gspca_dev, ctrl->val);
698 break;
699 case V4L2_CID_SHARPNESS:
700 err = s5k4aa_set_noise(gspca_dev, ctrl->val);
701 break;
702 case V4L2_CID_HFLIP:
703 err = s5k4aa_set_hvflip(gspca_dev);
704 break;
705 default:
706 return -EINVAL;
707 }
708
709 return err;
710 }
711
s5k4aa_disconnect(struct sd * sd)712 void s5k4aa_disconnect(struct sd *sd)
713 {
714 sd->sensor = NULL;
715 }
716
s5k4aa_dump_registers(struct sd * sd)717 static void s5k4aa_dump_registers(struct sd *sd)
718 {
719 int address;
720 u8 page, old_page;
721 m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
722 for (page = 0; page < 16; page++) {
723 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
724 pr_info("Dumping the s5k4aa register state for page 0x%x\n",
725 page);
726 for (address = 0; address <= 0xff; address++) {
727 u8 value = 0;
728 m5602_read_sensor(sd, address, &value, 1);
729 pr_info("register 0x%x contains 0x%x\n",
730 address, value);
731 }
732 }
733 pr_info("s5k4aa register state dump complete\n");
734
735 for (page = 0; page < 16; page++) {
736 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
737 pr_info("Probing for which registers that are read/write for page 0x%x\n",
738 page);
739 for (address = 0; address <= 0xff; address++) {
740 u8 old_value, ctrl_value, test_value = 0xff;
741
742 m5602_read_sensor(sd, address, &old_value, 1);
743 m5602_write_sensor(sd, address, &test_value, 1);
744 m5602_read_sensor(sd, address, &ctrl_value, 1);
745
746 if (ctrl_value == test_value)
747 pr_info("register 0x%x is writeable\n",
748 address);
749 else
750 pr_info("register 0x%x is read only\n",
751 address);
752
753 /* Restore original value */
754 m5602_write_sensor(sd, address, &old_value, 1);
755 }
756 }
757 pr_info("Read/write register probing complete\n");
758 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
759 }
760