blob: 191bcd7189798351e5a171767c86fd5e7b8686b1 [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én6dc4cff2008-11-26 04:08:10 -0300479 err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &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 Andr?na594fb42009-01-06 11:37:03 -0300482
Erik Andr?na68985d2009-01-13 15:44:03 -0300483 err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
484 if (err < 0)
485 return err;
486
Grégory Lardière9bc738f2009-02-12 03:40:29 -0300487 if (dmi_check_system(s5k4aa_vflip_dmi_table))
Erik Andr?na594fb42009-01-06 11:37:03 -0300488 val = !val;
489
Grégory Lardière9bc738f2009-02-12 03:40:29 -0300490 data = ((data & ~S5K4AA_RM_V_FLIP) | ((val & 0x01) << 7));
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300491 err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300492 if (err < 0)
Erik Andr?n051781b2008-12-27 12:28:00 -0300493 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300494
Grégory Lardière9bc738f2009-02-12 03:40:29 -0300495 err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
496 if (err < 0)
497 return err;
498 data = (data & 0xfe) | !val;
499 err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
Erik Andrén32500702008-11-20 04:02:44 -0300500 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300501}
502
Erik Andr?ncf811d52009-04-03 02:49:10 -0300503static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
Erik Andrenc109f812008-10-01 04:51:53 -0300504{
505 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?na594fb42009-01-06 11:37:03 -0300506 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300507
Erik Andr?na594fb42009-01-06 11:37:03 -0300508 *val = sensor_settings[HFLIP_IDX];
Erik Andren17ea88a2008-10-16 16:46:07 -0300509 PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
Erik Andr?n051781b2008-12-27 12:28:00 -0300510
Erik Andr?na594fb42009-01-06 11:37:03 -0300511 return 0;
Erik Andrenc109f812008-10-01 04:51:53 -0300512}
513
Erik Andr?ncf811d52009-04-03 02:49:10 -0300514static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
Erik Andrenc109f812008-10-01 04:51:53 -0300515{
516 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?na594fb42009-01-06 11:37:03 -0300517 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300518 u8 data = S5K4AA_PAGE_MAP_2;
519 int err;
520
Erik Andr?na594fb42009-01-06 11:37:03 -0300521 sensor_settings[HFLIP_IDX] = val;
522
523 PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300524 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300525 if (err < 0)
Erik Andr?n051781b2008-12-27 12:28:00 -0300526 return err;
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300527 err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300528 if (err < 0)
Erik Andr?n051781b2008-12-27 12:28:00 -0300529 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300530
Erik Andr?na68985d2009-01-13 15:44:03 -0300531 err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
532 if (err < 0)
533 return err;
534
Grégory Lardière9bc738f2009-02-12 03:40:29 -0300535 if (dmi_check_system(s5k4aa_vflip_dmi_table))
Erik Andrén2f17e1a2009-01-22 03:51:40 -0300536 val = !val;
Erik Andrén2f17e1a2009-01-22 03:51:40 -0300537
Erik Andrenc109f812008-10-01 04:51:53 -0300538 data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300539 err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300540 if (err < 0)
Erik Andr?n051781b2008-12-27 12:28:00 -0300541 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300542
Grégory Lardière9bc738f2009-02-12 03:40:29 -0300543 err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
544 if (err < 0)
545 return err;
546 data = (data & 0xfe) | !val;
547 err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
Erik Andrén32500702008-11-20 04:02:44 -0300548 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300549}
550
Erik Andr?ncf811d52009-04-03 02:49:10 -0300551static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
Erik Andrenc109f812008-10-01 04:51:53 -0300552{
553 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?na594fb42009-01-06 11:37:03 -0300554 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300555
Erik Andr?na594fb42009-01-06 11:37:03 -0300556 *val = sensor_settings[GAIN_IDX];
Erik Andren17ea88a2008-10-16 16:46:07 -0300557 PDEBUG(D_V4L2, "Read gain %d", *val);
Erik Andr?na594fb42009-01-06 11:37:03 -0300558 return 0;
Erik Andrenc109f812008-10-01 04:51:53 -0300559}
560
Erik Andr?ncf811d52009-04-03 02:49:10 -0300561static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
Erik Andrenc109f812008-10-01 04:51:53 -0300562{
563 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?na594fb42009-01-06 11:37:03 -0300564 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300565 u8 data = S5K4AA_PAGE_MAP_2;
566 int err;
567
Erik Andr?na594fb42009-01-06 11:37:03 -0300568 sensor_settings[GAIN_IDX] = val;
569
Erik Andren17ea88a2008-10-16 16:46:07 -0300570 PDEBUG(D_V4L2, "Set gain to %d", val);
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300571 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300572 if (err < 0)
Erik Andr?n051781b2008-12-27 12:28:00 -0300573 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300574
575 data = val & 0xff;
Erik Andr?n7ee46292009-01-14 03:37:03 -0300576 err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300577
Erik Andrén32500702008-11-20 04:02:44 -0300578 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300579}
580
Erik Andr?n7ee46292009-01-14 03:37:03 -0300581static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
582{
583 struct sd *sd = (struct sd *) gspca_dev;
584 s32 *sensor_settings = sd->sensor_priv;
585
586 *val = sensor_settings[BRIGHTNESS_IDX];
587 PDEBUG(D_V4L2, "Read brightness %d", *val);
588 return 0;
589}
590
591static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
592{
593 struct sd *sd = (struct sd *) gspca_dev;
594 s32 *sensor_settings = sd->sensor_priv;
595 u8 data = S5K4AA_PAGE_MAP_2;
596 int err;
597
598 sensor_settings[BRIGHTNESS_IDX] = val;
599
600 PDEBUG(D_V4L2, "Set brightness to %d", val);
601 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
602 if (err < 0)
603 return err;
604
605 data = val & 0xff;
606 return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1);
607}
608
Erik Andr?n3290d402009-01-13 16:40:28 -0300609static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val)
610{
611 struct sd *sd = (struct sd *) gspca_dev;
612 s32 *sensor_settings = sd->sensor_priv;
613
614 *val = sensor_settings[NOISE_SUPP_IDX];
615 PDEBUG(D_V4L2, "Read noise %d", *val);
616 return 0;
617}
618
619static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
620{
621 struct sd *sd = (struct sd *) gspca_dev;
622 s32 *sensor_settings = sd->sensor_priv;
623 u8 data = S5K4AA_PAGE_MAP_2;
624 int err;
625
626 sensor_settings[NOISE_SUPP_IDX] = val;
627
628 PDEBUG(D_V4L2, "Set noise to %d", val);
629 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
630 if (err < 0)
631 return err;
632
633 data = val & 0x01;
634 return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1);
635}
636
Erik Andr?na594fb42009-01-06 11:37:03 -0300637void s5k4aa_disconnect(struct sd *sd)
638{
639 sd->sensor = NULL;
640 kfree(sd->sensor_priv);
641}
642
Erik Andrén658efb62008-11-24 14:21:29 -0300643static void s5k4aa_dump_registers(struct sd *sd)
Erik Andrenc109f812008-10-01 04:51:53 -0300644{
645 int address;
646 u8 page, old_page;
Erik Andrén4feb24f2008-11-27 13:51:11 -0300647 m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300648 for (page = 0; page < 16; page++) {
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300649 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300650 info("Dumping the s5k4aa register state for page 0x%x", page);
651 for (address = 0; address <= 0xff; address++) {
652 u8 value = 0;
Erik Andrén4feb24f2008-11-27 13:51:11 -0300653 m5602_read_sensor(sd, address, &value, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300654 info("register 0x%x contains 0x%x",
655 address, value);
656 }
657 }
658 info("s5k4aa register state dump complete");
659
660 for (page = 0; page < 16; page++) {
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300661 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300662 info("Probing for which registers that are "
663 "read/write for page 0x%x", page);
664 for (address = 0; address <= 0xff; address++) {
665 u8 old_value, ctrl_value, test_value = 0xff;
666
Erik Andrén4feb24f2008-11-27 13:51:11 -0300667 m5602_read_sensor(sd, address, &old_value, 1);
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300668 m5602_write_sensor(sd, address, &test_value, 1);
Erik Andrén4feb24f2008-11-27 13:51:11 -0300669 m5602_read_sensor(sd, address, &ctrl_value, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300670
671 if (ctrl_value == test_value)
672 info("register 0x%x is writeable", address);
673 else
674 info("register 0x%x is read only", address);
675
676 /* Restore original value */
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300677 m5602_write_sensor(sd, address, &old_value, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300678 }
679 }
680 info("Read/write register probing complete");
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300681 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300682}