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 	gspca_dbg(gspca_dev, D_PROBE, "Probing for a s5k83a sensor\n");
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 	if (IS_ERR(sd->rotation_thread)) {
349 		err = PTR_ERR(sd->rotation_thread);
350 		sd->rotation_thread = NULL;
351 		return err;
352 	}
353 	wake_up_process(sd->rotation_thread);
354 
355 	/* Preinit the sensor */
356 	for (i = 0; i < ARRAY_SIZE(start_s5k83a) && !err; i++) {
357 		u8 data[2] = {start_s5k83a[i][2], start_s5k83a[i][3]};
358 		if (start_s5k83a[i][0] == SENSOR)
359 			err = m5602_write_sensor(sd, start_s5k83a[i][1],
360 				data, 2);
361 		else
362 			err = m5602_write_bridge(sd, start_s5k83a[i][1],
363 				data[0]);
364 	}
365 	if (err < 0)
366 		return err;
367 
368 	return s5k83a_set_led_indication(sd, 1);
369 }
370 
371 int s5k83a_stop(struct sd *sd)
372 {
373 	if (sd->rotation_thread)
374 		kthread_stop(sd->rotation_thread);
375 
376 	return s5k83a_set_led_indication(sd, 0);
377 }
378 
379 void s5k83a_disconnect(struct sd *sd)
380 {
381 	s5k83a_stop(sd);
382 
383 	sd->sensor = NULL;
384 }
385 
386 static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
387 {
388 	int err;
389 	u8 data[2];
390 	struct sd *sd = (struct sd *) gspca_dev;
391 
392 	data[0] = 0x00;
393 	data[1] = 0x20;
394 	err = m5602_write_sensor(sd, 0x14, data, 2);
395 	if (err < 0)
396 		return err;
397 
398 	data[0] = 0x01;
399 	data[1] = 0x00;
400 	err = m5602_write_sensor(sd, 0x0d, data, 2);
401 	if (err < 0)
402 		return err;
403 
404 	/* FIXME: This is not sane, we need to figure out the composition
405 		  of these registers */
406 	data[0] = val >> 3; /* gain, high 5 bits */
407 	data[1] = val >> 1; /* gain, high 7 bits */
408 	err = m5602_write_sensor(sd, S5K83A_GAIN, data, 2);
409 
410 	return err;
411 }
412 
413 static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
414 {
415 	int err;
416 	u8 data[1];
417 	struct sd *sd = (struct sd *) gspca_dev;
418 
419 	data[0] = val;
420 	err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 1);
421 	return err;
422 }
423 
424 static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
425 {
426 	int err;
427 	u8 data[2];
428 	struct sd *sd = (struct sd *) gspca_dev;
429 
430 	data[0] = 0;
431 	data[1] = val;
432 	err = m5602_write_sensor(sd, S5K83A_EXPOSURE, data, 2);
433 	return err;
434 }
435 
436 static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
437 				__s32 vflip, __s32 hflip)
438 {
439 	int err;
440 	u8 data[1];
441 	struct sd *sd = (struct sd *) gspca_dev;
442 
443 	data[0] = 0x05;
444 	err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
445 	if (err < 0)
446 		return err;
447 
448 	/* six bit is vflip, seven is hflip */
449 	data[0] = S5K83A_FLIP_MASK;
450 	data[0] = (vflip) ? data[0] | 0x40 : data[0];
451 	data[0] = (hflip) ? data[0] | 0x80 : data[0];
452 
453 	err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1);
454 	if (err < 0)
455 		return err;
456 
457 	data[0] = (vflip) ? 0x0b : 0x0a;
458 	err = m5602_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1);
459 	if (err < 0)
460 		return err;
461 
462 	data[0] = (hflip) ? 0x0a : 0x0b;
463 	err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1);
464 	return err;
465 }
466 
467 static int s5k83a_set_hvflip(struct gspca_dev *gspca_dev)
468 {
469 	int err;
470 	u8 reg;
471 	struct sd *sd = (struct sd *) gspca_dev;
472 	int hflip = sd->hflip->val;
473 	int vflip = sd->vflip->val;
474 
475 	err = s5k83a_get_rotation(sd, &reg);
476 	if (err < 0)
477 		return err;
478 	if (reg) {
479 		hflip = !hflip;
480 		vflip = !vflip;
481 	}
482 
483 	err = s5k83a_set_flip_real(gspca_dev, vflip, hflip);
484 	return err;
485 }
486 
487 static int s5k83a_s_ctrl(struct v4l2_ctrl *ctrl)
488 {
489 	struct gspca_dev *gspca_dev =
490 		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
491 	int err;
492 
493 	if (!gspca_dev->streaming)
494 		return 0;
495 
496 	switch (ctrl->id) {
497 	case V4L2_CID_BRIGHTNESS:
498 		err = s5k83a_set_brightness(gspca_dev, ctrl->val);
499 		break;
500 	case V4L2_CID_EXPOSURE:
501 		err = s5k83a_set_exposure(gspca_dev, ctrl->val);
502 		break;
503 	case V4L2_CID_GAIN:
504 		err = s5k83a_set_gain(gspca_dev, ctrl->val);
505 		break;
506 	case V4L2_CID_HFLIP:
507 		err = s5k83a_set_hvflip(gspca_dev);
508 		break;
509 	default:
510 		return -EINVAL;
511 	}
512 
513 	return err;
514 }
515 
516 static int s5k83a_set_led_indication(struct sd *sd, u8 val)
517 {
518 	int err = 0;
519 	u8 data[1];
520 
521 	err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, data);
522 	if (err < 0)
523 		return err;
524 
525 	if (val)
526 		data[0] = data[0] | S5K83A_GPIO_LED_MASK;
527 	else
528 		data[0] = data[0] & ~S5K83A_GPIO_LED_MASK;
529 
530 	err = m5602_write_bridge(sd, M5602_XB_GPIO_DAT, data[0]);
531 
532 	return err;
533 }
534 
535 /* Get camera rotation on Acer notebooks */
536 static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data)
537 {
538 	int err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, reg_data);
539 	*reg_data = (*reg_data & S5K83A_GPIO_ROTATION_MASK) ? 0 : 1;
540 	return err;
541 }
542 
543 static void s5k83a_dump_registers(struct sd *sd)
544 {
545 	int address;
546 	u8 page, old_page;
547 	m5602_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
548 
549 	for (page = 0; page < 16; page++) {
550 		m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
551 		pr_info("Dumping the s5k83a register state for page 0x%x\n",
552 			page);
553 		for (address = 0; address <= 0xff; address++) {
554 			u8 val = 0;
555 			m5602_read_sensor(sd, address, &val, 1);
556 			pr_info("register 0x%x contains 0x%x\n", address, val);
557 		}
558 	}
559 	pr_info("s5k83a register state dump complete\n");
560 
561 	for (page = 0; page < 16; page++) {
562 		m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
563 		pr_info("Probing for which registers that are read/write for page 0x%x\n",
564 			page);
565 		for (address = 0; address <= 0xff; address++) {
566 			u8 old_val, ctrl_val, test_val = 0xff;
567 
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);
571 
572 			if (ctrl_val == test_val)
573 				pr_info("register 0x%x is writeable\n",
574 					address);
575 			else
576 				pr_info("register 0x%x is read only\n",
577 					address);
578 
579 			/* Restore original val */
580 			m5602_write_sensor(sd, address, &old_val, 1);
581 		}
582 	}
583 	pr_info("Read/write register probing complete\n");
584 	m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
585 }
586