1 /*
2 * Driver for the s5k83a sensor
3 *
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>
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 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
20
21 #include <linux/kthread.h>
22 #include "m5602_s5k83a.h"
23
24 static int s5k83a_s_ctrl(struct v4l2_ctrl *ctrl);
25
26 static const struct v4l2_ctrl_ops s5k83a_ctrl_ops = {
27 .s_ctrl = s5k83a_s_ctrl,
28 };
29
30 static struct v4l2_pix_format s5k83a_modes[] = {
31 {
32 640,
33 480,
34 V4L2_PIX_FMT_SBGGR8,
35 V4L2_FIELD_NONE,
36 .sizeimage =
37 640 * 480,
38 .bytesperline = 640,
39 .colorspace = V4L2_COLORSPACE_SRGB,
40 .priv = 0
41 }
42 };
43
44 static const unsigned char preinit_s5k83a[][4] = {
45 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
46 {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
47 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
48 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
49 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
50 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00},
51 {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00},
52
53 {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
54 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
55 {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
56 {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
57 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
58 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
59 {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
60 {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
61 {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
62 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
63 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
64 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
65 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
66 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
67 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
68 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
69 {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
70 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
71 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
72 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
73 {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00},
74 {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
75 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
76 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
77 {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
78 {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
79 };
80
81 /* This could probably be considerably shortened.
82 I don't have the hardware to experiment with it, patches welcome
83 */
84 static const unsigned char init_s5k83a[][4] = {
85 /* The following sequence is useless after a clean boot
86 but is necessary after resume from suspend */
87 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
88 {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
89 {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
90 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
91 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
92 {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
93 {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
94 {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
95 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
96 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
97 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
98 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
99 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
100 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
101 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
102 {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
103 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
104 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
105 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
106 {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
107 {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
108 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
109 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
110 {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
111 {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
112
113 {SENSOR, S5K83A_PAGE_MAP, 0x04, 0x00},
114 {SENSOR, 0xaf, 0x01, 0x00},
115 {SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00},
116 {SENSOR, 0x7b, 0xff, 0x00},
117 {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
118 {SENSOR, 0x01, 0x50, 0x00},
119 {SENSOR, 0x12, 0x20, 0x00},
120 {SENSOR, 0x17, 0x40, 0x00},
121 {SENSOR, 0x1c, 0x00, 0x00},
122 {SENSOR, 0x02, 0x70, 0x00},
123 {SENSOR, 0x03, 0x0b, 0x00},
124 {SENSOR, 0x04, 0xf0, 0x00},
125 {SENSOR, 0x05, 0x0b, 0x00},
126 {SENSOR, 0x06, 0x71, 0x00},
127 {SENSOR, 0x07, 0xe8, 0x00}, /* 488 */
128 {SENSOR, 0x08, 0x02, 0x00},
129 {SENSOR, 0x09, 0x88, 0x00}, /* 648 */
130 {SENSOR, 0x14, 0x00, 0x00},
131 {SENSOR, 0x15, 0x20, 0x00}, /* 32 */
132 {SENSOR, 0x19, 0x00, 0x00},
133 {SENSOR, 0x1a, 0x98, 0x00}, /* 152 */
134 {SENSOR, 0x0f, 0x02, 0x00},
135 {SENSOR, 0x10, 0xe5, 0x00}, /* 741 */
136 /* normal colors
137 (this is value after boot, but after tries can be different) */
138 {SENSOR, 0x00, 0x06, 0x00},
139 };
140
141 static const unsigned char start_s5k83a[][4] = {
142 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
143 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
144 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
145 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
146 {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
147 {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
148 {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
149 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
150 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
151 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
152 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
153 {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
154 {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00}, /* 484 */
155 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
156 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
157 {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
158 {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
159 {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
160 {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
161 {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
162 {BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00}, /* 639 */
163 {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
164 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
165 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
166 };
167
168 static void s5k83a_dump_registers(struct sd *sd);
169 static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data);
170 static int s5k83a_set_led_indication(struct sd *sd, u8 val);
171 static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
172 __s32 vflip, __s32 hflip);
173
s5k83a_probe(struct sd * sd)174 int s5k83a_probe(struct sd *sd)
175 {
176 u8 prod_id = 0, ver_id = 0;
177 int i, err = 0;
178 struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
179
180 if (force_sensor) {
181 if (force_sensor == S5K83A_SENSOR) {
182 pr_info("Forcing a %s sensor\n", s5k83a.name);
183 goto sensor_found;
184 }
185 /* If we want to force another sensor, don't try to probe this
186 * one */
187 return -ENODEV;
188 }
189
190 PDEBUG(D_PROBE, "Probing for a s5k83a sensor");
191
192 /* Preinit the sensor */
193 for (i = 0; i < ARRAY_SIZE(preinit_s5k83a) && !err; i++) {
194 u8 data[2] = {preinit_s5k83a[i][2], preinit_s5k83a[i][3]};
195 if (preinit_s5k83a[i][0] == SENSOR)
196 err = m5602_write_sensor(sd, preinit_s5k83a[i][1],
197 data, 2);
198 else
199 err = m5602_write_bridge(sd, preinit_s5k83a[i][1],
200 data[0]);
201 }
202
203 /* We don't know what register (if any) that contain the product id
204 * Just pick the first addresses that seem to produce the same results
205 * on multiple machines */
206 if (m5602_read_sensor(sd, 0x00, &prod_id, 1))
207 return -ENODEV;
208
209 if (m5602_read_sensor(sd, 0x01, &ver_id, 1))
210 return -ENODEV;
211
212 if ((prod_id == 0xff) || (ver_id == 0xff))
213 return -ENODEV;
214 else
215 pr_info("Detected a s5k83a sensor\n");
216
217 sensor_found:
218 sd->gspca_dev.cam.cam_mode = s5k83a_modes;
219 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k83a_modes);
220
221 /* null the pointer! thread is't running now */
222 sd->rotation_thread = NULL;
223
224 return 0;
225 }
226
s5k83a_init(struct sd * sd)227 int s5k83a_init(struct sd *sd)
228 {
229 int i, err = 0;
230
231 for (i = 0; i < ARRAY_SIZE(init_s5k83a) && !err; i++) {
232 u8 data[2] = {0x00, 0x00};
233
234 switch (init_s5k83a[i][0]) {
235 case BRIDGE:
236 err = m5602_write_bridge(sd,
237 init_s5k83a[i][1],
238 init_s5k83a[i][2]);
239 break;
240
241 case SENSOR:
242 data[0] = init_s5k83a[i][2];
243 err = m5602_write_sensor(sd,
244 init_s5k83a[i][1], data, 1);
245 break;
246
247 case SENSOR_LONG:
248 data[0] = init_s5k83a[i][2];
249 data[1] = init_s5k83a[i][3];
250 err = m5602_write_sensor(sd,
251 init_s5k83a[i][1], data, 2);
252 break;
253 default:
254 pr_info("Invalid stream command, exiting init\n");
255 return -EINVAL;
256 }
257 }
258
259 if (dump_sensor)
260 s5k83a_dump_registers(sd);
261
262 return err;
263 }
264
s5k83a_init_controls(struct sd * sd)265 int s5k83a_init_controls(struct sd *sd)
266 {
267 struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
268
269 sd->gspca_dev.vdev.ctrl_handler = hdl;
270 v4l2_ctrl_handler_init(hdl, 6);
271
272 v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_BRIGHTNESS,
273 0, 255, 1, S5K83A_DEFAULT_BRIGHTNESS);
274
275 v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_EXPOSURE,
276 0, S5K83A_MAXIMUM_EXPOSURE, 1,
277 S5K83A_DEFAULT_EXPOSURE);
278
279 v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_GAIN,
280 0, 255, 1, S5K83A_DEFAULT_GAIN);
281
282 sd->hflip = v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_HFLIP,
283 0, 1, 1, 0);
284 sd->vflip = v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_VFLIP,
285 0, 1, 1, 0);
286
287 if (hdl->error) {
288 pr_err("Could not initialize controls\n");
289 return hdl->error;
290 }
291
292 v4l2_ctrl_cluster(2, &sd->hflip);
293
294 return 0;
295 }
296
rotation_thread_function(void * data)297 static int rotation_thread_function(void *data)
298 {
299 struct sd *sd = (struct sd *) data;
300 u8 reg, previous_rotation = 0;
301 __s32 vflip, hflip;
302
303 set_current_state(TASK_INTERRUPTIBLE);
304 while (!schedule_timeout(msecs_to_jiffies(100))) {
305 if (mutex_lock_interruptible(&sd->gspca_dev.usb_lock))
306 break;
307
308 s5k83a_get_rotation(sd, ®);
309 if (previous_rotation != reg) {
310 previous_rotation = reg;
311 pr_info("Camera was flipped\n");
312
313 hflip = sd->hflip->val;
314 vflip = sd->vflip->val;
315
316 if (reg) {
317 vflip = !vflip;
318 hflip = !hflip;
319 }
320 s5k83a_set_flip_real((struct gspca_dev *) sd,
321 vflip, hflip);
322 }
323
324 mutex_unlock(&sd->gspca_dev.usb_lock);
325 set_current_state(TASK_INTERRUPTIBLE);
326 }
327
328 /* return to "front" flip */
329 if (previous_rotation) {
330 hflip = sd->hflip->val;
331 vflip = sd->vflip->val;
332 s5k83a_set_flip_real((struct gspca_dev *) sd, vflip, hflip);
333 }
334
335 sd->rotation_thread = NULL;
336 return 0;
337 }
338
s5k83a_start(struct sd * sd)339 int s5k83a_start(struct sd *sd)
340 {
341 int i, err = 0;
342
343 /* Create another thread, polling the GPIO ports of the camera to check
344 if it got rotated. This is how the windows driver does it so we have
345 to assume that there is no better way of accomplishing this */
346 sd->rotation_thread = kthread_create(rotation_thread_function,
347 sd, "rotation thread");
348 wake_up_process(sd->rotation_thread);
349
350 /* Preinit the sensor */
351 for (i = 0; i < ARRAY_SIZE(start_s5k83a) && !err; i++) {
352 u8 data[2] = {start_s5k83a[i][2], start_s5k83a[i][3]};
353 if (start_s5k83a[i][0] == SENSOR)
354 err = m5602_write_sensor(sd, start_s5k83a[i][1],
355 data, 2);
356 else
357 err = m5602_write_bridge(sd, start_s5k83a[i][1],
358 data[0]);
359 }
360 if (err < 0)
361 return err;
362
363 return s5k83a_set_led_indication(sd, 1);
364 }
365
s5k83a_stop(struct sd * sd)366 int s5k83a_stop(struct sd *sd)
367 {
368 if (sd->rotation_thread)
369 kthread_stop(sd->rotation_thread);
370
371 return s5k83a_set_led_indication(sd, 0);
372 }
373
s5k83a_disconnect(struct sd * sd)374 void s5k83a_disconnect(struct sd *sd)
375 {
376 s5k83a_stop(sd);
377
378 sd->sensor = NULL;
379 }
380
s5k83a_set_gain(struct gspca_dev * gspca_dev,__s32 val)381 static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
382 {
383 int err;
384 u8 data[2];
385 struct sd *sd = (struct sd *) gspca_dev;
386
387 data[0] = 0x00;
388 data[1] = 0x20;
389 err = m5602_write_sensor(sd, 0x14, data, 2);
390 if (err < 0)
391 return err;
392
393 data[0] = 0x01;
394 data[1] = 0x00;
395 err = m5602_write_sensor(sd, 0x0d, data, 2);
396 if (err < 0)
397 return err;
398
399 /* FIXME: This is not sane, we need to figure out the composition
400 of these registers */
401 data[0] = val >> 3; /* gain, high 5 bits */
402 data[1] = val >> 1; /* gain, high 7 bits */
403 err = m5602_write_sensor(sd, S5K83A_GAIN, data, 2);
404
405 return err;
406 }
407
s5k83a_set_brightness(struct gspca_dev * gspca_dev,__s32 val)408 static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
409 {
410 int err;
411 u8 data[1];
412 struct sd *sd = (struct sd *) gspca_dev;
413
414 data[0] = val;
415 err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 1);
416 return err;
417 }
418
s5k83a_set_exposure(struct gspca_dev * gspca_dev,__s32 val)419 static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
420 {
421 int err;
422 u8 data[2];
423 struct sd *sd = (struct sd *) gspca_dev;
424
425 data[0] = 0;
426 data[1] = val;
427 err = m5602_write_sensor(sd, S5K83A_EXPOSURE, data, 2);
428 return err;
429 }
430
s5k83a_set_flip_real(struct gspca_dev * gspca_dev,__s32 vflip,__s32 hflip)431 static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
432 __s32 vflip, __s32 hflip)
433 {
434 int err;
435 u8 data[1];
436 struct sd *sd = (struct sd *) gspca_dev;
437
438 data[0] = 0x05;
439 err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
440 if (err < 0)
441 return err;
442
443 /* six bit is vflip, seven is hflip */
444 data[0] = S5K83A_FLIP_MASK;
445 data[0] = (vflip) ? data[0] | 0x40 : data[0];
446 data[0] = (hflip) ? data[0] | 0x80 : data[0];
447
448 err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1);
449 if (err < 0)
450 return err;
451
452 data[0] = (vflip) ? 0x0b : 0x0a;
453 err = m5602_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1);
454 if (err < 0)
455 return err;
456
457 data[0] = (hflip) ? 0x0a : 0x0b;
458 err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1);
459 return err;
460 }
461
s5k83a_set_hvflip(struct gspca_dev * gspca_dev)462 static int s5k83a_set_hvflip(struct gspca_dev *gspca_dev)
463 {
464 int err;
465 u8 reg;
466 struct sd *sd = (struct sd *) gspca_dev;
467 int hflip = sd->hflip->val;
468 int vflip = sd->vflip->val;
469
470 err = s5k83a_get_rotation(sd, ®);
471 if (err < 0)
472 return err;
473 if (reg) {
474 hflip = !hflip;
475 vflip = !vflip;
476 }
477
478 err = s5k83a_set_flip_real(gspca_dev, vflip, hflip);
479 return err;
480 }
481
s5k83a_s_ctrl(struct v4l2_ctrl * ctrl)482 static int s5k83a_s_ctrl(struct v4l2_ctrl *ctrl)
483 {
484 struct gspca_dev *gspca_dev =
485 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
486 int err;
487
488 if (!gspca_dev->streaming)
489 return 0;
490
491 switch (ctrl->id) {
492 case V4L2_CID_BRIGHTNESS:
493 err = s5k83a_set_brightness(gspca_dev, ctrl->val);
494 break;
495 case V4L2_CID_EXPOSURE:
496 err = s5k83a_set_exposure(gspca_dev, ctrl->val);
497 break;
498 case V4L2_CID_GAIN:
499 err = s5k83a_set_gain(gspca_dev, ctrl->val);
500 break;
501 case V4L2_CID_HFLIP:
502 err = s5k83a_set_hvflip(gspca_dev);
503 break;
504 default:
505 return -EINVAL;
506 }
507
508 return err;
509 }
510
s5k83a_set_led_indication(struct sd * sd,u8 val)511 static int s5k83a_set_led_indication(struct sd *sd, u8 val)
512 {
513 int err = 0;
514 u8 data[1];
515
516 err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, data);
517 if (err < 0)
518 return err;
519
520 if (val)
521 data[0] = data[0] | S5K83A_GPIO_LED_MASK;
522 else
523 data[0] = data[0] & ~S5K83A_GPIO_LED_MASK;
524
525 err = m5602_write_bridge(sd, M5602_XB_GPIO_DAT, data[0]);
526
527 return err;
528 }
529
530 /* Get camera rotation on Acer notebooks */
s5k83a_get_rotation(struct sd * sd,u8 * reg_data)531 static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data)
532 {
533 int err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, reg_data);
534 *reg_data = (*reg_data & S5K83A_GPIO_ROTATION_MASK) ? 0 : 1;
535 return err;
536 }
537
s5k83a_dump_registers(struct sd * sd)538 static void s5k83a_dump_registers(struct sd *sd)
539 {
540 int address;
541 u8 page, old_page;
542 m5602_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
543
544 for (page = 0; page < 16; page++) {
545 m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
546 pr_info("Dumping the s5k83a register state for page 0x%x\n",
547 page);
548 for (address = 0; address <= 0xff; address++) {
549 u8 val = 0;
550 m5602_read_sensor(sd, address, &val, 1);
551 pr_info("register 0x%x contains 0x%x\n", address, val);
552 }
553 }
554 pr_info("s5k83a register state dump complete\n");
555
556 for (page = 0; page < 16; page++) {
557 m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
558 pr_info("Probing for which registers that are read/write for page 0x%x\n",
559 page);
560 for (address = 0; address <= 0xff; address++) {
561 u8 old_val, ctrl_val, test_val = 0xff;
562
563 m5602_read_sensor(sd, address, &old_val, 1);
564 m5602_write_sensor(sd, address, &test_val, 1);
565 m5602_read_sensor(sd, address, &ctrl_val, 1);
566
567 if (ctrl_val == test_val)
568 pr_info("register 0x%x is writeable\n",
569 address);
570 else
571 pr_info("register 0x%x is read only\n",
572 address);
573
574 /* Restore original val */
575 m5602_write_sensor(sd, address, &old_val, 1);
576 }
577 }
578 pr_info("Read/write register probing complete\n");
579 m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
580 }
581