blob: 59400e85896511781a7246148851966f08848844 [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 {
38 .ident = "Fujitsu-Siemens Amilo Xa 2528",
39 .matches = {
40 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
41 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528")
42 }
43 }, {
44 .ident = "Fujitsu-Siemens Amilo Xi 2550",
45 .matches = {
46 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
47 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550")
48 }
49 }, {
Erik Andrén97606772009-07-01 02:49:23 -030050 .ident = "Fujitsu-Siemens Amilo Pa 2548",
51 .matches = {
52 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
53 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2548")
54 }
55 }, {
Erik Andrén579ef872008-11-18 14:38:10 -030056 .ident = "MSI GX700",
57 .matches = {
58 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
59 DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
60 DMI_MATCH(DMI_BIOS_DATE, "07/26/2007")
61 }
62 }, {
Brian Kloppenborg95e6dcd2009-08-30 09:43:40 -030063 .ident = "MSI GX700",
64 .matches = {
65 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
66 DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
67 DMI_MATCH(DMI_BIOS_DATE, "07/19/2007")
68 }
69 }, {
Erik Andrén579ef872008-11-18 14:38:10 -030070 .ident = "MSI GX700/GX705/EX700",
71 .matches = {
72 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
73 DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700")
74 }
Erik Andrén79c35762009-02-12 16:36:05 -030075 }, {
76 .ident = "MSI L735",
77 .matches = {
78 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
79 DMI_MATCH(DMI_PRODUCT_NAME, "MS-1717X")
80 }
Erik Andrénf02c3942009-05-06 17:44:45 -030081 }, {
82 .ident = "Lenovo Y300",
83 .matches = {
84 DMI_MATCH(DMI_SYS_VENDOR, "L3000 Y300"),
85 DMI_MATCH(DMI_PRODUCT_NAME, "Y300")
86 }
Erik Andrén579ef872008-11-18 14:38:10 -030087 },
88 { }
89};
90
Erik Andr?n74cadfe2008-12-30 16:48:42 -030091static struct v4l2_pix_format s5k4aa_modes[] = {
92 {
93 640,
94 480,
95 V4L2_PIX_FMT_SBGGR8,
96 V4L2_FIELD_NONE,
97 .sizeimage =
98 640 * 480,
99 .bytesperline = 640,
100 .colorspace = V4L2_COLORSPACE_SRGB,
101 .priv = 0
Grégory Lardière60d52ce2009-02-12 03:32:52 -0300102 },
103 {
104 1280,
105 1024,
106 V4L2_PIX_FMT_SBGGR8,
107 V4L2_FIELD_NONE,
108 .sizeimage =
109 1280 * 1024,
110 .bytesperline = 1280,
111 .colorspace = V4L2_COLORSPACE_SRGB,
112 .priv = 0
Erik Andr?n74cadfe2008-12-30 16:48:42 -0300113 }
114};
115
Tobias Klauser2e036692009-04-26 09:30:18 -0300116static const struct ctrl s5k4aa_ctrls[] = {
Erik Andr?na594fb42009-01-06 11:37:03 -0300117#define VFLIP_IDX 0
Erik Andr?ne17cc082008-12-30 17:06:55 -0300118 {
119 {
120 .id = V4L2_CID_VFLIP,
121 .type = V4L2_CTRL_TYPE_BOOLEAN,
122 .name = "vertical flip",
123 .minimum = 0,
124 .maximum = 1,
125 .step = 1,
126 .default_value = 0
127 },
128 .set = s5k4aa_set_vflip,
129 .get = s5k4aa_get_vflip
Erik Andr?na594fb42009-01-06 11:37:03 -0300130 },
131#define HFLIP_IDX 1
132 {
Erik Andr?ne17cc082008-12-30 17:06:55 -0300133 {
134 .id = V4L2_CID_HFLIP,
135 .type = V4L2_CTRL_TYPE_BOOLEAN,
136 .name = "horizontal flip",
137 .minimum = 0,
138 .maximum = 1,
139 .step = 1,
140 .default_value = 0
141 },
142 .set = s5k4aa_set_hflip,
143 .get = s5k4aa_get_hflip
Erik Andr?na594fb42009-01-06 11:37:03 -0300144 },
145#define GAIN_IDX 2
146 {
Erik Andr?ne17cc082008-12-30 17:06:55 -0300147 {
148 .id = V4L2_CID_GAIN,
149 .type = V4L2_CTRL_TYPE_INTEGER,
150 .name = "Gain",
151 .minimum = 0,
152 .maximum = 127,
153 .step = 1,
Erik Andr?n7ee46292009-01-14 03:37:03 -0300154 .default_value = S5K4AA_DEFAULT_GAIN,
Erik Andr?ne17cc082008-12-30 17:06:55 -0300155 .flags = V4L2_CTRL_FLAG_SLIDER
156 },
157 .set = s5k4aa_set_gain,
158 .get = s5k4aa_get_gain
Erik Andr?na594fb42009-01-06 11:37:03 -0300159 },
160#define EXPOSURE_IDX 3
161 {
Erik Andr?ne17cc082008-12-30 17:06:55 -0300162 {
163 .id = V4L2_CID_EXPOSURE,
164 .type = V4L2_CTRL_TYPE_INTEGER,
165 .name = "Exposure",
166 .minimum = 13,
167 .maximum = 0xfff,
168 .step = 1,
169 .default_value = 0x100,
170 .flags = V4L2_CTRL_FLAG_SLIDER
171 },
172 .set = s5k4aa_set_exposure,
173 .get = s5k4aa_get_exposure
Erik Andr?n3290d402009-01-13 16:40:28 -0300174 },
175#define NOISE_SUPP_IDX 4
176 {
177 {
178 .id = V4L2_CID_PRIVATE_BASE,
179 .type = V4L2_CTRL_TYPE_BOOLEAN,
180 .name = "Noise suppression (smoothing)",
181 .minimum = 0,
182 .maximum = 1,
183 .step = 1,
184 .default_value = 1,
185 },
186 .set = s5k4aa_set_noise,
187 .get = s5k4aa_get_noise
188 },
Erik Andr?n7ee46292009-01-14 03:37:03 -0300189#define BRIGHTNESS_IDX 5
190 {
191 {
192 .id = V4L2_CID_BRIGHTNESS,
193 .type = V4L2_CTRL_TYPE_INTEGER,
194 .name = "Brightness",
195 .minimum = 0,
196 .maximum = 0x1f,
197 .step = 1,
198 .default_value = S5K4AA_DEFAULT_BRIGHTNESS,
199 },
200 .set = s5k4aa_set_brightness,
201 .get = s5k4aa_get_brightness
202 },
203
Erik Andr?ne17cc082008-12-30 17:06:55 -0300204};
205
Erik Andrén658efb62008-11-24 14:21:29 -0300206static void s5k4aa_dump_registers(struct sd *sd);
Erik Andrén579ef872008-11-18 14:38:10 -0300207
Erik Andrenc109f812008-10-01 04:51:53 -0300208int s5k4aa_probe(struct sd *sd)
209{
210 u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
211 const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
212 int i, err = 0;
Erik Andr?na594fb42009-01-06 11:37:03 -0300213 s32 *sensor_settings;
Erik Andrenc109f812008-10-01 04:51:53 -0300214
215 if (force_sensor) {
216 if (force_sensor == S5K4AA_SENSOR) {
217 info("Forcing a %s sensor", s5k4aa.name);
218 goto sensor_found;
219 }
220 /* If we want to force another sensor, don't try to probe this
221 * one */
222 return -ENODEV;
223 }
224
225 info("Probing for a s5k4aa sensor");
226
227 /* Preinit the sensor */
228 for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) {
229 u8 data[2] = {0x00, 0x00};
230
231 switch (preinit_s5k4aa[i][0]) {
232 case BRIDGE:
233 err = m5602_write_bridge(sd,
234 preinit_s5k4aa[i][1],
235 preinit_s5k4aa[i][2]);
236 break;
237
238 case SENSOR:
239 data[0] = preinit_s5k4aa[i][2];
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300240 err = m5602_write_sensor(sd,
Erik Andrenc109f812008-10-01 04:51:53 -0300241 preinit_s5k4aa[i][1],
242 data, 1);
243 break;
244
245 case SENSOR_LONG:
246 data[0] = preinit_s5k4aa[i][2];
247 data[1] = preinit_s5k4aa[i][3];
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300248 err = m5602_write_sensor(sd,
Erik Andrenc109f812008-10-01 04:51:53 -0300249 preinit_s5k4aa[i][1],
250 data, 2);
251 break;
252 default:
253 info("Invalid stream command, exiting init");
254 return -EINVAL;
255 }
256 }
257
258 /* Test some registers, but we don't know their exact meaning yet */
Gregory Lardiered2c45232009-02-22 17:54:11 -0300259 if (m5602_read_sensor(sd, 0x00, prod_id, 2))
260 return -ENODEV;
261 if (m5602_read_sensor(sd, 0x02, prod_id+2, 2))
262 return -ENODEV;
263 if (m5602_read_sensor(sd, 0x04, prod_id+4, 2))
Erik Andrenc109f812008-10-01 04:51:53 -0300264 return -ENODEV;
265
266 if (memcmp(prod_id, expected_prod_id, sizeof(prod_id)))
267 return -ENODEV;
268 else
269 info("Detected a s5k4aa sensor");
Erik Andrén32500702008-11-20 04:02:44 -0300270
Erik Andrenc109f812008-10-01 04:51:53 -0300271sensor_found:
Erik Andr?na594fb42009-01-06 11:37:03 -0300272 sensor_settings = kmalloc(
273 ARRAY_SIZE(s5k4aa_ctrls) * sizeof(s32), GFP_KERNEL);
274 if (!sensor_settings)
275 return -ENOMEM;
276
Erik Andr?n74cadfe2008-12-30 16:48:42 -0300277 sd->gspca_dev.cam.cam_mode = s5k4aa_modes;
278 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes);
Erik Andr?ne17cc082008-12-30 17:06:55 -0300279 sd->desc->ctrls = s5k4aa_ctrls;
Erik Andr?ne4cc4fc2008-12-30 15:27:17 -0300280 sd->desc->nctrls = ARRAY_SIZE(s5k4aa_ctrls);
Erik Andr?na594fb42009-01-06 11:37:03 -0300281
282 for (i = 0; i < ARRAY_SIZE(s5k4aa_ctrls); i++)
283 sensor_settings[i] = s5k4aa_ctrls[i].qctrl.default_value;
284 sd->sensor_priv = sensor_settings;
Erik Andr?nd4a389a2009-01-09 03:30:54 -0300285
Erik Andrenc109f812008-10-01 04:51:53 -0300286 return 0;
287}
288
Erik Andr?nad567ec2008-12-26 12:57:42 -0300289int s5k4aa_start(struct sd *sd)
290{
291 int i, err = 0;
292 u8 data[2];
293 struct cam *cam = &sd->gspca_dev.cam;
Grégory Lardière9bc738f2009-02-12 03:40:29 -0300294 s32 *sensor_settings = sd->sensor_priv;
Erik Andr?nad567ec2008-12-26 12:57:42 -0300295
Erik Andr?nd4a389a2009-01-09 03:30:54 -0300296 switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) {
Erik Andrén4fcec142009-01-29 13:34:41 -0300297 case 1280:
298 PDEBUG(D_V4L2, "Configuring camera for SXGA mode");
299
300 for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) {
301 switch (SXGA_s5k4aa[i][0]) {
302 case BRIDGE:
303 err = m5602_write_bridge(sd,
304 SXGA_s5k4aa[i][1],
305 SXGA_s5k4aa[i][2]);
306 break;
307
308 case SENSOR:
309 data[0] = SXGA_s5k4aa[i][2];
310 err = m5602_write_sensor(sd,
311 SXGA_s5k4aa[i][1],
312 data, 1);
313 break;
314
315 case SENSOR_LONG:
316 data[0] = SXGA_s5k4aa[i][2];
317 data[1] = SXGA_s5k4aa[i][3];
318 err = m5602_write_sensor(sd,
319 SXGA_s5k4aa[i][1],
320 data, 2);
321 break;
322
323 default:
324 err("Invalid stream command, exiting init");
325 return -EINVAL;
326 }
327 }
Grégory Lardière60d52ce2009-02-12 03:32:52 -0300328 err = s5k4aa_set_noise(&sd->gspca_dev, 0);
329 if (err < 0)
330 return err;
331 break;
Erik Andrén4fcec142009-01-29 13:34:41 -0300332
Erik Andr?nad567ec2008-12-26 12:57:42 -0300333 case 640:
334 PDEBUG(D_V4L2, "Configuring camera for VGA mode");
335
336 for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) {
337 switch (VGA_s5k4aa[i][0]) {
338 case BRIDGE:
339 err = m5602_write_bridge(sd,
340 VGA_s5k4aa[i][1],
341 VGA_s5k4aa[i][2]);
342 break;
343
344 case SENSOR:
345 data[0] = VGA_s5k4aa[i][2];
346 err = m5602_write_sensor(sd,
347 VGA_s5k4aa[i][1],
348 data, 1);
349 break;
350
351 case SENSOR_LONG:
352 data[0] = VGA_s5k4aa[i][2];
353 data[1] = VGA_s5k4aa[i][3];
354 err = m5602_write_sensor(sd,
355 VGA_s5k4aa[i][1],
356 data, 2);
357 break;
358
359 default:
360 err("Invalid stream command, exiting init");
361 return -EINVAL;
362 }
363 }
Grégory Lardière60d52ce2009-02-12 03:32:52 -0300364 err = s5k4aa_set_noise(&sd->gspca_dev, 1);
365 if (err < 0)
366 return err;
367 break;
Erik Andr?nad567ec2008-12-26 12:57:42 -0300368 }
Grégory Lardière9bc738f2009-02-12 03:40:29 -0300369 if (err < 0)
370 return err;
371
372 err = s5k4aa_set_exposure(&sd->gspca_dev,
373 sensor_settings[EXPOSURE_IDX]);
374 if (err < 0)
375 return err;
376
377 err = s5k4aa_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
378 if (err < 0)
379 return err;
380
381 err = s5k4aa_set_brightness(&sd->gspca_dev,
382 sensor_settings[BRIGHTNESS_IDX]);
383 if (err < 0)
384 return err;
385
386 err = s5k4aa_set_noise(&sd->gspca_dev, sensor_settings[NOISE_SUPP_IDX]);
387 if (err < 0)
388 return err;
389
390 err = s5k4aa_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
391 if (err < 0)
392 return err;
393
394 return s5k4aa_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
Erik Andr?nad567ec2008-12-26 12:57:42 -0300395}
396
Erik Andrenc109f812008-10-01 04:51:53 -0300397int s5k4aa_init(struct sd *sd)
398{
399 int i, err = 0;
400
401 for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) {
402 u8 data[2] = {0x00, 0x00};
403
404 switch (init_s5k4aa[i][0]) {
405 case BRIDGE:
406 err = m5602_write_bridge(sd,
407 init_s5k4aa[i][1],
408 init_s5k4aa[i][2]);
409 break;
410
411 case SENSOR:
412 data[0] = init_s5k4aa[i][2];
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300413 err = m5602_write_sensor(sd,
Erik Andrenc109f812008-10-01 04:51:53 -0300414 init_s5k4aa[i][1], data, 1);
415 break;
416
417 case SENSOR_LONG:
418 data[0] = init_s5k4aa[i][2];
419 data[1] = init_s5k4aa[i][3];
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300420 err = m5602_write_sensor(sd,
Erik Andrenc109f812008-10-01 04:51:53 -0300421 init_s5k4aa[i][1], data, 2);
422 break;
423 default:
424 info("Invalid stream command, exiting init");
425 return -EINVAL;
426 }
427 }
428
Erik Andr?n36e756c2009-01-09 13:35:00 -0300429 if (dump_sensor)
430 s5k4aa_dump_registers(sd);
431
Grégory Lardière9bc738f2009-02-12 03:40:29 -0300432 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300433}
434
Erik Andr?ncf811d52009-04-03 02:49:10 -0300435static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
Erik Andrenc109f812008-10-01 04:51:53 -0300436{
437 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?na594fb42009-01-06 11:37:03 -0300438 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300439
Erik Andr?na594fb42009-01-06 11:37:03 -0300440 *val = sensor_settings[EXPOSURE_IDX];
Erik Andren17ea88a2008-10-16 16:46:07 -0300441 PDEBUG(D_V4L2, "Read exposure %d", *val);
Erik Andr?n051781b2008-12-27 12:28:00 -0300442
Erik Andr?na594fb42009-01-06 11:37:03 -0300443 return 0;
Erik Andrenc109f812008-10-01 04:51:53 -0300444}
445
Erik Andr?ncf811d52009-04-03 02:49:10 -0300446static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
Erik Andrenc109f812008-10-01 04:51:53 -0300447{
448 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?na594fb42009-01-06 11:37:03 -0300449 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300450 u8 data = S5K4AA_PAGE_MAP_2;
451 int err;
452
Erik Andr?na594fb42009-01-06 11:37:03 -0300453 sensor_settings[EXPOSURE_IDX] = val;
Erik Andren17ea88a2008-10-16 16:46:07 -0300454 PDEBUG(D_V4L2, "Set exposure to %d", val);
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300455 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300456 if (err < 0)
Erik Andr?n051781b2008-12-27 12:28:00 -0300457 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300458 data = (val >> 8) & 0xff;
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300459 err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300460 if (err < 0)
Erik Andr?n051781b2008-12-27 12:28:00 -0300461 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300462 data = val & 0xff;
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300463 err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
Erik Andr?n051781b2008-12-27 12:28:00 -0300464
Erik Andrén32500702008-11-20 04:02:44 -0300465 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300466}
467
Erik Andr?ncf811d52009-04-03 02:49:10 -0300468static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
Erik Andrenc109f812008-10-01 04:51:53 -0300469{
470 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?na594fb42009-01-06 11:37:03 -0300471 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300472
Erik Andr?na594fb42009-01-06 11:37:03 -0300473 *val = sensor_settings[VFLIP_IDX];
Erik Andren17ea88a2008-10-16 16:46:07 -0300474 PDEBUG(D_V4L2, "Read vertical flip %d", *val);
Erik Andrenc109f812008-10-01 04:51:53 -0300475
Erik Andr?na594fb42009-01-06 11:37:03 -0300476 return 0;
Erik Andrenc109f812008-10-01 04:51:53 -0300477}
478
Erik Andr?ncf811d52009-04-03 02:49:10 -0300479static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
Erik Andrenc109f812008-10-01 04:51:53 -0300480{
481 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?na594fb42009-01-06 11:37:03 -0300482 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300483 u8 data = S5K4AA_PAGE_MAP_2;
484 int err;
485
Erik Andr?na594fb42009-01-06 11:37:03 -0300486 sensor_settings[VFLIP_IDX] = val;
487
Erik Andren17ea88a2008-10-16 16:46:07 -0300488 PDEBUG(D_V4L2, "Set vertical flip to %d", val);
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300489 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300490 if (err < 0)
Erik Andr?n051781b2008-12-27 12:28:00 -0300491 return err;
Erik Andr?na594fb42009-01-06 11:37:03 -0300492
Erik Andr?na68985d2009-01-13 15:44:03 -0300493 err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
494 if (err < 0)
495 return err;
496
Grégory Lardière9bc738f2009-02-12 03:40:29 -0300497 if (dmi_check_system(s5k4aa_vflip_dmi_table))
Erik Andr?na594fb42009-01-06 11:37:03 -0300498 val = !val;
499
Grégory Lardière9bc738f2009-02-12 03:40:29 -0300500 data = ((data & ~S5K4AA_RM_V_FLIP) | ((val & 0x01) << 7));
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300501 err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300502 if (err < 0)
Erik Andr?n051781b2008-12-27 12:28:00 -0300503 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300504
Grégory Lardière9bc738f2009-02-12 03:40:29 -0300505 err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
506 if (err < 0)
507 return err;
508 data = (data & 0xfe) | !val;
509 err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
Erik Andrén32500702008-11-20 04:02:44 -0300510 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300511}
512
Erik Andr?ncf811d52009-04-03 02:49:10 -0300513static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
Erik Andrenc109f812008-10-01 04:51:53 -0300514{
515 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?na594fb42009-01-06 11:37:03 -0300516 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300517
Erik Andr?na594fb42009-01-06 11:37:03 -0300518 *val = sensor_settings[HFLIP_IDX];
Erik Andren17ea88a2008-10-16 16:46:07 -0300519 PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
Erik Andr?n051781b2008-12-27 12:28:00 -0300520
Erik Andr?na594fb42009-01-06 11:37:03 -0300521 return 0;
Erik Andrenc109f812008-10-01 04:51:53 -0300522}
523
Erik Andr?ncf811d52009-04-03 02:49:10 -0300524static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
Erik Andrenc109f812008-10-01 04:51:53 -0300525{
526 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?na594fb42009-01-06 11:37:03 -0300527 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300528 u8 data = S5K4AA_PAGE_MAP_2;
529 int err;
530
Erik Andr?na594fb42009-01-06 11:37:03 -0300531 sensor_settings[HFLIP_IDX] = val;
532
533 PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300534 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300535 if (err < 0)
Erik Andr?n051781b2008-12-27 12:28:00 -0300536 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300537
Erik Andr?na68985d2009-01-13 15:44:03 -0300538 err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
539 if (err < 0)
540 return err;
541
Grégory Lardière9bc738f2009-02-12 03:40:29 -0300542 if (dmi_check_system(s5k4aa_vflip_dmi_table))
Erik Andrén2f17e1a2009-01-22 03:51:40 -0300543 val = !val;
Erik Andrén2f17e1a2009-01-22 03:51:40 -0300544
Erik Andrenc109f812008-10-01 04:51:53 -0300545 data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300546 err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300547 if (err < 0)
Erik Andr?n051781b2008-12-27 12:28:00 -0300548 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300549
Grégory Lardière9bc738f2009-02-12 03:40:29 -0300550 err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
551 if (err < 0)
552 return err;
553 data = (data & 0xfe) | !val;
554 err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
Erik Andrén32500702008-11-20 04:02:44 -0300555 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300556}
557
Erik Andr?ncf811d52009-04-03 02:49:10 -0300558static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
Erik Andrenc109f812008-10-01 04:51:53 -0300559{
560 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?na594fb42009-01-06 11:37:03 -0300561 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300562
Erik Andr?na594fb42009-01-06 11:37:03 -0300563 *val = sensor_settings[GAIN_IDX];
Erik Andren17ea88a2008-10-16 16:46:07 -0300564 PDEBUG(D_V4L2, "Read gain %d", *val);
Erik Andr?na594fb42009-01-06 11:37:03 -0300565 return 0;
Erik Andrenc109f812008-10-01 04:51:53 -0300566}
567
Erik Andr?ncf811d52009-04-03 02:49:10 -0300568static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
Erik Andrenc109f812008-10-01 04:51:53 -0300569{
570 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?na594fb42009-01-06 11:37:03 -0300571 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300572 u8 data = S5K4AA_PAGE_MAP_2;
573 int err;
574
Erik Andr?na594fb42009-01-06 11:37:03 -0300575 sensor_settings[GAIN_IDX] = val;
576
Erik Andren17ea88a2008-10-16 16:46:07 -0300577 PDEBUG(D_V4L2, "Set gain to %d", val);
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300578 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300579 if (err < 0)
Erik Andr?n051781b2008-12-27 12:28:00 -0300580 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300581
582 data = val & 0xff;
Erik Andr?n7ee46292009-01-14 03:37:03 -0300583 err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300584
Erik Andrén32500702008-11-20 04:02:44 -0300585 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300586}
587
Erik Andr?n7ee46292009-01-14 03:37:03 -0300588static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
589{
590 struct sd *sd = (struct sd *) gspca_dev;
591 s32 *sensor_settings = sd->sensor_priv;
592
593 *val = sensor_settings[BRIGHTNESS_IDX];
594 PDEBUG(D_V4L2, "Read brightness %d", *val);
595 return 0;
596}
597
598static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
599{
600 struct sd *sd = (struct sd *) gspca_dev;
601 s32 *sensor_settings = sd->sensor_priv;
602 u8 data = S5K4AA_PAGE_MAP_2;
603 int err;
604
605 sensor_settings[BRIGHTNESS_IDX] = val;
606
607 PDEBUG(D_V4L2, "Set brightness to %d", val);
608 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
609 if (err < 0)
610 return err;
611
612 data = val & 0xff;
613 return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1);
614}
615
Erik Andr?n3290d402009-01-13 16:40:28 -0300616static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val)
617{
618 struct sd *sd = (struct sd *) gspca_dev;
619 s32 *sensor_settings = sd->sensor_priv;
620
621 *val = sensor_settings[NOISE_SUPP_IDX];
622 PDEBUG(D_V4L2, "Read noise %d", *val);
623 return 0;
624}
625
626static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
627{
628 struct sd *sd = (struct sd *) gspca_dev;
629 s32 *sensor_settings = sd->sensor_priv;
630 u8 data = S5K4AA_PAGE_MAP_2;
631 int err;
632
633 sensor_settings[NOISE_SUPP_IDX] = val;
634
635 PDEBUG(D_V4L2, "Set noise to %d", val);
636 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
637 if (err < 0)
638 return err;
639
640 data = val & 0x01;
641 return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1);
642}
643
Erik Andr?na594fb42009-01-06 11:37:03 -0300644void s5k4aa_disconnect(struct sd *sd)
645{
646 sd->sensor = NULL;
647 kfree(sd->sensor_priv);
648}
649
Erik Andrén658efb62008-11-24 14:21:29 -0300650static void s5k4aa_dump_registers(struct sd *sd)
Erik Andrenc109f812008-10-01 04:51:53 -0300651{
652 int address;
653 u8 page, old_page;
Erik Andrén4feb24f2008-11-27 13:51:11 -0300654 m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300655 for (page = 0; page < 16; page++) {
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300656 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300657 info("Dumping the s5k4aa register state for page 0x%x", page);
658 for (address = 0; address <= 0xff; address++) {
659 u8 value = 0;
Erik Andrén4feb24f2008-11-27 13:51:11 -0300660 m5602_read_sensor(sd, address, &value, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300661 info("register 0x%x contains 0x%x",
662 address, value);
663 }
664 }
665 info("s5k4aa register state dump complete");
666
667 for (page = 0; page < 16; page++) {
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300668 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300669 info("Probing for which registers that are "
670 "read/write for page 0x%x", page);
671 for (address = 0; address <= 0xff; address++) {
672 u8 old_value, ctrl_value, test_value = 0xff;
673
Erik Andrén4feb24f2008-11-27 13:51:11 -0300674 m5602_read_sensor(sd, address, &old_value, 1);
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300675 m5602_write_sensor(sd, address, &test_value, 1);
Erik Andrén4feb24f2008-11-27 13:51:11 -0300676 m5602_read_sensor(sd, address, &ctrl_value, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300677
678 if (ctrl_value == test_value)
679 info("register 0x%x is writeable", address);
680 else
681 info("register 0x%x is read only", address);
682
683 /* Restore original value */
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300684 m5602_write_sensor(sd, address, &old_value, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300685 }
686 }
687 info("Read/write register probing complete");
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300688 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300689}