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 
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 
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 
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 
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, &reg);
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 
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 
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 
374 void s5k83a_disconnect(struct sd *sd)
375 {
376 	s5k83a_stop(sd);
377 
378 	sd->sensor = NULL;
379 }
380 
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 
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 
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 
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 
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, &reg);
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 
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 
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 */
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 
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