blob: a27afeb6f39be4ffb85608f22c428018939932a5 [file] [log] [blame]
Erik Andrenc109f812008-10-01 04:51:53 -03001/*
2 * Driver for the s5k4aa sensor
3 *
Erik Andren0c505e682008-10-16 16:43:16 -03004 * Copyright (C) 2008 Erik Andrén
Erik Andrenc109f812008-10-01 04:51:53 -03005 * 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
Erik Andr?ncf811d52009-04-03 02:49:10 -030021static 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);
Erik Andr?n3290d402009-01-13 16:40:28 -030029static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val);
30static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val);
Erik Andr?n7ee46292009-01-14 03:37:03 -030031static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
32static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
Erik Andr?ncf811d52009-04-03 02:49:10 -030033
Erik Andrén579ef872008-11-18 14:38:10 -030034static
35 const
36 struct dmi_system_id s5k4aa_vflip_dmi_table[] = {
37 {
Erik Andrénb6ef8832009-09-27 10:11:43 -030038 .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 }, {
Erik Andrén579ef872008-11-18 14:38:10 -030045 .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 }
50 }, {
Erik Andrén81191f62009-10-03 10:01:41 -030051 .ident = "Fujitsu-Siemens Amilo Xi 2528",
52 .matches = {
53 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
54 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2528")
55 }
56 }, {
Erik Andrén579ef872008-11-18 14:38:10 -030057 .ident = "Fujitsu-Siemens Amilo Xi 2550",
58 .matches = {
59 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
60 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550")
61 }
62 }, {
Erik Andrén97606772009-07-01 02:49:23 -030063 .ident = "Fujitsu-Siemens Amilo Pa 2548",
64 .matches = {
65 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
66 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2548")
67 }
68 }, {
Erik Andrén579ef872008-11-18 14:38:10 -030069 .ident = "MSI GX700",
70 .matches = {
71 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
72 DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
Erik Andrén2339a182009-09-27 10:20:21 -030073 DMI_MATCH(DMI_BIOS_DATE, "12/02/2008")
74 }
75 }, {
76 .ident = "MSI GX700",
77 .matches = {
78 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
79 DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
Erik Andrén579ef872008-11-18 14:38:10 -030080 DMI_MATCH(DMI_BIOS_DATE, "07/26/2007")
81 }
82 }, {
Brian Kloppenborg95e6dcd2009-08-30 09:43:40 -030083 .ident = "MSI GX700",
84 .matches = {
85 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
86 DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
87 DMI_MATCH(DMI_BIOS_DATE, "07/19/2007")
88 }
89 }, {
Erik Andrén579ef872008-11-18 14:38:10 -030090 .ident = "MSI GX700/GX705/EX700",
91 .matches = {
92 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
93 DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700")
94 }
Erik Andrén79c35762009-02-12 16:36:05 -030095 }, {
96 .ident = "MSI L735",
97 .matches = {
98 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
99 DMI_MATCH(DMI_PRODUCT_NAME, "MS-1717X")
100 }
Erik Andrénf02c3942009-05-06 17:44:45 -0300101 }, {
102 .ident = "Lenovo Y300",
103 .matches = {
104 DMI_MATCH(DMI_SYS_VENDOR, "L3000 Y300"),
105 DMI_MATCH(DMI_PRODUCT_NAME, "Y300")
106 }
Erik Andrén579ef872008-11-18 14:38:10 -0300107 },
108 { }
109};
110
Erik Andr?n74cadfe2008-12-30 16:48:42 -0300111static struct v4l2_pix_format s5k4aa_modes[] = {
112 {
113 640,
114 480,
115 V4L2_PIX_FMT_SBGGR8,
116 V4L2_FIELD_NONE,
117 .sizeimage =
118 640 * 480,
119 .bytesperline = 640,
120 .colorspace = V4L2_COLORSPACE_SRGB,
121 .priv = 0
Grégory Lardière60d52ce2009-02-12 03:32:52 -0300122 },
123 {
124 1280,
125 1024,
126 V4L2_PIX_FMT_SBGGR8,
127 V4L2_FIELD_NONE,
128 .sizeimage =
129 1280 * 1024,
130 .bytesperline = 1280,
131 .colorspace = V4L2_COLORSPACE_SRGB,
132 .priv = 0
Erik Andr?n74cadfe2008-12-30 16:48:42 -0300133 }
134};
135
Tobias Klauser2e036692009-04-26 09:30:18 -0300136static const struct ctrl s5k4aa_ctrls[] = {
Erik Andr?na594fb42009-01-06 11:37:03 -0300137#define VFLIP_IDX 0
Erik Andr?ne17cc082008-12-30 17:06:55 -0300138 {
139 {
140 .id = V4L2_CID_VFLIP,
141 .type = V4L2_CTRL_TYPE_BOOLEAN,
142 .name = "vertical flip",
143 .minimum = 0,
144 .maximum = 1,
145 .step = 1,
146 .default_value = 0
147 },
148 .set = s5k4aa_set_vflip,
149 .get = s5k4aa_get_vflip
Erik Andr?na594fb42009-01-06 11:37:03 -0300150 },
151#define HFLIP_IDX 1
152 {
Erik Andr?ne17cc082008-12-30 17:06:55 -0300153 {
154 .id = V4L2_CID_HFLIP,
155 .type = V4L2_CTRL_TYPE_BOOLEAN,
156 .name = "horizontal flip",
157 .minimum = 0,
158 .maximum = 1,
159 .step = 1,
160 .default_value = 0
161 },
162 .set = s5k4aa_set_hflip,
163 .get = s5k4aa_get_hflip
Erik Andr?na594fb42009-01-06 11:37:03 -0300164 },
165#define GAIN_IDX 2
166 {
Erik Andr?ne17cc082008-12-30 17:06:55 -0300167 {
168 .id = V4L2_CID_GAIN,
169 .type = V4L2_CTRL_TYPE_INTEGER,
170 .name = "Gain",
171 .minimum = 0,
172 .maximum = 127,
173 .step = 1,
Erik Andr?n7ee46292009-01-14 03:37:03 -0300174 .default_value = S5K4AA_DEFAULT_GAIN,
Erik Andr?ne17cc082008-12-30 17:06:55 -0300175 .flags = V4L2_CTRL_FLAG_SLIDER
176 },
177 .set = s5k4aa_set_gain,
178 .get = s5k4aa_get_gain
Erik Andr?na594fb42009-01-06 11:37:03 -0300179 },
180#define EXPOSURE_IDX 3
181 {
Erik Andr?ne17cc082008-12-30 17:06:55 -0300182 {
183 .id = V4L2_CID_EXPOSURE,
184 .type = V4L2_CTRL_TYPE_INTEGER,
185 .name = "Exposure",
186 .minimum = 13,
187 .maximum = 0xfff,
188 .step = 1,
189 .default_value = 0x100,
190 .flags = V4L2_CTRL_FLAG_SLIDER
191 },
192 .set = s5k4aa_set_exposure,
193 .get = s5k4aa_get_exposure
Erik Andr?n3290d402009-01-13 16:40:28 -0300194 },
195#define NOISE_SUPP_IDX 4
196 {
197 {
198 .id = V4L2_CID_PRIVATE_BASE,
199 .type = V4L2_CTRL_TYPE_BOOLEAN,
200 .name = "Noise suppression (smoothing)",
201 .minimum = 0,
202 .maximum = 1,
203 .step = 1,
204 .default_value = 1,
205 },
206 .set = s5k4aa_set_noise,
207 .get = s5k4aa_get_noise
208 },
Erik Andr?n7ee46292009-01-14 03:37:03 -0300209#define BRIGHTNESS_IDX 5
210 {
211 {
212 .id = V4L2_CID_BRIGHTNESS,
213 .type = V4L2_CTRL_TYPE_INTEGER,
214 .name = "Brightness",
215 .minimum = 0,
216 .maximum = 0x1f,
217 .step = 1,
218 .default_value = S5K4AA_DEFAULT_BRIGHTNESS,
219 },
220 .set = s5k4aa_set_brightness,
221 .get = s5k4aa_get_brightness
222 },
223
Erik Andr?ne17cc082008-12-30 17:06:55 -0300224};
225
Erik Andrén658efb62008-11-24 14:21:29 -0300226static void s5k4aa_dump_registers(struct sd *sd);
Erik Andrén579ef872008-11-18 14:38:10 -0300227
Erik Andrenc109f812008-10-01 04:51:53 -0300228int s5k4aa_probe(struct sd *sd)
229{
230 u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
231 const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
232 int i, err = 0;
Erik Andr?na594fb42009-01-06 11:37:03 -0300233 s32 *sensor_settings;
Erik Andrenc109f812008-10-01 04:51:53 -0300234
235 if (force_sensor) {
236 if (force_sensor == S5K4AA_SENSOR) {
237 info("Forcing a %s sensor", s5k4aa.name);
238 goto sensor_found;
239 }
240 /* If we want to force another sensor, don't try to probe this
241 * one */
242 return -ENODEV;
243 }
244
245 info("Probing for a s5k4aa sensor");
246
247 /* Preinit the sensor */
248 for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) {
249 u8 data[2] = {0x00, 0x00};
250
251 switch (preinit_s5k4aa[i][0]) {
252 case BRIDGE:
253 err = m5602_write_bridge(sd,
254 preinit_s5k4aa[i][1],
255 preinit_s5k4aa[i][2]);
256 break;
257
258 case SENSOR:
259 data[0] = preinit_s5k4aa[i][2];
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300260 err = m5602_write_sensor(sd,
Erik Andrenc109f812008-10-01 04:51:53 -0300261 preinit_s5k4aa[i][1],
262 data, 1);
263 break;
264
265 case SENSOR_LONG:
266 data[0] = preinit_s5k4aa[i][2];
267 data[1] = preinit_s5k4aa[i][3];
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300268 err = m5602_write_sensor(sd,
Erik Andrenc109f812008-10-01 04:51:53 -0300269 preinit_s5k4aa[i][1],
270 data, 2);
271 break;
272 default:
273 info("Invalid stream command, exiting init");
274 return -EINVAL;
275 }
276 }
277
278 /* Test some registers, but we don't know their exact meaning yet */
Gregory Lardiered2c45232009-02-22 17:54:11 -0300279 if (m5602_read_sensor(sd, 0x00, prod_id, 2))
280 return -ENODEV;
281 if (m5602_read_sensor(sd, 0x02, prod_id+2, 2))
282 return -ENODEV;
283 if (m5602_read_sensor(sd, 0x04, prod_id+4, 2))
Erik Andrenc109f812008-10-01 04:51:53 -0300284 return -ENODEV;
285
286 if (memcmp(prod_id, expected_prod_id, sizeof(prod_id)))
287 return -ENODEV;
288 else
289 info("Detected a s5k4aa sensor");
Erik Andrén32500702008-11-20 04:02:44 -0300290
Erik Andrenc109f812008-10-01 04:51:53 -0300291sensor_found:
Erik Andr?na594fb42009-01-06 11:37:03 -0300292 sensor_settings = kmalloc(
293 ARRAY_SIZE(s5k4aa_ctrls) * sizeof(s32), GFP_KERNEL);
294 if (!sensor_settings)
295 return -ENOMEM;
296
Erik Andr?n74cadfe2008-12-30 16:48:42 -0300297 sd->gspca_dev.cam.cam_mode = s5k4aa_modes;
298 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes);
Erik Andr?ne17cc082008-12-30 17:06:55 -0300299 sd->desc->ctrls = s5k4aa_ctrls;
Erik Andr?ne4cc4fc2008-12-30 15:27:17 -0300300 sd->desc->nctrls = ARRAY_SIZE(s5k4aa_ctrls);
Erik Andr?na594fb42009-01-06 11:37:03 -0300301
302 for (i = 0; i < ARRAY_SIZE(s5k4aa_ctrls); i++)
303 sensor_settings[i] = s5k4aa_ctrls[i].qctrl.default_value;
304 sd->sensor_priv = sensor_settings;
Erik Andr?nd4a389a2009-01-09 03:30:54 -0300305
Erik Andrenc109f812008-10-01 04:51:53 -0300306 return 0;
307}
308
Erik Andr?nad567ec2008-12-26 12:57:42 -0300309int s5k4aa_start(struct sd *sd)
310{
311 int i, err = 0;
312 u8 data[2];
313 struct cam *cam = &sd->gspca_dev.cam;
Grégory Lardière9bc738f2009-02-12 03:40:29 -0300314 s32 *sensor_settings = sd->sensor_priv;
Erik Andr?nad567ec2008-12-26 12:57:42 -0300315
Erik Andr?nd4a389a2009-01-09 03:30:54 -0300316 switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) {
Erik Andrén4fcec142009-01-29 13:34:41 -0300317 case 1280:
318 PDEBUG(D_V4L2, "Configuring camera for SXGA mode");
319
320 for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) {
321 switch (SXGA_s5k4aa[i][0]) {
322 case BRIDGE:
323 err = m5602_write_bridge(sd,
324 SXGA_s5k4aa[i][1],
325 SXGA_s5k4aa[i][2]);
326 break;
327
328 case SENSOR:
329 data[0] = SXGA_s5k4aa[i][2];
330 err = m5602_write_sensor(sd,
331 SXGA_s5k4aa[i][1],
332 data, 1);
333 break;
334
335 case SENSOR_LONG:
336 data[0] = SXGA_s5k4aa[i][2];
337 data[1] = SXGA_s5k4aa[i][3];
338 err = m5602_write_sensor(sd,
339 SXGA_s5k4aa[i][1],
340 data, 2);
341 break;
342
343 default:
344 err("Invalid stream command, exiting init");
345 return -EINVAL;
346 }
347 }
Grégory Lardière60d52ce2009-02-12 03:32:52 -0300348 err = s5k4aa_set_noise(&sd->gspca_dev, 0);
349 if (err < 0)
350 return err;
351 break;
Erik Andrén4fcec142009-01-29 13:34:41 -0300352
Erik Andr?nad567ec2008-12-26 12:57:42 -0300353 case 640:
354 PDEBUG(D_V4L2, "Configuring camera for VGA mode");
355
356 for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) {
357 switch (VGA_s5k4aa[i][0]) {
358 case BRIDGE:
359 err = m5602_write_bridge(sd,
360 VGA_s5k4aa[i][1],
361 VGA_s5k4aa[i][2]);
362 break;
363
364 case SENSOR:
365 data[0] = VGA_s5k4aa[i][2];
366 err = m5602_write_sensor(sd,
367 VGA_s5k4aa[i][1],
368 data, 1);
369 break;
370
371 case SENSOR_LONG:
372 data[0] = VGA_s5k4aa[i][2];
373 data[1] = VGA_s5k4aa[i][3];
374 err = m5602_write_sensor(sd,
375 VGA_s5k4aa[i][1],
376 data, 2);
377 break;
378
379 default:
380 err("Invalid stream command, exiting init");
381 return -EINVAL;
382 }
383 }
Grégory Lardière60d52ce2009-02-12 03:32:52 -0300384 err = s5k4aa_set_noise(&sd->gspca_dev, 1);
385 if (err < 0)
386 return err;
387 break;
Erik Andr?nad567ec2008-12-26 12:57:42 -0300388 }
Grégory Lardière9bc738f2009-02-12 03:40:29 -0300389 if (err < 0)
390 return err;
391
392 err = s5k4aa_set_exposure(&sd->gspca_dev,
393 sensor_settings[EXPOSURE_IDX]);
394 if (err < 0)
395 return err;
396
397 err = s5k4aa_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
398 if (err < 0)
399 return err;
400
401 err = s5k4aa_set_brightness(&sd->gspca_dev,
402 sensor_settings[BRIGHTNESS_IDX]);
403 if (err < 0)
404 return err;
405
406 err = s5k4aa_set_noise(&sd->gspca_dev, sensor_settings[NOISE_SUPP_IDX]);
407 if (err < 0)
408 return err;
409
410 err = s5k4aa_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
411 if (err < 0)
412 return err;
413
414 return s5k4aa_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
Erik Andr?nad567ec2008-12-26 12:57:42 -0300415}
416
Erik Andrenc109f812008-10-01 04:51:53 -0300417int s5k4aa_init(struct sd *sd)
418{
419 int i, err = 0;
420
421 for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) {
422 u8 data[2] = {0x00, 0x00};
423
424 switch (init_s5k4aa[i][0]) {
425 case BRIDGE:
426 err = m5602_write_bridge(sd,
427 init_s5k4aa[i][1],
428 init_s5k4aa[i][2]);
429 break;
430
431 case SENSOR:
432 data[0] = init_s5k4aa[i][2];
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300433 err = m5602_write_sensor(sd,
Erik Andrenc109f812008-10-01 04:51:53 -0300434 init_s5k4aa[i][1], data, 1);
435 break;
436
437 case SENSOR_LONG:
438 data[0] = init_s5k4aa[i][2];
439 data[1] = init_s5k4aa[i][3];
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300440 err = m5602_write_sensor(sd,
Erik Andrenc109f812008-10-01 04:51:53 -0300441 init_s5k4aa[i][1], data, 2);
442 break;
443 default:
444 info("Invalid stream command, exiting init");
445 return -EINVAL;
446 }
447 }
448
Erik Andr?n36e756c2009-01-09 13:35:00 -0300449 if (dump_sensor)
450 s5k4aa_dump_registers(sd);
451
Grégory Lardière9bc738f2009-02-12 03:40:29 -0300452 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300453}
454
Erik Andr?ncf811d52009-04-03 02:49:10 -0300455static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
Erik Andrenc109f812008-10-01 04:51:53 -0300456{
457 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?na594fb42009-01-06 11:37:03 -0300458 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300459
Erik Andr?na594fb42009-01-06 11:37:03 -0300460 *val = sensor_settings[EXPOSURE_IDX];
Erik Andren17ea88a2008-10-16 16:46:07 -0300461 PDEBUG(D_V4L2, "Read exposure %d", *val);
Erik Andr?n051781b2008-12-27 12:28:00 -0300462
Erik Andr?na594fb42009-01-06 11:37:03 -0300463 return 0;
Erik Andrenc109f812008-10-01 04:51:53 -0300464}
465
Erik Andr?ncf811d52009-04-03 02:49:10 -0300466static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
Erik Andrenc109f812008-10-01 04:51:53 -0300467{
468 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?na594fb42009-01-06 11:37:03 -0300469 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300470 u8 data = S5K4AA_PAGE_MAP_2;
471 int err;
472
Erik Andr?na594fb42009-01-06 11:37:03 -0300473 sensor_settings[EXPOSURE_IDX] = val;
Erik Andren17ea88a2008-10-16 16:46:07 -0300474 PDEBUG(D_V4L2, "Set exposure to %d", val);
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300475 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300476 if (err < 0)
Erik Andr?n051781b2008-12-27 12:28:00 -0300477 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300478 data = (val >> 8) & 0xff;
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300479 err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300480 if (err < 0)
Erik Andr?n051781b2008-12-27 12:28:00 -0300481 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300482 data = val & 0xff;
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300483 err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
Erik Andr?n051781b2008-12-27 12:28:00 -0300484
Erik Andrén32500702008-11-20 04:02:44 -0300485 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300486}
487
Erik Andr?ncf811d52009-04-03 02:49:10 -0300488static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
Erik Andrenc109f812008-10-01 04:51:53 -0300489{
490 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?na594fb42009-01-06 11:37:03 -0300491 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300492
Erik Andr?na594fb42009-01-06 11:37:03 -0300493 *val = sensor_settings[VFLIP_IDX];
Erik Andren17ea88a2008-10-16 16:46:07 -0300494 PDEBUG(D_V4L2, "Read vertical flip %d", *val);
Erik Andrenc109f812008-10-01 04:51:53 -0300495
Erik Andr?na594fb42009-01-06 11:37:03 -0300496 return 0;
Erik Andrenc109f812008-10-01 04:51:53 -0300497}
498
Erik Andr?ncf811d52009-04-03 02:49:10 -0300499static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
Erik Andrenc109f812008-10-01 04:51:53 -0300500{
501 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?na594fb42009-01-06 11:37:03 -0300502 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300503 u8 data = S5K4AA_PAGE_MAP_2;
504 int err;
505
Erik Andr?na594fb42009-01-06 11:37:03 -0300506 sensor_settings[VFLIP_IDX] = val;
507
Erik Andren17ea88a2008-10-16 16:46:07 -0300508 PDEBUG(D_V4L2, "Set vertical flip to %d", val);
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300509 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300510 if (err < 0)
Erik Andr?n051781b2008-12-27 12:28:00 -0300511 return err;
Erik Andr?na594fb42009-01-06 11:37:03 -0300512
Erik Andr?na68985d2009-01-13 15:44:03 -0300513 err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
514 if (err < 0)
515 return err;
516
Grégory Lardière9bc738f2009-02-12 03:40:29 -0300517 if (dmi_check_system(s5k4aa_vflip_dmi_table))
Erik Andr?na594fb42009-01-06 11:37:03 -0300518 val = !val;
519
Grégory Lardière9bc738f2009-02-12 03:40:29 -0300520 data = ((data & ~S5K4AA_RM_V_FLIP) | ((val & 0x01) << 7));
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300521 err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300522 if (err < 0)
Erik Andr?n051781b2008-12-27 12:28:00 -0300523 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300524
Grégory Lardière9bc738f2009-02-12 03:40:29 -0300525 err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
526 if (err < 0)
527 return err;
528 data = (data & 0xfe) | !val;
529 err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
Erik Andrén32500702008-11-20 04:02:44 -0300530 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300531}
532
Erik Andr?ncf811d52009-04-03 02:49:10 -0300533static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
Erik Andrenc109f812008-10-01 04:51:53 -0300534{
535 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?na594fb42009-01-06 11:37:03 -0300536 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300537
Erik Andr?na594fb42009-01-06 11:37:03 -0300538 *val = sensor_settings[HFLIP_IDX];
Erik Andren17ea88a2008-10-16 16:46:07 -0300539 PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
Erik Andr?n051781b2008-12-27 12:28:00 -0300540
Erik Andr?na594fb42009-01-06 11:37:03 -0300541 return 0;
Erik Andrenc109f812008-10-01 04:51:53 -0300542}
543
Erik Andr?ncf811d52009-04-03 02:49:10 -0300544static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
Erik Andrenc109f812008-10-01 04:51:53 -0300545{
546 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?na594fb42009-01-06 11:37:03 -0300547 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300548 u8 data = S5K4AA_PAGE_MAP_2;
549 int err;
550
Erik Andr?na594fb42009-01-06 11:37:03 -0300551 sensor_settings[HFLIP_IDX] = val;
552
553 PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300554 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300555 if (err < 0)
Erik Andr?n051781b2008-12-27 12:28:00 -0300556 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300557
Erik Andr?na68985d2009-01-13 15:44:03 -0300558 err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
559 if (err < 0)
560 return err;
561
Grégory Lardière9bc738f2009-02-12 03:40:29 -0300562 if (dmi_check_system(s5k4aa_vflip_dmi_table))
Erik Andrén2f17e1a2009-01-22 03:51:40 -0300563 val = !val;
Erik Andrén2f17e1a2009-01-22 03:51:40 -0300564
Erik Andrenc109f812008-10-01 04:51:53 -0300565 data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300566 err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300567 if (err < 0)
Erik Andr?n051781b2008-12-27 12:28:00 -0300568 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300569
Grégory Lardière9bc738f2009-02-12 03:40:29 -0300570 err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
571 if (err < 0)
572 return err;
573 data = (data & 0xfe) | !val;
574 err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
Erik Andrén32500702008-11-20 04:02:44 -0300575 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300576}
577
Erik Andr?ncf811d52009-04-03 02:49:10 -0300578static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
Erik Andrenc109f812008-10-01 04:51:53 -0300579{
580 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?na594fb42009-01-06 11:37:03 -0300581 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300582
Erik Andr?na594fb42009-01-06 11:37:03 -0300583 *val = sensor_settings[GAIN_IDX];
Erik Andren17ea88a2008-10-16 16:46:07 -0300584 PDEBUG(D_V4L2, "Read gain %d", *val);
Erik Andr?na594fb42009-01-06 11:37:03 -0300585 return 0;
Erik Andrenc109f812008-10-01 04:51:53 -0300586}
587
Erik Andr?ncf811d52009-04-03 02:49:10 -0300588static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
Erik Andrenc109f812008-10-01 04:51:53 -0300589{
590 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?na594fb42009-01-06 11:37:03 -0300591 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300592 u8 data = S5K4AA_PAGE_MAP_2;
593 int err;
594
Erik Andr?na594fb42009-01-06 11:37:03 -0300595 sensor_settings[GAIN_IDX] = val;
596
Erik Andren17ea88a2008-10-16 16:46:07 -0300597 PDEBUG(D_V4L2, "Set gain to %d", val);
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300598 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300599 if (err < 0)
Erik Andr?n051781b2008-12-27 12:28:00 -0300600 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300601
602 data = val & 0xff;
Erik Andr?n7ee46292009-01-14 03:37:03 -0300603 err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300604
Erik Andrén32500702008-11-20 04:02:44 -0300605 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300606}
607
Erik Andr?n7ee46292009-01-14 03:37:03 -0300608static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
609{
610 struct sd *sd = (struct sd *) gspca_dev;
611 s32 *sensor_settings = sd->sensor_priv;
612
613 *val = sensor_settings[BRIGHTNESS_IDX];
614 PDEBUG(D_V4L2, "Read brightness %d", *val);
615 return 0;
616}
617
618static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
619{
620 struct sd *sd = (struct sd *) gspca_dev;
621 s32 *sensor_settings = sd->sensor_priv;
622 u8 data = S5K4AA_PAGE_MAP_2;
623 int err;
624
625 sensor_settings[BRIGHTNESS_IDX] = val;
626
627 PDEBUG(D_V4L2, "Set brightness to %d", val);
628 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
629 if (err < 0)
630 return err;
631
632 data = val & 0xff;
633 return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1);
634}
635
Erik Andr?n3290d402009-01-13 16:40:28 -0300636static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val)
637{
638 struct sd *sd = (struct sd *) gspca_dev;
639 s32 *sensor_settings = sd->sensor_priv;
640
641 *val = sensor_settings[NOISE_SUPP_IDX];
642 PDEBUG(D_V4L2, "Read noise %d", *val);
643 return 0;
644}
645
646static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
647{
648 struct sd *sd = (struct sd *) gspca_dev;
649 s32 *sensor_settings = sd->sensor_priv;
650 u8 data = S5K4AA_PAGE_MAP_2;
651 int err;
652
653 sensor_settings[NOISE_SUPP_IDX] = val;
654
655 PDEBUG(D_V4L2, "Set noise to %d", val);
656 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
657 if (err < 0)
658 return err;
659
660 data = val & 0x01;
661 return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1);
662}
663
Erik Andr?na594fb42009-01-06 11:37:03 -0300664void s5k4aa_disconnect(struct sd *sd)
665{
666 sd->sensor = NULL;
667 kfree(sd->sensor_priv);
668}
669
Erik Andrén658efb62008-11-24 14:21:29 -0300670static void s5k4aa_dump_registers(struct sd *sd)
Erik Andrenc109f812008-10-01 04:51:53 -0300671{
672 int address;
673 u8 page, old_page;
Erik Andrén4feb24f2008-11-27 13:51:11 -0300674 m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300675 for (page = 0; page < 16; page++) {
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300676 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300677 info("Dumping the s5k4aa register state for page 0x%x", page);
678 for (address = 0; address <= 0xff; address++) {
679 u8 value = 0;
Erik Andrén4feb24f2008-11-27 13:51:11 -0300680 m5602_read_sensor(sd, address, &value, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300681 info("register 0x%x contains 0x%x",
682 address, value);
683 }
684 }
685 info("s5k4aa register state dump complete");
686
687 for (page = 0; page < 16; page++) {
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300688 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300689 info("Probing for which registers that are "
690 "read/write for page 0x%x", page);
691 for (address = 0; address <= 0xff; address++) {
692 u8 old_value, ctrl_value, test_value = 0xff;
693
Erik Andrén4feb24f2008-11-27 13:51:11 -0300694 m5602_read_sensor(sd, address, &old_value, 1);
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300695 m5602_write_sensor(sd, address, &test_value, 1);
Erik Andrén4feb24f2008-11-27 13:51:11 -0300696 m5602_read_sensor(sd, address, &ctrl_value, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300697
698 if (ctrl_value == test_value)
699 info("register 0x%x is writeable", address);
700 else
701 info("register 0x%x is read only", address);
702
703 /* Restore original value */
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300704 m5602_write_sensor(sd, address, &old_value, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300705 }
706 }
707 info("Read/write register probing complete");
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300708 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300709}