Merge branch 'tracing/core' of git://git.kernel.org/pub/scm/linux/kernel/git/frederic...
[linux-2.6-block.git] / drivers / media / video / gspca / m5602 / m5602_s5k4aa.c
CommitLineData
c109f816
EA
1/*
2 * Driver for the s5k4aa sensor
3 *
0c505e68 4 * Copyright (C) 2008 Erik Andrén
c109f816
EA
5 * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
6 * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
7 *
8 * Portions of code to USB interface and ALi driver software,
9 * Copyright (c) 2006 Willem Duinker
10 * v4l2 interface modeled after the V4L2 driver
11 * for SN9C10x PC Camera Controllers
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License as
15 * published by the Free Software Foundation, version 2.
16 *
17 */
18
19#include "m5602_s5k4aa.h"
20
cf811d50
EA
21static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
22static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
23static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
24static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
25static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
26static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
27static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
28static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val);
3290d402
EA
29static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val);
30static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val);
7ee46290
EA
31static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
32static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
cf811d50 33
579ef879
EA
34static
35 const
36 struct dmi_system_id s5k4aa_vflip_dmi_table[] = {
37 {
b6ef8836
EA
38 .ident = "BRUNEINIT",
39 .matches = {
40 DMI_MATCH(DMI_SYS_VENDOR, "BRUNENIT"),
41 DMI_MATCH(DMI_PRODUCT_NAME, "BRUNENIT"),
42 DMI_MATCH(DMI_BOARD_VERSION, "00030D0000000001")
43 }
44 }, {
579ef879
EA
45 .ident = "Fujitsu-Siemens Amilo Xa 2528",
46 .matches = {
47 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
48 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528")
49 }
5cc60d61
EA
50 }, {
51 .ident = "Fujitsu-Siemens Amilo Xi 2428",
52 .matches = {
53 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
54 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2428")
55 }
81191f69
EA
56 }, {
57 .ident = "Fujitsu-Siemens Amilo Xi 2528",
58 .matches = {
59 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
60 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2528")
61 }
579ef879
EA
62 }, {
63 .ident = "Fujitsu-Siemens Amilo Xi 2550",
64 .matches = {
65 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
66 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550")
67 }
97606774
EA
68 }, {
69 .ident = "Fujitsu-Siemens Amilo Pa 2548",
70 .matches = {
71 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
72 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2548")
73 }
2339a188
EA
74 }, {
75 .ident = "MSI GX700",
76 .matches = {
77 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
78 DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
79 DMI_MATCH(DMI_BIOS_DATE, "12/02/2008")
80 }
579ef879
EA
81 }, {
82 .ident = "MSI GX700",
83 .matches = {
84 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
85 DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
86 DMI_MATCH(DMI_BIOS_DATE, "07/26/2007")
87 }
95e6dcd1
BK
88 }, {
89 .ident = "MSI GX700",
90 .matches = {
91 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
92 DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
93 DMI_MATCH(DMI_BIOS_DATE, "07/19/2007")
94 }
579ef879
EA
95 }, {
96 .ident = "MSI GX700/GX705/EX700",
97 .matches = {
98 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
99 DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700")
100 }
79c3576a
EA
101 }, {
102 .ident = "MSI L735",
103 .matches = {
104 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
105 DMI_MATCH(DMI_PRODUCT_NAME, "MS-1717X")
106 }
f02c3944
EA
107 }, {
108 .ident = "Lenovo Y300",
109 .matches = {
110 DMI_MATCH(DMI_SYS_VENDOR, "L3000 Y300"),
111 DMI_MATCH(DMI_PRODUCT_NAME, "Y300")
112 }
579ef879
EA
113 },
114 { }
115};
116
74cadfe1
EA
117static struct v4l2_pix_format s5k4aa_modes[] = {
118 {
119 640,
120 480,
121 V4L2_PIX_FMT_SBGGR8,
122 V4L2_FIELD_NONE,
123 .sizeimage =
124 640 * 480,
125 .bytesperline = 640,
126 .colorspace = V4L2_COLORSPACE_SRGB,
127 .priv = 0
60d52cec
GL
128 },
129 {
130 1280,
131 1024,
132 V4L2_PIX_FMT_SBGGR8,
133 V4L2_FIELD_NONE,
134 .sizeimage =
135 1280 * 1024,
136 .bytesperline = 1280,
137 .colorspace = V4L2_COLORSPACE_SRGB,
138 .priv = 0
74cadfe1
EA
139 }
140};
141
2e03669d 142static const struct ctrl s5k4aa_ctrls[] = {
a594fb48 143#define VFLIP_IDX 0
e17cc08c
EA
144 {
145 {
146 .id = V4L2_CID_VFLIP,
147 .type = V4L2_CTRL_TYPE_BOOLEAN,
148 .name = "vertical flip",
149 .minimum = 0,
150 .maximum = 1,
151 .step = 1,
152 .default_value = 0
153 },
154 .set = s5k4aa_set_vflip,
155 .get = s5k4aa_get_vflip
a594fb48
EA
156 },
157#define HFLIP_IDX 1
158 {
e17cc08c
EA
159 {
160 .id = V4L2_CID_HFLIP,
161 .type = V4L2_CTRL_TYPE_BOOLEAN,
162 .name = "horizontal flip",
163 .minimum = 0,
164 .maximum = 1,
165 .step = 1,
166 .default_value = 0
167 },
168 .set = s5k4aa_set_hflip,
169 .get = s5k4aa_get_hflip
a594fb48
EA
170 },
171#define GAIN_IDX 2
172 {
e17cc08c
EA
173 {
174 .id = V4L2_CID_GAIN,
175 .type = V4L2_CTRL_TYPE_INTEGER,
176 .name = "Gain",
177 .minimum = 0,
178 .maximum = 127,
179 .step = 1,
7ee46290 180 .default_value = S5K4AA_DEFAULT_GAIN,
e17cc08c
EA
181 .flags = V4L2_CTRL_FLAG_SLIDER
182 },
183 .set = s5k4aa_set_gain,
184 .get = s5k4aa_get_gain
a594fb48
EA
185 },
186#define EXPOSURE_IDX 3
187 {
e17cc08c
EA
188 {
189 .id = V4L2_CID_EXPOSURE,
190 .type = V4L2_CTRL_TYPE_INTEGER,
191 .name = "Exposure",
192 .minimum = 13,
193 .maximum = 0xfff,
194 .step = 1,
195 .default_value = 0x100,
196 .flags = V4L2_CTRL_FLAG_SLIDER
197 },
198 .set = s5k4aa_set_exposure,
199 .get = s5k4aa_get_exposure
3290d402
EA
200 },
201#define NOISE_SUPP_IDX 4
202 {
203 {
204 .id = V4L2_CID_PRIVATE_BASE,
205 .type = V4L2_CTRL_TYPE_BOOLEAN,
206 .name = "Noise suppression (smoothing)",
207 .minimum = 0,
208 .maximum = 1,
209 .step = 1,
210 .default_value = 1,
211 },
212 .set = s5k4aa_set_noise,
213 .get = s5k4aa_get_noise
214 },
7ee46290
EA
215#define BRIGHTNESS_IDX 5
216 {
217 {
218 .id = V4L2_CID_BRIGHTNESS,
219 .type = V4L2_CTRL_TYPE_INTEGER,
220 .name = "Brightness",
221 .minimum = 0,
222 .maximum = 0x1f,
223 .step = 1,
224 .default_value = S5K4AA_DEFAULT_BRIGHTNESS,
225 },
226 .set = s5k4aa_set_brightness,
227 .get = s5k4aa_get_brightness
228 },
229
e17cc08c
EA
230};
231
658efb63 232static void s5k4aa_dump_registers(struct sd *sd);
579ef879 233
c109f816
EA
234int s5k4aa_probe(struct sd *sd)
235{
236 u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
237 const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
238 int i, err = 0;
a594fb48 239 s32 *sensor_settings;
c109f816
EA
240
241 if (force_sensor) {
242 if (force_sensor == S5K4AA_SENSOR) {
243 info("Forcing a %s sensor", s5k4aa.name);
244 goto sensor_found;
245 }
246 /* If we want to force another sensor, don't try to probe this
247 * one */
248 return -ENODEV;
249 }
250
251 info("Probing for a s5k4aa sensor");
252
253 /* Preinit the sensor */
254 for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) {
255 u8 data[2] = {0x00, 0x00};
256
257 switch (preinit_s5k4aa[i][0]) {
258 case BRIDGE:
259 err = m5602_write_bridge(sd,
260 preinit_s5k4aa[i][1],
261 preinit_s5k4aa[i][2]);
262 break;
263
264 case SENSOR:
265 data[0] = preinit_s5k4aa[i][2];
6dc4cff0 266 err = m5602_write_sensor(sd,
c109f816
EA
267 preinit_s5k4aa[i][1],
268 data, 1);
269 break;
270
271 case SENSOR_LONG:
272 data[0] = preinit_s5k4aa[i][2];
273 data[1] = preinit_s5k4aa[i][3];
6dc4cff0 274 err = m5602_write_sensor(sd,
c109f816
EA
275 preinit_s5k4aa[i][1],
276 data, 2);
277 break;
278 default:
279 info("Invalid stream command, exiting init");
280 return -EINVAL;
281 }
282 }
283
284 /* Test some registers, but we don't know their exact meaning yet */
d2c45230
GL
285 if (m5602_read_sensor(sd, 0x00, prod_id, 2))
286 return -ENODEV;
287 if (m5602_read_sensor(sd, 0x02, prod_id+2, 2))
288 return -ENODEV;
289 if (m5602_read_sensor(sd, 0x04, prod_id+4, 2))
c109f816
EA
290 return -ENODEV;
291
292 if (memcmp(prod_id, expected_prod_id, sizeof(prod_id)))
293 return -ENODEV;
294 else
295 info("Detected a s5k4aa sensor");
32500701 296
c109f816 297sensor_found:
a594fb48
EA
298 sensor_settings = kmalloc(
299 ARRAY_SIZE(s5k4aa_ctrls) * sizeof(s32), GFP_KERNEL);
300 if (!sensor_settings)
301 return -ENOMEM;
302
74cadfe1
EA
303 sd->gspca_dev.cam.cam_mode = s5k4aa_modes;
304 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes);
e17cc08c 305 sd->desc->ctrls = s5k4aa_ctrls;
e4cc4fcc 306 sd->desc->nctrls = ARRAY_SIZE(s5k4aa_ctrls);
a594fb48
EA
307
308 for (i = 0; i < ARRAY_SIZE(s5k4aa_ctrls); i++)
309 sensor_settings[i] = s5k4aa_ctrls[i].qctrl.default_value;
310 sd->sensor_priv = sensor_settings;
d4a389a3 311
c109f816
EA
312 return 0;
313}
314
ad567ec2
EA
315int s5k4aa_start(struct sd *sd)
316{
317 int i, err = 0;
318 u8 data[2];
319 struct cam *cam = &sd->gspca_dev.cam;
9bc738fb 320 s32 *sensor_settings = sd->sensor_priv;
ad567ec2 321
d4a389a3 322 switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) {
4fcec145
EA
323 case 1280:
324 PDEBUG(D_V4L2, "Configuring camera for SXGA mode");
325
326 for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) {
327 switch (SXGA_s5k4aa[i][0]) {
328 case BRIDGE:
329 err = m5602_write_bridge(sd,
330 SXGA_s5k4aa[i][1],
331 SXGA_s5k4aa[i][2]);
332 break;
333
334 case SENSOR:
335 data[0] = SXGA_s5k4aa[i][2];
336 err = m5602_write_sensor(sd,
337 SXGA_s5k4aa[i][1],
338 data, 1);
339 break;
340
341 case SENSOR_LONG:
342 data[0] = SXGA_s5k4aa[i][2];
343 data[1] = SXGA_s5k4aa[i][3];
344 err = m5602_write_sensor(sd,
345 SXGA_s5k4aa[i][1],
346 data, 2);
347 break;
348
349 default:
350 err("Invalid stream command, exiting init");
351 return -EINVAL;
352 }
353 }
60d52cec
GL
354 err = s5k4aa_set_noise(&sd->gspca_dev, 0);
355 if (err < 0)
356 return err;
357 break;
4fcec145 358
ad567ec2
EA
359 case 640:
360 PDEBUG(D_V4L2, "Configuring camera for VGA mode");
361
362 for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) {
363 switch (VGA_s5k4aa[i][0]) {
364 case BRIDGE:
365 err = m5602_write_bridge(sd,
366 VGA_s5k4aa[i][1],
367 VGA_s5k4aa[i][2]);
368 break;
369
370 case SENSOR:
371 data[0] = VGA_s5k4aa[i][2];
372 err = m5602_write_sensor(sd,
373 VGA_s5k4aa[i][1],
374 data, 1);
375 break;
376
377 case SENSOR_LONG:
378 data[0] = VGA_s5k4aa[i][2];
379 data[1] = VGA_s5k4aa[i][3];
380 err = m5602_write_sensor(sd,
381 VGA_s5k4aa[i][1],
382 data, 2);
383 break;
384
385 default:
386 err("Invalid stream command, exiting init");
387 return -EINVAL;
388 }
389 }
60d52cec
GL
390 err = s5k4aa_set_noise(&sd->gspca_dev, 1);
391 if (err < 0)
392 return err;
393 break;
ad567ec2 394 }
9bc738fb
GL
395 if (err < 0)
396 return err;
397
398 err = s5k4aa_set_exposure(&sd->gspca_dev,
399 sensor_settings[EXPOSURE_IDX]);
400 if (err < 0)
401 return err;
402
403 err = s5k4aa_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
404 if (err < 0)
405 return err;
406
407 err = s5k4aa_set_brightness(&sd->gspca_dev,
408 sensor_settings[BRIGHTNESS_IDX]);
409 if (err < 0)
410 return err;
411
412 err = s5k4aa_set_noise(&sd->gspca_dev, sensor_settings[NOISE_SUPP_IDX]);
413 if (err < 0)
414 return err;
415
416 err = s5k4aa_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
417 if (err < 0)
418 return err;
419
420 return s5k4aa_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
ad567ec2
EA
421}
422
c109f816
EA
423int s5k4aa_init(struct sd *sd)
424{
425 int i, err = 0;
426
427 for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) {
428 u8 data[2] = {0x00, 0x00};
429
430 switch (init_s5k4aa[i][0]) {
431 case BRIDGE:
432 err = m5602_write_bridge(sd,
433 init_s5k4aa[i][1],
434 init_s5k4aa[i][2]);
435 break;
436
437 case SENSOR:
438 data[0] = init_s5k4aa[i][2];
6dc4cff0 439 err = m5602_write_sensor(sd,
c109f816
EA
440 init_s5k4aa[i][1], data, 1);
441 break;
442
443 case SENSOR_LONG:
444 data[0] = init_s5k4aa[i][2];
445 data[1] = init_s5k4aa[i][3];
6dc4cff0 446 err = m5602_write_sensor(sd,
c109f816
EA
447 init_s5k4aa[i][1], data, 2);
448 break;
449 default:
450 info("Invalid stream command, exiting init");
451 return -EINVAL;
452 }
453 }
454
36e756c5
EA
455 if (dump_sensor)
456 s5k4aa_dump_registers(sd);
457
9bc738fb 458 return err;
c109f816
EA
459}
460
cf811d50 461static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
c109f816
EA
462{
463 struct sd *sd = (struct sd *) gspca_dev;
a594fb48 464 s32 *sensor_settings = sd->sensor_priv;
c109f816 465
a594fb48 466 *val = sensor_settings[EXPOSURE_IDX];
17ea88ae 467 PDEBUG(D_V4L2, "Read exposure %d", *val);
051781b3 468
a594fb48 469 return 0;
c109f816
EA
470}
471
cf811d50 472static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
c109f816
EA
473{
474 struct sd *sd = (struct sd *) gspca_dev;
a594fb48 475 s32 *sensor_settings = sd->sensor_priv;
c109f816
EA
476 u8 data = S5K4AA_PAGE_MAP_2;
477 int err;
478
a594fb48 479 sensor_settings[EXPOSURE_IDX] = val;
17ea88ae 480 PDEBUG(D_V4L2, "Set exposure to %d", val);
6dc4cff0 481 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
c109f816 482 if (err < 0)
051781b3 483 return err;
c109f816 484 data = (val >> 8) & 0xff;
6dc4cff0 485 err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
c109f816 486 if (err < 0)
051781b3 487 return err;
c109f816 488 data = val & 0xff;
6dc4cff0 489 err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
051781b3 490
32500701 491 return err;
c109f816
EA
492}
493
cf811d50 494static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
c109f816
EA
495{
496 struct sd *sd = (struct sd *) gspca_dev;
a594fb48 497 s32 *sensor_settings = sd->sensor_priv;
c109f816 498
a594fb48 499 *val = sensor_settings[VFLIP_IDX];
17ea88ae 500 PDEBUG(D_V4L2, "Read vertical flip %d", *val);
c109f816 501
a594fb48 502 return 0;
c109f816
EA
503}
504
cf811d50 505static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
c109f816
EA
506{
507 struct sd *sd = (struct sd *) gspca_dev;
a594fb48 508 s32 *sensor_settings = sd->sensor_priv;
c109f816
EA
509 u8 data = S5K4AA_PAGE_MAP_2;
510 int err;
511
a594fb48
EA
512 sensor_settings[VFLIP_IDX] = val;
513
17ea88ae 514 PDEBUG(D_V4L2, "Set vertical flip to %d", val);
6dc4cff0 515 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
c109f816 516 if (err < 0)
051781b3 517 return err;
a594fb48 518
a68985d4
EA
519 err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
520 if (err < 0)
521 return err;
522
9bc738fb 523 if (dmi_check_system(s5k4aa_vflip_dmi_table))
a594fb48
EA
524 val = !val;
525
9bc738fb 526 data = ((data & ~S5K4AA_RM_V_FLIP) | ((val & 0x01) << 7));
6dc4cff0 527 err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
c109f816 528 if (err < 0)
051781b3 529 return err;
c109f816 530
9bc738fb
GL
531 err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
532 if (err < 0)
533 return err;
83955556
JFM
534 if (val)
535 data &= 0xfe;
536 else
537 data |= 0x01;
9bc738fb 538 err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
32500701 539 return err;
c109f816
EA
540}
541
cf811d50 542static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
c109f816
EA
543{
544 struct sd *sd = (struct sd *) gspca_dev;
a594fb48 545 s32 *sensor_settings = sd->sensor_priv;
c109f816 546
a594fb48 547 *val = sensor_settings[HFLIP_IDX];
17ea88ae 548 PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
051781b3 549
a594fb48 550 return 0;
c109f816
EA
551}
552
cf811d50 553static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
c109f816
EA
554{
555 struct sd *sd = (struct sd *) gspca_dev;
a594fb48 556 s32 *sensor_settings = sd->sensor_priv;
c109f816
EA
557 u8 data = S5K4AA_PAGE_MAP_2;
558 int err;
559
a594fb48
EA
560 sensor_settings[HFLIP_IDX] = val;
561
562 PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
6dc4cff0 563 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
c109f816 564 if (err < 0)
051781b3 565 return err;
c109f816 566
a68985d4
EA
567 err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
568 if (err < 0)
569 return err;
570
9bc738fb 571 if (dmi_check_system(s5k4aa_vflip_dmi_table))
2f17e1a1 572 val = !val;
2f17e1a1 573
c109f816 574 data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
6dc4cff0 575 err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
c109f816 576 if (err < 0)
051781b3 577 return err;
c109f816 578
9bc738fb
GL
579 err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
580 if (err < 0)
581 return err;
83955556
JFM
582 if (val)
583 data &= 0xfe;
584 else
585 data |= 0x01;
9bc738fb 586 err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
32500701 587 return err;
c109f816
EA
588}
589
cf811d50 590static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
c109f816
EA
591{
592 struct sd *sd = (struct sd *) gspca_dev;
a594fb48 593 s32 *sensor_settings = sd->sensor_priv;
c109f816 594
a594fb48 595 *val = sensor_settings[GAIN_IDX];
17ea88ae 596 PDEBUG(D_V4L2, "Read gain %d", *val);
a594fb48 597 return 0;
c109f816
EA
598}
599
cf811d50 600static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
c109f816
EA
601{
602 struct sd *sd = (struct sd *) gspca_dev;
a594fb48 603 s32 *sensor_settings = sd->sensor_priv;
c109f816
EA
604 u8 data = S5K4AA_PAGE_MAP_2;
605 int err;
606
a594fb48
EA
607 sensor_settings[GAIN_IDX] = val;
608
17ea88ae 609 PDEBUG(D_V4L2, "Set gain to %d", val);
6dc4cff0 610 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
c109f816 611 if (err < 0)
051781b3 612 return err;
c109f816
EA
613
614 data = val & 0xff;
7ee46290 615 err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1);
c109f816 616
32500701 617 return err;
c109f816
EA
618}
619
7ee46290
EA
620static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
621{
622 struct sd *sd = (struct sd *) gspca_dev;
623 s32 *sensor_settings = sd->sensor_priv;
624
625 *val = sensor_settings[BRIGHTNESS_IDX];
626 PDEBUG(D_V4L2, "Read brightness %d", *val);
627 return 0;
628}
629
630static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
631{
632 struct sd *sd = (struct sd *) gspca_dev;
633 s32 *sensor_settings = sd->sensor_priv;
634 u8 data = S5K4AA_PAGE_MAP_2;
635 int err;
636
637 sensor_settings[BRIGHTNESS_IDX] = val;
638
639 PDEBUG(D_V4L2, "Set brightness to %d", 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 return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1);
646}
647
3290d402
EA
648static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val)
649{
650 struct sd *sd = (struct sd *) gspca_dev;
651 s32 *sensor_settings = sd->sensor_priv;
652
653 *val = sensor_settings[NOISE_SUPP_IDX];
654 PDEBUG(D_V4L2, "Read noise %d", *val);
655 return 0;
656}
657
658static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
659{
660 struct sd *sd = (struct sd *) gspca_dev;
661 s32 *sensor_settings = sd->sensor_priv;
662 u8 data = S5K4AA_PAGE_MAP_2;
663 int err;
664
665 sensor_settings[NOISE_SUPP_IDX] = val;
666
667 PDEBUG(D_V4L2, "Set noise to %d", val);
668 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
669 if (err < 0)
670 return err;
671
672 data = val & 0x01;
673 return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1);
674}
675
a594fb48
EA
676void s5k4aa_disconnect(struct sd *sd)
677{
678 sd->sensor = NULL;
679 kfree(sd->sensor_priv);
680}
681
658efb63 682static void s5k4aa_dump_registers(struct sd *sd)
c109f816
EA
683{
684 int address;
685 u8 page, old_page;
4feb24fc 686 m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
c109f816 687 for (page = 0; page < 16; page++) {
6dc4cff0 688 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
c109f816
EA
689 info("Dumping the s5k4aa register state for page 0x%x", page);
690 for (address = 0; address <= 0xff; address++) {
691 u8 value = 0;
4feb24fc 692 m5602_read_sensor(sd, address, &value, 1);
c109f816
EA
693 info("register 0x%x contains 0x%x",
694 address, value);
695 }
696 }
697 info("s5k4aa register state dump complete");
698
699 for (page = 0; page < 16; page++) {
6dc4cff0 700 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
c109f816
EA
701 info("Probing for which registers that are "
702 "read/write for page 0x%x", page);
703 for (address = 0; address <= 0xff; address++) {
704 u8 old_value, ctrl_value, test_value = 0xff;
705
4feb24fc 706 m5602_read_sensor(sd, address, &old_value, 1);
6dc4cff0 707 m5602_write_sensor(sd, address, &test_value, 1);
4feb24fc 708 m5602_read_sensor(sd, address, &ctrl_value, 1);
c109f816
EA
709
710 if (ctrl_value == test_value)
711 info("register 0x%x is writeable", address);
712 else
713 info("register 0x%x is read only", address);
714
715 /* Restore original value */
6dc4cff0 716 m5602_write_sensor(sd, address, &old_value, 1);
c109f816
EA
717 }
718 }
719 info("Read/write register probing complete");
6dc4cff0 720 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
c109f816 721}