GNU Linux-libre 6.7.9-gnu
[releases.git] / drivers / media / usb / gspca / m5602 / m5602_s5k83a.c
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
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
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
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
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, &reg);
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
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_run(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
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         u8 data[1];
411         struct sd *sd = (struct sd *) gspca_dev;
412
413         data[0] = val;
414         return m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 1);
415 }
416
417 static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
418 {
419         u8 data[2];
420         struct sd *sd = (struct sd *) gspca_dev;
421
422         data[0] = 0;
423         data[1] = val;
424         return m5602_write_sensor(sd, S5K83A_EXPOSURE, data, 2);
425 }
426
427 static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
428                                 __s32 vflip, __s32 hflip)
429 {
430         int err;
431         u8 data[1];
432         struct sd *sd = (struct sd *) gspca_dev;
433
434         data[0] = 0x05;
435         err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
436         if (err < 0)
437                 return err;
438
439         /* six bit is vflip, seven is hflip */
440         data[0] = S5K83A_FLIP_MASK;
441         data[0] = (vflip) ? data[0] | 0x40 : data[0];
442         data[0] = (hflip) ? data[0] | 0x80 : data[0];
443
444         err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1);
445         if (err < 0)
446                 return err;
447
448         data[0] = (vflip) ? 0x0b : 0x0a;
449         err = m5602_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1);
450         if (err < 0)
451                 return err;
452
453         data[0] = (hflip) ? 0x0a : 0x0b;
454         err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1);
455         return err;
456 }
457
458 static int s5k83a_set_hvflip(struct gspca_dev *gspca_dev)
459 {
460         int err;
461         u8 reg;
462         struct sd *sd = (struct sd *) gspca_dev;
463         int hflip = sd->hflip->val;
464         int vflip = sd->vflip->val;
465
466         err = s5k83a_get_rotation(sd, &reg);
467         if (err < 0)
468                 return err;
469         if (reg) {
470                 hflip = !hflip;
471                 vflip = !vflip;
472         }
473
474         err = s5k83a_set_flip_real(gspca_dev, vflip, hflip);
475         return err;
476 }
477
478 static int s5k83a_s_ctrl(struct v4l2_ctrl *ctrl)
479 {
480         struct gspca_dev *gspca_dev =
481                 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
482         int err;
483
484         if (!gspca_dev->streaming)
485                 return 0;
486
487         switch (ctrl->id) {
488         case V4L2_CID_BRIGHTNESS:
489                 err = s5k83a_set_brightness(gspca_dev, ctrl->val);
490                 break;
491         case V4L2_CID_EXPOSURE:
492                 err = s5k83a_set_exposure(gspca_dev, ctrl->val);
493                 break;
494         case V4L2_CID_GAIN:
495                 err = s5k83a_set_gain(gspca_dev, ctrl->val);
496                 break;
497         case V4L2_CID_HFLIP:
498                 err = s5k83a_set_hvflip(gspca_dev);
499                 break;
500         default:
501                 return -EINVAL;
502         }
503
504         return err;
505 }
506
507 static int s5k83a_set_led_indication(struct sd *sd, u8 val)
508 {
509         int err = 0;
510         u8 data[1];
511
512         err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, data);
513         if (err < 0)
514                 return err;
515
516         if (val)
517                 data[0] = data[0] | S5K83A_GPIO_LED_MASK;
518         else
519                 data[0] = data[0] & ~S5K83A_GPIO_LED_MASK;
520
521         err = m5602_write_bridge(sd, M5602_XB_GPIO_DAT, data[0]);
522
523         return err;
524 }
525
526 /* Get camera rotation on Acer notebooks */
527 static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data)
528 {
529         int err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, reg_data);
530         *reg_data = (*reg_data & S5K83A_GPIO_ROTATION_MASK) ? 0 : 1;
531         return err;
532 }
533
534 static void s5k83a_dump_registers(struct sd *sd)
535 {
536         int address;
537         u8 page, old_page;
538         m5602_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
539
540         for (page = 0; page < 16; page++) {
541                 m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
542                 pr_info("Dumping the s5k83a register state for page 0x%x\n",
543                         page);
544                 for (address = 0; address <= 0xff; address++) {
545                         u8 val = 0;
546                         m5602_read_sensor(sd, address, &val, 1);
547                         pr_info("register 0x%x contains 0x%x\n", address, val);
548                 }
549         }
550         pr_info("s5k83a register state dump complete\n");
551
552         for (page = 0; page < 16; page++) {
553                 m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
554                 pr_info("Probing for which registers that are read/write for page 0x%x\n",
555                         page);
556                 for (address = 0; address <= 0xff; address++) {
557                         u8 old_val, ctrl_val, test_val = 0xff;
558
559                         m5602_read_sensor(sd, address, &old_val, 1);
560                         m5602_write_sensor(sd, address, &test_val, 1);
561                         m5602_read_sensor(sd, address, &ctrl_val, 1);
562
563                         if (ctrl_val == test_val)
564                                 pr_info("register 0x%x is writeable\n",
565                                         address);
566                         else
567                                 pr_info("register 0x%x is read only\n",
568                                         address);
569
570                         /* Restore original val */
571                         m5602_write_sensor(sd, address, &old_val, 1);
572                 }
573         }
574         pr_info("Read/write register probing complete\n");
575         m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
576 }