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