blob: 0163903d1c0fb4a5dbbe0ec0a0b5bd5fa1b11284 [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 }, {
50 .ident = "MSI GX700",
51 .matches = {
52 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
53 DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
54 DMI_MATCH(DMI_BIOS_DATE, "07/26/2007")
55 }
56 }, {
57 .ident = "MSI GX700/GX705/EX700",
58 .matches = {
59 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
60 DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700")
61 }
Erik Andrén79c35762009-02-12 16:36:05 -030062 }, {
63 .ident = "MSI L735",
64 .matches = {
65 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
66 DMI_MATCH(DMI_PRODUCT_NAME, "MS-1717X")
67 }
Erik Andrénf02c3942009-05-06 17:44:45 -030068 }, {
69 .ident = "Lenovo Y300",
70 .matches = {
71 DMI_MATCH(DMI_SYS_VENDOR, "L3000 Y300"),
72 DMI_MATCH(DMI_PRODUCT_NAME, "Y300")
73 }
Erik Andrén579ef872008-11-18 14:38:10 -030074 },
75 { }
76};
77
Erik Andr?n74cadfe2008-12-30 16:48:42 -030078static struct v4l2_pix_format s5k4aa_modes[] = {
79 {
80 640,
81 480,
82 V4L2_PIX_FMT_SBGGR8,
83 V4L2_FIELD_NONE,
84 .sizeimage =
85 640 * 480,
86 .bytesperline = 640,
87 .colorspace = V4L2_COLORSPACE_SRGB,
88 .priv = 0
Grégory Lardière60d52ce2009-02-12 03:32:52 -030089 },
90 {
91 1280,
92 1024,
93 V4L2_PIX_FMT_SBGGR8,
94 V4L2_FIELD_NONE,
95 .sizeimage =
96 1280 * 1024,
97 .bytesperline = 1280,
98 .colorspace = V4L2_COLORSPACE_SRGB,
99 .priv = 0
Erik Andr?n74cadfe2008-12-30 16:48:42 -0300100 }
101};
102
Tobias Klauser2e036692009-04-26 09:30:18 -0300103static const struct ctrl s5k4aa_ctrls[] = {
Erik Andr?na594fb42009-01-06 11:37:03 -0300104#define VFLIP_IDX 0
Erik Andr?ne17cc082008-12-30 17:06:55 -0300105 {
106 {
107 .id = V4L2_CID_VFLIP,
108 .type = V4L2_CTRL_TYPE_BOOLEAN,
109 .name = "vertical flip",
110 .minimum = 0,
111 .maximum = 1,
112 .step = 1,
113 .default_value = 0
114 },
115 .set = s5k4aa_set_vflip,
116 .get = s5k4aa_get_vflip
Erik Andr?na594fb42009-01-06 11:37:03 -0300117 },
118#define HFLIP_IDX 1
119 {
Erik Andr?ne17cc082008-12-30 17:06:55 -0300120 {
121 .id = V4L2_CID_HFLIP,
122 .type = V4L2_CTRL_TYPE_BOOLEAN,
123 .name = "horizontal flip",
124 .minimum = 0,
125 .maximum = 1,
126 .step = 1,
127 .default_value = 0
128 },
129 .set = s5k4aa_set_hflip,
130 .get = s5k4aa_get_hflip
Erik Andr?na594fb42009-01-06 11:37:03 -0300131 },
132#define GAIN_IDX 2
133 {
Erik Andr?ne17cc082008-12-30 17:06:55 -0300134 {
135 .id = V4L2_CID_GAIN,
136 .type = V4L2_CTRL_TYPE_INTEGER,
137 .name = "Gain",
138 .minimum = 0,
139 .maximum = 127,
140 .step = 1,
Erik Andr?n7ee46292009-01-14 03:37:03 -0300141 .default_value = S5K4AA_DEFAULT_GAIN,
Erik Andr?ne17cc082008-12-30 17:06:55 -0300142 .flags = V4L2_CTRL_FLAG_SLIDER
143 },
144 .set = s5k4aa_set_gain,
145 .get = s5k4aa_get_gain
Erik Andr?na594fb42009-01-06 11:37:03 -0300146 },
147#define EXPOSURE_IDX 3
148 {
Erik Andr?ne17cc082008-12-30 17:06:55 -0300149 {
150 .id = V4L2_CID_EXPOSURE,
151 .type = V4L2_CTRL_TYPE_INTEGER,
152 .name = "Exposure",
153 .minimum = 13,
154 .maximum = 0xfff,
155 .step = 1,
156 .default_value = 0x100,
157 .flags = V4L2_CTRL_FLAG_SLIDER
158 },
159 .set = s5k4aa_set_exposure,
160 .get = s5k4aa_get_exposure
Erik Andr?n3290d402009-01-13 16:40:28 -0300161 },
162#define NOISE_SUPP_IDX 4
163 {
164 {
165 .id = V4L2_CID_PRIVATE_BASE,
166 .type = V4L2_CTRL_TYPE_BOOLEAN,
167 .name = "Noise suppression (smoothing)",
168 .minimum = 0,
169 .maximum = 1,
170 .step = 1,
171 .default_value = 1,
172 },
173 .set = s5k4aa_set_noise,
174 .get = s5k4aa_get_noise
175 },
Erik Andr?n7ee46292009-01-14 03:37:03 -0300176#define BRIGHTNESS_IDX 5
177 {
178 {
179 .id = V4L2_CID_BRIGHTNESS,
180 .type = V4L2_CTRL_TYPE_INTEGER,
181 .name = "Brightness",
182 .minimum = 0,
183 .maximum = 0x1f,
184 .step = 1,
185 .default_value = S5K4AA_DEFAULT_BRIGHTNESS,
186 },
187 .set = s5k4aa_set_brightness,
188 .get = s5k4aa_get_brightness
189 },
190
Erik Andr?ne17cc082008-12-30 17:06:55 -0300191};
192
Erik Andrén658efb62008-11-24 14:21:29 -0300193static void s5k4aa_dump_registers(struct sd *sd);
Erik Andrén579ef872008-11-18 14:38:10 -0300194
Erik Andrenc109f812008-10-01 04:51:53 -0300195int s5k4aa_probe(struct sd *sd)
196{
197 u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
198 const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
199 int i, err = 0;
Erik Andr?na594fb42009-01-06 11:37:03 -0300200 s32 *sensor_settings;
Erik Andrenc109f812008-10-01 04:51:53 -0300201
202 if (force_sensor) {
203 if (force_sensor == S5K4AA_SENSOR) {
204 info("Forcing a %s sensor", s5k4aa.name);
205 goto sensor_found;
206 }
207 /* If we want to force another sensor, don't try to probe this
208 * one */
209 return -ENODEV;
210 }
211
212 info("Probing for a s5k4aa sensor");
213
214 /* Preinit the sensor */
215 for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) {
216 u8 data[2] = {0x00, 0x00};
217
218 switch (preinit_s5k4aa[i][0]) {
219 case BRIDGE:
220 err = m5602_write_bridge(sd,
221 preinit_s5k4aa[i][1],
222 preinit_s5k4aa[i][2]);
223 break;
224
225 case SENSOR:
226 data[0] = preinit_s5k4aa[i][2];
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300227 err = m5602_write_sensor(sd,
Erik Andrenc109f812008-10-01 04:51:53 -0300228 preinit_s5k4aa[i][1],
229 data, 1);
230 break;
231
232 case SENSOR_LONG:
233 data[0] = preinit_s5k4aa[i][2];
234 data[1] = preinit_s5k4aa[i][3];
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300235 err = m5602_write_sensor(sd,
Erik Andrenc109f812008-10-01 04:51:53 -0300236 preinit_s5k4aa[i][1],
237 data, 2);
238 break;
239 default:
240 info("Invalid stream command, exiting init");
241 return -EINVAL;
242 }
243 }
244
245 /* Test some registers, but we don't know their exact meaning yet */
Gregory Lardiered2c45232009-02-22 17:54:11 -0300246 if (m5602_read_sensor(sd, 0x00, prod_id, 2))
247 return -ENODEV;
248 if (m5602_read_sensor(sd, 0x02, prod_id+2, 2))
249 return -ENODEV;
250 if (m5602_read_sensor(sd, 0x04, prod_id+4, 2))
Erik Andrenc109f812008-10-01 04:51:53 -0300251 return -ENODEV;
252
253 if (memcmp(prod_id, expected_prod_id, sizeof(prod_id)))
254 return -ENODEV;
255 else
256 info("Detected a s5k4aa sensor");
Erik Andrén32500702008-11-20 04:02:44 -0300257
Erik Andrenc109f812008-10-01 04:51:53 -0300258sensor_found:
Erik Andr?na594fb42009-01-06 11:37:03 -0300259 sensor_settings = kmalloc(
260 ARRAY_SIZE(s5k4aa_ctrls) * sizeof(s32), GFP_KERNEL);
261 if (!sensor_settings)
262 return -ENOMEM;
263
Erik Andr?n74cadfe2008-12-30 16:48:42 -0300264 sd->gspca_dev.cam.cam_mode = s5k4aa_modes;
265 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes);
Erik Andr?ne17cc082008-12-30 17:06:55 -0300266 sd->desc->ctrls = s5k4aa_ctrls;
Erik Andr?ne4cc4fc2008-12-30 15:27:17 -0300267 sd->desc->nctrls = ARRAY_SIZE(s5k4aa_ctrls);
Erik Andr?na594fb42009-01-06 11:37:03 -0300268
269 for (i = 0; i < ARRAY_SIZE(s5k4aa_ctrls); i++)
270 sensor_settings[i] = s5k4aa_ctrls[i].qctrl.default_value;
271 sd->sensor_priv = sensor_settings;
Erik Andr?nd4a389a2009-01-09 03:30:54 -0300272
Erik Andrenc109f812008-10-01 04:51:53 -0300273 return 0;
274}
275
Erik Andr?nad567ec2008-12-26 12:57:42 -0300276int s5k4aa_start(struct sd *sd)
277{
278 int i, err = 0;
279 u8 data[2];
280 struct cam *cam = &sd->gspca_dev.cam;
Grégory Lardière9bc738f2009-02-12 03:40:29 -0300281 s32 *sensor_settings = sd->sensor_priv;
Erik Andr?nad567ec2008-12-26 12:57:42 -0300282
Erik Andr?nd4a389a2009-01-09 03:30:54 -0300283 switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) {
Erik Andrén4fcec142009-01-29 13:34:41 -0300284 case 1280:
285 PDEBUG(D_V4L2, "Configuring camera for SXGA mode");
286
287 for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) {
288 switch (SXGA_s5k4aa[i][0]) {
289 case BRIDGE:
290 err = m5602_write_bridge(sd,
291 SXGA_s5k4aa[i][1],
292 SXGA_s5k4aa[i][2]);
293 break;
294
295 case SENSOR:
296 data[0] = SXGA_s5k4aa[i][2];
297 err = m5602_write_sensor(sd,
298 SXGA_s5k4aa[i][1],
299 data, 1);
300 break;
301
302 case SENSOR_LONG:
303 data[0] = SXGA_s5k4aa[i][2];
304 data[1] = SXGA_s5k4aa[i][3];
305 err = m5602_write_sensor(sd,
306 SXGA_s5k4aa[i][1],
307 data, 2);
308 break;
309
310 default:
311 err("Invalid stream command, exiting init");
312 return -EINVAL;
313 }
314 }
Grégory Lardière60d52ce2009-02-12 03:32:52 -0300315 err = s5k4aa_set_noise(&sd->gspca_dev, 0);
316 if (err < 0)
317 return err;
318 break;
Erik Andrén4fcec142009-01-29 13:34:41 -0300319
Erik Andr?nad567ec2008-12-26 12:57:42 -0300320 case 640:
321 PDEBUG(D_V4L2, "Configuring camera for VGA mode");
322
323 for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) {
324 switch (VGA_s5k4aa[i][0]) {
325 case BRIDGE:
326 err = m5602_write_bridge(sd,
327 VGA_s5k4aa[i][1],
328 VGA_s5k4aa[i][2]);
329 break;
330
331 case SENSOR:
332 data[0] = VGA_s5k4aa[i][2];
333 err = m5602_write_sensor(sd,
334 VGA_s5k4aa[i][1],
335 data, 1);
336 break;
337
338 case SENSOR_LONG:
339 data[0] = VGA_s5k4aa[i][2];
340 data[1] = VGA_s5k4aa[i][3];
341 err = m5602_write_sensor(sd,
342 VGA_s5k4aa[i][1],
343 data, 2);
344 break;
345
346 default:
347 err("Invalid stream command, exiting init");
348 return -EINVAL;
349 }
350 }
Grégory Lardière60d52ce2009-02-12 03:32:52 -0300351 err = s5k4aa_set_noise(&sd->gspca_dev, 1);
352 if (err < 0)
353 return err;
354 break;
Erik Andr?nad567ec2008-12-26 12:57:42 -0300355 }
Grégory Lardière9bc738f2009-02-12 03:40:29 -0300356 if (err < 0)
357 return err;
358
359 err = s5k4aa_set_exposure(&sd->gspca_dev,
360 sensor_settings[EXPOSURE_IDX]);
361 if (err < 0)
362 return err;
363
364 err = s5k4aa_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
365 if (err < 0)
366 return err;
367
368 err = s5k4aa_set_brightness(&sd->gspca_dev,
369 sensor_settings[BRIGHTNESS_IDX]);
370 if (err < 0)
371 return err;
372
373 err = s5k4aa_set_noise(&sd->gspca_dev, sensor_settings[NOISE_SUPP_IDX]);
374 if (err < 0)
375 return err;
376
377 err = s5k4aa_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
378 if (err < 0)
379 return err;
380
381 return s5k4aa_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
Erik Andr?nad567ec2008-12-26 12:57:42 -0300382}
383
Erik Andrenc109f812008-10-01 04:51:53 -0300384int s5k4aa_init(struct sd *sd)
385{
386 int i, err = 0;
387
388 for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) {
389 u8 data[2] = {0x00, 0x00};
390
391 switch (init_s5k4aa[i][0]) {
392 case BRIDGE:
393 err = m5602_write_bridge(sd,
394 init_s5k4aa[i][1],
395 init_s5k4aa[i][2]);
396 break;
397
398 case SENSOR:
399 data[0] = init_s5k4aa[i][2];
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300400 err = m5602_write_sensor(sd,
Erik Andrenc109f812008-10-01 04:51:53 -0300401 init_s5k4aa[i][1], data, 1);
402 break;
403
404 case SENSOR_LONG:
405 data[0] = init_s5k4aa[i][2];
406 data[1] = init_s5k4aa[i][3];
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300407 err = m5602_write_sensor(sd,
Erik Andrenc109f812008-10-01 04:51:53 -0300408 init_s5k4aa[i][1], data, 2);
409 break;
410 default:
411 info("Invalid stream command, exiting init");
412 return -EINVAL;
413 }
414 }
415
Erik Andr?n36e756c2009-01-09 13:35:00 -0300416 if (dump_sensor)
417 s5k4aa_dump_registers(sd);
418
Grégory Lardière9bc738f2009-02-12 03:40:29 -0300419 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300420}
421
Erik Andr?ncf811d52009-04-03 02:49:10 -0300422static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
Erik Andrenc109f812008-10-01 04:51:53 -0300423{
424 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?na594fb42009-01-06 11:37:03 -0300425 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300426
Erik Andr?na594fb42009-01-06 11:37:03 -0300427 *val = sensor_settings[EXPOSURE_IDX];
Erik Andren17ea88a2008-10-16 16:46:07 -0300428 PDEBUG(D_V4L2, "Read exposure %d", *val);
Erik Andr?n051781b2008-12-27 12:28:00 -0300429
Erik Andr?na594fb42009-01-06 11:37:03 -0300430 return 0;
Erik Andrenc109f812008-10-01 04:51:53 -0300431}
432
Erik Andr?ncf811d52009-04-03 02:49:10 -0300433static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
Erik Andrenc109f812008-10-01 04:51:53 -0300434{
435 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?na594fb42009-01-06 11:37:03 -0300436 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300437 u8 data = S5K4AA_PAGE_MAP_2;
438 int err;
439
Erik Andr?na594fb42009-01-06 11:37:03 -0300440 sensor_settings[EXPOSURE_IDX] = val;
Erik Andren17ea88a2008-10-16 16:46:07 -0300441 PDEBUG(D_V4L2, "Set exposure to %d", val);
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300442 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300443 if (err < 0)
Erik Andr?n051781b2008-12-27 12:28:00 -0300444 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300445 data = (val >> 8) & 0xff;
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300446 err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300447 if (err < 0)
Erik Andr?n051781b2008-12-27 12:28:00 -0300448 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300449 data = val & 0xff;
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300450 err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
Erik Andr?n051781b2008-12-27 12:28:00 -0300451
Erik Andrén32500702008-11-20 04:02:44 -0300452 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300453}
454
Erik Andr?ncf811d52009-04-03 02:49:10 -0300455static int s5k4aa_get_vflip(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[VFLIP_IDX];
Erik Andren17ea88a2008-10-16 16:46:07 -0300461 PDEBUG(D_V4L2, "Read vertical flip %d", *val);
Erik Andrenc109f812008-10-01 04:51:53 -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_vflip(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[VFLIP_IDX] = val;
474
Erik Andren17ea88a2008-10-16 16:46:07 -0300475 PDEBUG(D_V4L2, "Set vertical flip to %d", val);
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300476 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300477 if (err < 0)
Erik Andr?n051781b2008-12-27 12:28:00 -0300478 return err;
Erik Andr?na594fb42009-01-06 11:37:03 -0300479
Erik Andr?na68985d2009-01-13 15:44:03 -0300480 err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
481 if (err < 0)
482 return err;
483
Grégory Lardière9bc738f2009-02-12 03:40:29 -0300484 if (dmi_check_system(s5k4aa_vflip_dmi_table))
Erik Andr?na594fb42009-01-06 11:37:03 -0300485 val = !val;
486
Grégory Lardière9bc738f2009-02-12 03:40:29 -0300487 data = ((data & ~S5K4AA_RM_V_FLIP) | ((val & 0x01) << 7));
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300488 err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300489 if (err < 0)
Erik Andr?n051781b2008-12-27 12:28:00 -0300490 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300491
Grégory Lardière9bc738f2009-02-12 03:40:29 -0300492 err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
493 if (err < 0)
494 return err;
495 data = (data & 0xfe) | !val;
496 err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
Erik Andrén32500702008-11-20 04:02:44 -0300497 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300498}
499
Erik Andr?ncf811d52009-04-03 02:49:10 -0300500static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
Erik Andrenc109f812008-10-01 04:51:53 -0300501{
502 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?na594fb42009-01-06 11:37:03 -0300503 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300504
Erik Andr?na594fb42009-01-06 11:37:03 -0300505 *val = sensor_settings[HFLIP_IDX];
Erik Andren17ea88a2008-10-16 16:46:07 -0300506 PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
Erik Andr?n051781b2008-12-27 12:28:00 -0300507
Erik Andr?na594fb42009-01-06 11:37:03 -0300508 return 0;
Erik Andrenc109f812008-10-01 04:51:53 -0300509}
510
Erik Andr?ncf811d52009-04-03 02:49:10 -0300511static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
Erik Andrenc109f812008-10-01 04:51:53 -0300512{
513 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?na594fb42009-01-06 11:37:03 -0300514 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300515 u8 data = S5K4AA_PAGE_MAP_2;
516 int err;
517
Erik Andr?na594fb42009-01-06 11:37:03 -0300518 sensor_settings[HFLIP_IDX] = val;
519
520 PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300521 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &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
Erik Andr?na68985d2009-01-13 15:44:03 -0300525 err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
526 if (err < 0)
527 return err;
528
Grégory Lardière9bc738f2009-02-12 03:40:29 -0300529 if (dmi_check_system(s5k4aa_vflip_dmi_table))
Erik Andrén2f17e1a2009-01-22 03:51:40 -0300530 val = !val;
Erik Andrén2f17e1a2009-01-22 03:51:40 -0300531
Erik Andrenc109f812008-10-01 04:51:53 -0300532 data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300533 err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300534 if (err < 0)
Erik Andr?n051781b2008-12-27 12:28:00 -0300535 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300536
Grégory Lardière9bc738f2009-02-12 03:40:29 -0300537 err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
538 if (err < 0)
539 return err;
540 data = (data & 0xfe) | !val;
541 err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
Erik Andrén32500702008-11-20 04:02:44 -0300542 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300543}
544
Erik Andr?ncf811d52009-04-03 02:49:10 -0300545static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
Erik Andrenc109f812008-10-01 04:51:53 -0300546{
547 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?na594fb42009-01-06 11:37:03 -0300548 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300549
Erik Andr?na594fb42009-01-06 11:37:03 -0300550 *val = sensor_settings[GAIN_IDX];
Erik Andren17ea88a2008-10-16 16:46:07 -0300551 PDEBUG(D_V4L2, "Read gain %d", *val);
Erik Andr?na594fb42009-01-06 11:37:03 -0300552 return 0;
Erik Andrenc109f812008-10-01 04:51:53 -0300553}
554
Erik Andr?ncf811d52009-04-03 02:49:10 -0300555static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
Erik Andrenc109f812008-10-01 04:51:53 -0300556{
557 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?na594fb42009-01-06 11:37:03 -0300558 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300559 u8 data = S5K4AA_PAGE_MAP_2;
560 int err;
561
Erik Andr?na594fb42009-01-06 11:37:03 -0300562 sensor_settings[GAIN_IDX] = val;
563
Erik Andren17ea88a2008-10-16 16:46:07 -0300564 PDEBUG(D_V4L2, "Set gain to %d", val);
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300565 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300566 if (err < 0)
Erik Andr?n051781b2008-12-27 12:28:00 -0300567 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300568
569 data = val & 0xff;
Erik Andr?n7ee46292009-01-14 03:37:03 -0300570 err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300571
Erik Andrén32500702008-11-20 04:02:44 -0300572 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300573}
574
Erik Andr?n7ee46292009-01-14 03:37:03 -0300575static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
576{
577 struct sd *sd = (struct sd *) gspca_dev;
578 s32 *sensor_settings = sd->sensor_priv;
579
580 *val = sensor_settings[BRIGHTNESS_IDX];
581 PDEBUG(D_V4L2, "Read brightness %d", *val);
582 return 0;
583}
584
585static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
586{
587 struct sd *sd = (struct sd *) gspca_dev;
588 s32 *sensor_settings = sd->sensor_priv;
589 u8 data = S5K4AA_PAGE_MAP_2;
590 int err;
591
592 sensor_settings[BRIGHTNESS_IDX] = val;
593
594 PDEBUG(D_V4L2, "Set brightness to %d", val);
595 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
596 if (err < 0)
597 return err;
598
599 data = val & 0xff;
600 return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1);
601}
602
Erik Andr?n3290d402009-01-13 16:40:28 -0300603static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val)
604{
605 struct sd *sd = (struct sd *) gspca_dev;
606 s32 *sensor_settings = sd->sensor_priv;
607
608 *val = sensor_settings[NOISE_SUPP_IDX];
609 PDEBUG(D_V4L2, "Read noise %d", *val);
610 return 0;
611}
612
613static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
614{
615 struct sd *sd = (struct sd *) gspca_dev;
616 s32 *sensor_settings = sd->sensor_priv;
617 u8 data = S5K4AA_PAGE_MAP_2;
618 int err;
619
620 sensor_settings[NOISE_SUPP_IDX] = val;
621
622 PDEBUG(D_V4L2, "Set noise to %d", val);
623 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
624 if (err < 0)
625 return err;
626
627 data = val & 0x01;
628 return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1);
629}
630
Erik Andr?na594fb42009-01-06 11:37:03 -0300631void s5k4aa_disconnect(struct sd *sd)
632{
633 sd->sensor = NULL;
634 kfree(sd->sensor_priv);
635}
636
Erik Andrén658efb62008-11-24 14:21:29 -0300637static void s5k4aa_dump_registers(struct sd *sd)
Erik Andrenc109f812008-10-01 04:51:53 -0300638{
639 int address;
640 u8 page, old_page;
Erik Andrén4feb24f2008-11-27 13:51:11 -0300641 m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300642 for (page = 0; page < 16; page++) {
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300643 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300644 info("Dumping the s5k4aa register state for page 0x%x", page);
645 for (address = 0; address <= 0xff; address++) {
646 u8 value = 0;
Erik Andrén4feb24f2008-11-27 13:51:11 -0300647 m5602_read_sensor(sd, address, &value, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300648 info("register 0x%x contains 0x%x",
649 address, value);
650 }
651 }
652 info("s5k4aa register state dump complete");
653
654 for (page = 0; page < 16; page++) {
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300655 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300656 info("Probing for which registers that are "
657 "read/write for page 0x%x", page);
658 for (address = 0; address <= 0xff; address++) {
659 u8 old_value, ctrl_value, test_value = 0xff;
660
Erik Andrén4feb24f2008-11-27 13:51:11 -0300661 m5602_read_sensor(sd, address, &old_value, 1);
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300662 m5602_write_sensor(sd, address, &test_value, 1);
Erik Andrén4feb24f2008-11-27 13:51:11 -0300663 m5602_read_sensor(sd, address, &ctrl_value, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300664
665 if (ctrl_value == test_value)
666 info("register 0x%x is writeable", address);
667 else
668 info("register 0x%x is read only", address);
669
670 /* Restore original value */
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300671 m5602_write_sensor(sd, address, &old_value, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300672 }
673 }
674 info("Read/write register probing complete");
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300675 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300676}