GNU Linux-libre 4.19.264-gnu1
[releases.git] / drivers / media / usb / gspca / m5602 / m5602_s5k83a.c
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 }