2 * Driver for the s5k83a sensor
4 * Copyright (C) 2008 Erik Andrén
5 * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
6 * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
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
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.
19 #include <linux/kthread.h>
20 #include "m5602_s5k83a.h"
22 static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val);
23 static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
24 static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
25 static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
26 static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
27 static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
28 static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
29 static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
30 static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
31 static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
33 static struct v4l2_pix_format s5k83a_modes[] = {
42 .colorspace = V4L2_COLORSPACE_SRGB,
47 const static struct ctrl s5k83a_ctrls[] = {
52 .type = V4L2_CTRL_TYPE_INTEGER,
57 .default_value = S5K83A_DEFAULT_GAIN,
58 .flags = V4L2_CTRL_FLAG_SLIDER
60 .set = s5k83a_set_gain,
61 .get = s5k83a_get_gain
64 #define BRIGHTNESS_IDX 1
67 .id = V4L2_CID_BRIGHTNESS,
68 .type = V4L2_CTRL_TYPE_INTEGER,
73 .default_value = S5K83A_DEFAULT_BRIGHTNESS,
74 .flags = V4L2_CTRL_FLAG_SLIDER
76 .set = s5k83a_set_brightness,
77 .get = s5k83a_get_brightness,
79 #define EXPOSURE_IDX 2
82 .id = V4L2_CID_EXPOSURE,
83 .type = V4L2_CTRL_TYPE_INTEGER,
86 .maximum = S5K83A_MAXIMUM_EXPOSURE,
88 .default_value = S5K83A_DEFAULT_EXPOSURE,
89 .flags = V4L2_CTRL_FLAG_SLIDER
91 .set = s5k83a_set_exposure,
92 .get = s5k83a_get_exposure
98 .type = V4L2_CTRL_TYPE_BOOLEAN,
99 .name = "horizontal flip",
105 .set = s5k83a_set_hflip,
106 .get = s5k83a_get_hflip
111 .id = V4L2_CID_VFLIP,
112 .type = V4L2_CTRL_TYPE_BOOLEAN,
113 .name = "vertical flip",
119 .set = s5k83a_set_vflip,
120 .get = s5k83a_get_vflip
124 static void s5k83a_dump_registers(struct sd *sd);
125 static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data);
126 static int s5k83a_set_led_indication(struct sd *sd, u8 val);
127 static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
128 __s32 vflip, __s32 hflip);
130 int s5k83a_probe(struct sd *sd)
132 struct s5k83a_priv *sens_priv;
133 u8 prod_id = 0, ver_id = 0;
137 if (force_sensor == S5K83A_SENSOR) {
138 info("Forcing a %s sensor", s5k83a.name);
141 /* If we want to force another sensor, don't try to probe this
146 info("Probing for a s5k83a sensor");
148 /* Preinit the sensor */
149 for (i = 0; i < ARRAY_SIZE(preinit_s5k83a) && !err; i++) {
150 u8 data[2] = {preinit_s5k83a[i][2], preinit_s5k83a[i][3]};
151 if (preinit_s5k83a[i][0] == SENSOR)
152 err = m5602_write_sensor(sd, preinit_s5k83a[i][1],
155 err = m5602_write_bridge(sd, preinit_s5k83a[i][1],
159 /* We don't know what register (if any) that contain the product id
160 * Just pick the first addresses that seem to produce the same results
161 * on multiple machines */
162 if (m5602_read_sensor(sd, 0x00, &prod_id, 1))
165 if (m5602_read_sensor(sd, 0x01, &ver_id, 1))
168 if ((prod_id == 0xff) || (ver_id == 0xff))
171 info("Detected a s5k83a sensor");
175 sizeof(struct s5k83a_priv), GFP_KERNEL);
179 sens_priv->settings =
180 kmalloc(sizeof(s32)*ARRAY_SIZE(s5k83a_ctrls), GFP_KERNEL);
181 if (!sens_priv->settings)
184 sd->gspca_dev.cam.cam_mode = s5k83a_modes;
185 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k83a_modes);
186 sd->desc->ctrls = s5k83a_ctrls;
187 sd->desc->nctrls = ARRAY_SIZE(s5k83a_ctrls);
189 /* null the pointer! thread is't running now */
190 sens_priv->rotation_thread = NULL;
192 for (i = 0; i < ARRAY_SIZE(s5k83a_ctrls); i++)
193 sens_priv->settings[i] = s5k83a_ctrls[i].qctrl.default_value;
195 sd->sensor_priv = sens_priv;
199 int s5k83a_init(struct sd *sd)
202 s32 *sensor_settings = sd->sensor_priv;
204 for (i = 0; i < ARRAY_SIZE(init_s5k83a) && !err; i++) {
205 u8 data[2] = {0x00, 0x00};
207 switch (init_s5k83a[i][0]) {
209 err = m5602_write_bridge(sd,
215 data[0] = init_s5k83a[i][2];
216 err = m5602_write_sensor(sd,
217 init_s5k83a[i][1], data, 1);
221 data[0] = init_s5k83a[i][2];
222 data[1] = init_s5k83a[i][3];
223 err = m5602_write_sensor(sd,
224 init_s5k83a[i][1], data, 2);
227 info("Invalid stream command, exiting init");
233 s5k83a_dump_registers(sd);
235 err = s5k83a_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
239 err = s5k83a_set_brightness(&sd->gspca_dev,
240 sensor_settings[BRIGHTNESS_IDX]);
244 err = s5k83a_set_exposure(&sd->gspca_dev,
245 sensor_settings[EXPOSURE_IDX]);
249 err = s5k83a_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
253 err = s5k83a_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
258 static int rotation_thread_function(void *data)
260 struct sd *sd = (struct sd *) data;
261 struct s5k83a_priv *sens_priv = sd->sensor_priv;
262 u8 reg, previous_rotation = 0;
265 set_current_state(TASK_INTERRUPTIBLE);
266 while (!schedule_timeout(100)) {
267 if (mutex_lock_interruptible(&sd->gspca_dev.usb_lock))
270 s5k83a_get_rotation(sd, ®);
271 if (previous_rotation != reg) {
272 previous_rotation = reg;
273 info("Camera was flipped");
275 s5k83a_get_vflip((struct gspca_dev *) sd, &vflip);
276 s5k83a_get_hflip((struct gspca_dev *) sd, &hflip);
282 s5k83a_set_flip_real((struct gspca_dev *) sd, vflip, hflip);
285 mutex_unlock(&sd->gspca_dev.usb_lock);
286 set_current_state(TASK_INTERRUPTIBLE);
289 /* return to "front" flip */
290 if (previous_rotation) {
291 s5k83a_get_vflip((struct gspca_dev *) sd, &vflip);
292 s5k83a_get_hflip((struct gspca_dev *) sd, &hflip);
293 s5k83a_set_flip_real((struct gspca_dev *) sd, vflip, hflip);
296 sens_priv->rotation_thread = NULL;
300 int s5k83a_start(struct sd *sd)
302 struct s5k83a_priv *sens_priv = sd->sensor_priv;
304 /* Create another thread, polling the GPIO ports of the camera to check
305 if it got rotated. This is how the windows driver does it so we have
306 to assume that there is no better way of accomplishing this */
307 sens_priv->rotation_thread = kthread_create(rotation_thread_function,
308 sd, "rotation thread");
309 wake_up_process(sens_priv->rotation_thread);
311 return s5k83a_set_led_indication(sd, 1);
314 int s5k83a_stop(struct sd *sd)
316 struct s5k83a_priv *sens_priv = sd->sensor_priv;
318 if (sens_priv->rotation_thread)
319 kthread_stop(sens_priv->rotation_thread);
321 return s5k83a_set_led_indication(sd, 0);
324 void s5k83a_disconnect(struct sd *sd)
326 struct s5k83a_priv *sens_priv = sd->sensor_priv;
331 kfree(sens_priv->settings);
335 static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
337 struct sd *sd = (struct sd *) gspca_dev;
338 struct s5k83a_priv *sens_priv = sd->sensor_priv;
340 *val = sens_priv->settings[GAIN_IDX];
344 static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
348 struct sd *sd = (struct sd *) gspca_dev;
349 struct s5k83a_priv *sens_priv = sd->sensor_priv;
351 sens_priv->settings[GAIN_IDX] = val;
355 err = m5602_write_sensor(sd, 0x14, data, 2);
361 err = m5602_write_sensor(sd, 0x0d, data, 2);
365 /* FIXME: This is not sane, we need to figure out the composition
366 of these registers */
367 data[0] = val >> 3; /* gain, high 5 bits */
368 data[1] = val >> 1; /* gain, high 7 bits */
369 err = m5602_write_sensor(sd, S5K83A_GAIN, data, 2);
374 static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
376 struct sd *sd = (struct sd *) gspca_dev;
377 struct s5k83a_priv *sens_priv = sd->sensor_priv;
379 *val = sens_priv->settings[BRIGHTNESS_IDX];
383 static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
387 struct sd *sd = (struct sd *) gspca_dev;
388 struct s5k83a_priv *sens_priv = sd->sensor_priv;
390 sens_priv->settings[BRIGHTNESS_IDX] = val;
392 err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 1);
396 static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
398 struct sd *sd = (struct sd *) gspca_dev;
399 struct s5k83a_priv *sens_priv = sd->sensor_priv;
401 *val = sens_priv->settings[EXPOSURE_IDX];
405 static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
409 struct sd *sd = (struct sd *) gspca_dev;
410 struct s5k83a_priv *sens_priv = sd->sensor_priv;
412 sens_priv->settings[EXPOSURE_IDX] = val;
415 err = m5602_write_sensor(sd, S5K83A_EXPOSURE, data, 2);
419 static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
421 struct sd *sd = (struct sd *) gspca_dev;
422 struct s5k83a_priv *sens_priv = sd->sensor_priv;
424 *val = sens_priv->settings[VFLIP_IDX];
428 static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
429 __s32 vflip, __s32 hflip)
433 struct sd *sd = (struct sd *) gspca_dev;
436 err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
440 /* six bit is vflip, seven is hflip */
441 data[0] = S5K83A_FLIP_MASK;
442 data[0] = (vflip) ? data[0] | 0x40 : data[0];
443 data[0] = (hflip) ? data[0] | 0x80 : data[0];
445 err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1);
449 data[0] = (vflip) ? 0x0b : 0x0a;
450 err = m5602_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1);
454 data[0] = (hflip) ? 0x0a : 0x0b;
455 err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1);
459 static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
464 struct sd *sd = (struct sd *) gspca_dev;
465 struct s5k83a_priv *sens_priv = sd->sensor_priv;
467 sens_priv->settings[VFLIP_IDX] = val;
469 s5k83a_get_hflip(gspca_dev, &hflip);
471 err = s5k83a_get_rotation(sd, ®);
479 err = s5k83a_set_flip_real(gspca_dev, val, hflip);
483 static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
485 struct sd *sd = (struct sd *) gspca_dev;
486 struct s5k83a_priv *sens_priv = sd->sensor_priv;
488 *val = sens_priv->settings[HFLIP_IDX];
492 static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
497 struct sd *sd = (struct sd *) gspca_dev;
498 struct s5k83a_priv *sens_priv = sd->sensor_priv;
500 sens_priv->settings[HFLIP_IDX] = val;
502 s5k83a_get_vflip(gspca_dev, &vflip);
504 err = s5k83a_get_rotation(sd, ®);
512 err = s5k83a_set_flip_real(gspca_dev, vflip, val);
516 static int s5k83a_set_led_indication(struct sd *sd, u8 val)
521 err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, data);
526 data[0] = data[0] | S5K83A_GPIO_LED_MASK;
528 data[0] = data[0] & ~S5K83A_GPIO_LED_MASK;
530 err = m5602_write_bridge(sd, M5602_XB_GPIO_DAT, data[0]);
535 /* Get camera rotation on Acer notebooks */
536 static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data)
538 int err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, reg_data);
539 *reg_data = (*reg_data & S5K83A_GPIO_ROTATION_MASK) ? 0 : 1;
543 static void s5k83a_dump_registers(struct sd *sd)
547 m5602_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
549 for (page = 0; page < 16; page++) {
550 m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
551 info("Dumping the s5k83a register state for page 0x%x", page);
552 for (address = 0; address <= 0xff; address++) {
554 m5602_read_sensor(sd, address, &val, 1);
555 info("register 0x%x contains 0x%x",
559 info("s5k83a register state dump complete");
561 for (page = 0; page < 16; page++) {
562 m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
563 info("Probing for which registers that are read/write "
564 "for page 0x%x", page);
565 for (address = 0; address <= 0xff; address++) {
566 u8 old_val, ctrl_val, test_val = 0xff;
568 m5602_read_sensor(sd, address, &old_val, 1);
569 m5602_write_sensor(sd, address, &test_val, 1);
570 m5602_read_sensor(sd, address, &ctrl_val, 1);
572 if (ctrl_val == test_val)
573 info("register 0x%x is writeable", address);
575 info("register 0x%x is read only", address);
577 /* Restore original val */
578 m5602_write_sensor(sd, address, &old_val, 1);
581 info("Read/write register probing complete");
582 m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);