]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/media/usb/gspca/m5602/m5602_s5k83a.c
[media] gscpa_gl860: Convert to the control framework
[mirror_ubuntu-jammy-kernel.git] / drivers / media / usb / gspca / m5602 / m5602_s5k83a.c
CommitLineData
c109f816
EA
1/*
2 * Driver for the s5k83a sensor
3 *
0c505e68 4 * Copyright (C) 2008 Erik Andrén
c109f816
EA
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
bdfe91f4
JP
19#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
20
ac3d5bfe 21#include <linux/kthread.h>
c109f816
EA
22#include "m5602_s5k83a.h"
23
cf811d50
EA
24static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val);
25static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
26static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
27static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
28static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
29static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
30static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
31static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
32static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
33static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
34
74cadfe1
EA
35static struct v4l2_pix_format s5k83a_modes[] = {
36 {
37 640,
38 480,
39 V4L2_PIX_FMT_SBGGR8,
40 V4L2_FIELD_NONE,
41 .sizeimage =
42 640 * 480,
43 .bytesperline = 640,
44 .colorspace = V4L2_COLORSPACE_SRGB,
45 .priv = 0
46 }
47};
48
2e03669d 49static const struct ctrl s5k83a_ctrls[] = {
ac3d5bfe 50#define GAIN_IDX 0
e17cc08c
EA
51 {
52 {
ac3d5bfe 53 .id = V4L2_CID_GAIN,
e17cc08c 54 .type = V4L2_CTRL_TYPE_INTEGER,
ac3d5bfe 55 .name = "gain",
e17cc08c
EA
56 .minimum = 0x00,
57 .maximum = 0xff,
58 .step = 0x01,
ac3d5bfe 59 .default_value = S5K83A_DEFAULT_GAIN,
e17cc08c
EA
60 .flags = V4L2_CTRL_FLAG_SLIDER
61 },
ac3d5bfe
LK
62 .set = s5k83a_set_gain,
63 .get = s5k83a_get_gain
e17cc08c 64
ac3d5bfe
LK
65 },
66#define BRIGHTNESS_IDX 1
67 {
e17cc08c 68 {
ac3d5bfe 69 .id = V4L2_CID_BRIGHTNESS,
e17cc08c 70 .type = V4L2_CTRL_TYPE_INTEGER,
ac3d5bfe 71 .name = "brightness",
e17cc08c
EA
72 .minimum = 0x00,
73 .maximum = 0xff,
74 .step = 0x01,
ac3d5bfe 75 .default_value = S5K83A_DEFAULT_BRIGHTNESS,
e17cc08c
EA
76 .flags = V4L2_CTRL_FLAG_SLIDER
77 },
ac3d5bfe
LK
78 .set = s5k83a_set_brightness,
79 .get = s5k83a_get_brightness,
80 },
81#define EXPOSURE_IDX 2
82 {
e17cc08c 83 {
ac3d5bfe 84 .id = V4L2_CID_EXPOSURE,
e17cc08c 85 .type = V4L2_CTRL_TYPE_INTEGER,
ac3d5bfe 86 .name = "exposure",
e17cc08c 87 .minimum = 0x00,
ac3d5bfe 88 .maximum = S5K83A_MAXIMUM_EXPOSURE,
e17cc08c 89 .step = 0x01,
ac3d5bfe 90 .default_value = S5K83A_DEFAULT_EXPOSURE,
e17cc08c
EA
91 .flags = V4L2_CTRL_FLAG_SLIDER
92 },
ac3d5bfe
LK
93 .set = s5k83a_set_exposure,
94 .get = s5k83a_get_exposure
95 },
96#define HFLIP_IDX 3
97 {
e17cc08c 98 {
00e02567
EA
99 .id = V4L2_CID_HFLIP,
100 .type = V4L2_CTRL_TYPE_BOOLEAN,
101 .name = "horizontal flip",
102 .minimum = 0,
103 .maximum = 1,
104 .step = 1,
105 .default_value = 0
e17cc08c
EA
106 },
107 .set = s5k83a_set_hflip,
108 .get = s5k83a_get_hflip
ac3d5bfe
LK
109 },
110#define VFLIP_IDX 4
111 {
e17cc08c 112 {
00e02567
EA
113 .id = V4L2_CID_VFLIP,
114 .type = V4L2_CTRL_TYPE_BOOLEAN,
115 .name = "vertical flip",
116 .minimum = 0,
117 .maximum = 1,
118 .step = 1,
119 .default_value = 0
e17cc08c
EA
120 },
121 .set = s5k83a_set_vflip,
122 .get = s5k83a_get_vflip
123 }
124};
125
658efb63 126static void s5k83a_dump_registers(struct sd *sd);
ac3d5bfe
LK
127static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data);
128static int s5k83a_set_led_indication(struct sd *sd, u8 val);
57851d0c
EA
129static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
130 __s32 vflip, __s32 hflip);
658efb63 131
c109f816
EA
132int s5k83a_probe(struct sd *sd)
133{
ac3d5bfe 134 struct s5k83a_priv *sens_priv;
c109f816
EA
135 u8 prod_id = 0, ver_id = 0;
136 int i, err = 0;
137
138 if (force_sensor) {
139 if (force_sensor == S5K83A_SENSOR) {
bdfe91f4 140 pr_info("Forcing a %s sensor\n", s5k83a.name);
c109f816
EA
141 goto sensor_found;
142 }
143 /* If we want to force another sensor, don't try to probe this
144 * one */
145 return -ENODEV;
146 }
147
969cc926 148 PDEBUG(D_PROBE, "Probing for a s5k83a sensor");
c109f816
EA
149
150 /* Preinit the sensor */
151 for (i = 0; i < ARRAY_SIZE(preinit_s5k83a) && !err; i++) {
152 u8 data[2] = {preinit_s5k83a[i][2], preinit_s5k83a[i][3]};
153 if (preinit_s5k83a[i][0] == SENSOR)
6dc4cff0 154 err = m5602_write_sensor(sd, preinit_s5k83a[i][1],
c109f816
EA
155 data, 2);
156 else
157 err = m5602_write_bridge(sd, preinit_s5k83a[i][1],
158 data[0]);
159 }
160
161 /* We don't know what register (if any) that contain the product id
162 * Just pick the first addresses that seem to produce the same results
163 * on multiple machines */
6b9c0a2a 164 if (m5602_read_sensor(sd, 0x00, &prod_id, 1))
c109f816
EA
165 return -ENODEV;
166
6b9c0a2a 167 if (m5602_read_sensor(sd, 0x01, &ver_id, 1))
c109f816
EA
168 return -ENODEV;
169
170 if ((prod_id == 0xff) || (ver_id == 0xff))
171 return -ENODEV;
172 else
bdfe91f4 173 pr_info("Detected a s5k83a sensor\n");
c109f816
EA
174
175sensor_found:
ac3d5bfe
LK
176 sens_priv = kmalloc(
177 sizeof(struct s5k83a_priv), GFP_KERNEL);
178 if (!sens_priv)
179 return -ENOMEM;
180
181 sens_priv->settings =
182 kmalloc(sizeof(s32)*ARRAY_SIZE(s5k83a_ctrls), GFP_KERNEL);
b807d175
JL
183 if (!sens_priv->settings) {
184 kfree(sens_priv);
ac3d5bfe 185 return -ENOMEM;
b807d175 186 }
ac3d5bfe 187
74cadfe1
EA
188 sd->gspca_dev.cam.cam_mode = s5k83a_modes;
189 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k83a_modes);
e17cc08c 190 sd->desc->ctrls = s5k83a_ctrls;
e4cc4fcc 191 sd->desc->nctrls = ARRAY_SIZE(s5k83a_ctrls);
ac3d5bfe
LK
192
193 /* null the pointer! thread is't running now */
194 sens_priv->rotation_thread = NULL;
195
196 for (i = 0; i < ARRAY_SIZE(s5k83a_ctrls); i++)
197 sens_priv->settings[i] = s5k83a_ctrls[i].qctrl.default_value;
198
199 sd->sensor_priv = sens_priv;
c109f816
EA
200 return 0;
201}
202
c109f816
EA
203int s5k83a_init(struct sd *sd)
204{
205 int i, err = 0;
c41507ba
LK
206 s32 *sensor_settings =
207 ((struct s5k83a_priv *) sd->sensor_priv)->settings;
c109f816
EA
208
209 for (i = 0; i < ARRAY_SIZE(init_s5k83a) && !err; i++) {
210 u8 data[2] = {0x00, 0x00};
211
212 switch (init_s5k83a[i][0]) {
213 case BRIDGE:
214 err = m5602_write_bridge(sd,
215 init_s5k83a[i][1],
216 init_s5k83a[i][2]);
217 break;
218
219 case SENSOR:
220 data[0] = init_s5k83a[i][2];
6dc4cff0 221 err = m5602_write_sensor(sd,
c109f816
EA
222 init_s5k83a[i][1], data, 1);
223 break;
224
225 case SENSOR_LONG:
226 data[0] = init_s5k83a[i][2];
227 data[1] = init_s5k83a[i][3];
6dc4cff0 228 err = m5602_write_sensor(sd,
c109f816
EA
229 init_s5k83a[i][1], data, 2);
230 break;
231 default:
bdfe91f4 232 pr_info("Invalid stream command, exiting init\n");
c109f816
EA
233 return -EINVAL;
234 }
235 }
236
237 if (dump_sensor)
238 s5k83a_dump_registers(sd);
239
57851d0c
EA
240 err = s5k83a_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
241 if (err < 0)
242 return err;
243
244 err = s5k83a_set_brightness(&sd->gspca_dev,
245 sensor_settings[BRIGHTNESS_IDX]);
246 if (err < 0)
247 return err;
248
249 err = s5k83a_set_exposure(&sd->gspca_dev,
250 sensor_settings[EXPOSURE_IDX]);
251 if (err < 0)
252 return err;
253
254 err = s5k83a_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
255 if (err < 0)
256 return err;
257
258 err = s5k83a_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
259
260 return err;
c109f816
EA
261}
262
ac3d5bfe
LK
263static int rotation_thread_function(void *data)
264{
265 struct sd *sd = (struct sd *) data;
266 struct s5k83a_priv *sens_priv = sd->sensor_priv;
267 u8 reg, previous_rotation = 0;
268 __s32 vflip, hflip;
269
270 set_current_state(TASK_INTERRUPTIBLE);
271 while (!schedule_timeout(100)) {
272 if (mutex_lock_interruptible(&sd->gspca_dev.usb_lock))
273 break;
274
275 s5k83a_get_rotation(sd, &reg);
276 if (previous_rotation != reg) {
277 previous_rotation = reg;
bdfe91f4 278 pr_info("Camera was flipped\n");
ac3d5bfe
LK
279
280 s5k83a_get_vflip((struct gspca_dev *) sd, &vflip);
281 s5k83a_get_hflip((struct gspca_dev *) sd, &hflip);
282
283 if (reg) {
284 vflip = !vflip;
285 hflip = !hflip;
286 }
1b844b53
EA
287 s5k83a_set_flip_real((struct gspca_dev *) sd,
288 vflip, hflip);
ac3d5bfe
LK
289 }
290
291 mutex_unlock(&sd->gspca_dev.usb_lock);
292 set_current_state(TASK_INTERRUPTIBLE);
293 }
294
295 /* return to "front" flip */
296 if (previous_rotation) {
297 s5k83a_get_vflip((struct gspca_dev *) sd, &vflip);
298 s5k83a_get_hflip((struct gspca_dev *) sd, &hflip);
299 s5k83a_set_flip_real((struct gspca_dev *) sd, vflip, hflip);
300 }
301
302 sens_priv->rotation_thread = NULL;
303 return 0;
304}
305
4a7581f0
LK
306int s5k83a_start(struct sd *sd)
307{
cde41bb2 308 int i, err = 0;
ac3d5bfe
LK
309 struct s5k83a_priv *sens_priv = sd->sensor_priv;
310
311 /* Create another thread, polling the GPIO ports of the camera to check
312 if it got rotated. This is how the windows driver does it so we have
313 to assume that there is no better way of accomplishing this */
57851d0c 314 sens_priv->rotation_thread = kthread_create(rotation_thread_function,
cde41bb2 315 sd, "rotation thread");
ac3d5bfe
LK
316 wake_up_process(sens_priv->rotation_thread);
317
cde41bb2
EA
318 /* Preinit the sensor */
319 for (i = 0; i < ARRAY_SIZE(start_s5k83a) && !err; i++) {
320 u8 data[2] = {start_s5k83a[i][2], start_s5k83a[i][3]};
321 if (start_s5k83a[i][0] == SENSOR)
322 err = m5602_write_sensor(sd, start_s5k83a[i][1],
323 data, 2);
324 else
325 err = m5602_write_bridge(sd, start_s5k83a[i][1],
326 data[0]);
327 }
328 if (err < 0)
329 return err;
330
4a7581f0
LK
331 return s5k83a_set_led_indication(sd, 1);
332}
333
334int s5k83a_stop(struct sd *sd)
335{
ac3d5bfe
LK
336 struct s5k83a_priv *sens_priv = sd->sensor_priv;
337
338 if (sens_priv->rotation_thread)
339 kthread_stop(sens_priv->rotation_thread);
340
4a7581f0
LK
341 return s5k83a_set_led_indication(sd, 0);
342}
343
ac3d5bfe 344void s5k83a_disconnect(struct sd *sd)
c109f816 345{
ac3d5bfe 346 struct s5k83a_priv *sens_priv = sd->sensor_priv;
c109f816 347
ac3d5bfe 348 s5k83a_stop(sd);
c109f816 349
ac3d5bfe
LK
350 sd->sensor = NULL;
351 kfree(sens_priv->settings);
352 kfree(sens_priv);
353}
c109f816 354
cf811d50 355static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
c109f816 356{
c109f816 357 struct sd *sd = (struct sd *) gspca_dev;
ac3d5bfe 358 struct s5k83a_priv *sens_priv = sd->sensor_priv;
c109f816 359
ac3d5bfe
LK
360 *val = sens_priv->settings[GAIN_IDX];
361 return 0;
c109f816
EA
362}
363
cf811d50 364static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
c109f816
EA
365{
366 int err;
367 u8 data[2];
368 struct sd *sd = (struct sd *) gspca_dev;
ac3d5bfe
LK
369 struct s5k83a_priv *sens_priv = sd->sensor_priv;
370
371 sens_priv->settings[GAIN_IDX] = val;
c109f816
EA
372
373 data[0] = 0x00;
374 data[1] = 0x20;
6dc4cff0 375 err = m5602_write_sensor(sd, 0x14, data, 2);
c109f816 376 if (err < 0)
051781b3 377 return err;
c109f816
EA
378
379 data[0] = 0x01;
380 data[1] = 0x00;
6dc4cff0 381 err = m5602_write_sensor(sd, 0x0d, data, 2);
c109f816 382 if (err < 0)
051781b3 383 return err;
c109f816
EA
384
385 /* FIXME: This is not sane, we need to figure out the composition
386 of these registers */
ac3d5bfe
LK
387 data[0] = val >> 3; /* gain, high 5 bits */
388 data[1] = val >> 1; /* gain, high 7 bits */
389 err = m5602_write_sensor(sd, S5K83A_GAIN, data, 2);
c109f816 390
7b2cd079 391 return err;
c109f816
EA
392}
393
cf811d50 394static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
c109f816 395{
c109f816 396 struct sd *sd = (struct sd *) gspca_dev;
ac3d5bfe 397 struct s5k83a_priv *sens_priv = sd->sensor_priv;
c109f816 398
ac3d5bfe
LK
399 *val = sens_priv->settings[BRIGHTNESS_IDX];
400 return 0;
c109f816
EA
401}
402
cf811d50 403static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
c109f816
EA
404{
405 int err;
406 u8 data[1];
407 struct sd *sd = (struct sd *) gspca_dev;
ac3d5bfe 408 struct s5k83a_priv *sens_priv = sd->sensor_priv;
c109f816 409
ac3d5bfe 410 sens_priv->settings[BRIGHTNESS_IDX] = val;
c109f816 411 data[0] = val;
ac3d5bfe 412 err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 1);
7b2cd079 413 return err;
c109f816
EA
414}
415
cf811d50 416static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
c109f816 417{
c109f816 418 struct sd *sd = (struct sd *) gspca_dev;
ac3d5bfe 419 struct s5k83a_priv *sens_priv = sd->sensor_priv;
c109f816 420
ac3d5bfe
LK
421 *val = sens_priv->settings[EXPOSURE_IDX];
422 return 0;
c109f816
EA
423}
424
cf811d50 425static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
c109f816 426{
18f8fae1 427 int err;
c109f816
EA
428 u8 data[2];
429 struct sd *sd = (struct sd *) gspca_dev;
ac3d5bfe 430 struct s5k83a_priv *sens_priv = sd->sensor_priv;
c109f816 431
ac3d5bfe 432 sens_priv->settings[EXPOSURE_IDX] = val;
c109f816
EA
433 data[0] = 0;
434 data[1] = val;
ac3d5bfe 435 err = m5602_write_sensor(sd, S5K83A_EXPOSURE, data, 2);
7b2cd079 436 return err;
c109f816 437}
18f8fae1 438
cf811d50 439static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
18f8fae1 440{
18f8fae1 441 struct sd *sd = (struct sd *) gspca_dev;
ac3d5bfe 442 struct s5k83a_priv *sens_priv = sd->sensor_priv;
18f8fae1 443
ac3d5bfe
LK
444 *val = sens_priv->settings[VFLIP_IDX];
445 return 0;
18f8fae1
EA
446}
447
57851d0c
EA
448static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
449 __s32 vflip, __s32 hflip)
18f8fae1
EA
450{
451 int err;
452 u8 data[1];
453 struct sd *sd = (struct sd *) gspca_dev;
454
455 data[0] = 0x05;
6dc4cff0 456 err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
18f8fae1 457 if (err < 0)
051781b3 458 return err;
18f8fae1 459
ac3d5bfe
LK
460 /* six bit is vflip, seven is hflip */
461 data[0] = S5K83A_FLIP_MASK;
462 data[0] = (vflip) ? data[0] | 0x40 : data[0];
463 data[0] = (hflip) ? data[0] | 0x80 : data[0];
18f8fae1 464
6dc4cff0 465 err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1);
18f8fae1 466 if (err < 0)
051781b3 467 return err;
18f8fae1 468
ac3d5bfe 469 data[0] = (vflip) ? 0x0b : 0x0a;
6dc4cff0 470 err = m5602_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1);
ac3d5bfe
LK
471 if (err < 0)
472 return err;
18f8fae1 473
ac3d5bfe
LK
474 data[0] = (hflip) ? 0x0a : 0x0b;
475 err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1);
7b2cd079 476 return err;
18f8fae1
EA
477}
478
cf811d50 479static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
18f8fae1
EA
480{
481 int err;
ac3d5bfe
LK
482 u8 reg;
483 __s32 hflip;
18f8fae1 484 struct sd *sd = (struct sd *) gspca_dev;
ac3d5bfe 485 struct s5k83a_priv *sens_priv = sd->sensor_priv;
18f8fae1 486
ac3d5bfe
LK
487 sens_priv->settings[VFLIP_IDX] = val;
488
489 s5k83a_get_hflip(gspca_dev, &hflip);
490
491 err = s5k83a_get_rotation(sd, &reg);
18f8fae1 492 if (err < 0)
051781b3 493 return err;
ac3d5bfe
LK
494 if (reg) {
495 val = !val;
496 hflip = !hflip;
497 }
18f8fae1 498
ac3d5bfe 499 err = s5k83a_set_flip_real(gspca_dev, val, hflip);
7b2cd079 500 return err;
18f8fae1
EA
501}
502
cf811d50 503static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
ac3d5bfe
LK
504{
505 struct sd *sd = (struct sd *) gspca_dev;
506 struct s5k83a_priv *sens_priv = sd->sensor_priv;
507
508 *val = sens_priv->settings[HFLIP_IDX];
509 return 0;
510}
511
cf811d50 512static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
18f8fae1
EA
513{
514 int err;
ac3d5bfe
LK
515 u8 reg;
516 __s32 vflip;
18f8fae1 517 struct sd *sd = (struct sd *) gspca_dev;
ac3d5bfe 518 struct s5k83a_priv *sens_priv = sd->sensor_priv;
18f8fae1 519
ac3d5bfe 520 sens_priv->settings[HFLIP_IDX] = val;
18f8fae1 521
ac3d5bfe 522 s5k83a_get_vflip(gspca_dev, &vflip);
18f8fae1 523
ac3d5bfe 524 err = s5k83a_get_rotation(sd, &reg);
18f8fae1 525 if (err < 0)
051781b3 526 return err;
ac3d5bfe
LK
527 if (reg) {
528 val = !val;
529 vflip = !vflip;
530 }
18f8fae1 531
ac3d5bfe 532 err = s5k83a_set_flip_real(gspca_dev, vflip, val);
7b2cd079 533 return err;
18f8fae1 534}
4a7581f0 535
ac3d5bfe 536static int s5k83a_set_led_indication(struct sd *sd, u8 val)
4a7581f0
LK
537{
538 int err = 0;
539 u8 data[1];
540
541 err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, data);
542 if (err < 0)
543 return err;
544
545 if (val)
546 data[0] = data[0] | S5K83A_GPIO_LED_MASK;
547 else
548 data[0] = data[0] & ~S5K83A_GPIO_LED_MASK;
549
550 err = m5602_write_bridge(sd, M5602_XB_GPIO_DAT, data[0]);
551
57851d0c 552 return err;
4a7581f0 553}
ac3d5bfe
LK
554
555/* Get camera rotation on Acer notebooks */
556static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data)
557{
558 int err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, reg_data);
559 *reg_data = (*reg_data & S5K83A_GPIO_ROTATION_MASK) ? 0 : 1;
560 return err;
561}
562
563static void s5k83a_dump_registers(struct sd *sd)
564{
565 int address;
566 u8 page, old_page;
567 m5602_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
568
569 for (page = 0; page < 16; page++) {
570 m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
bdfe91f4
JP
571 pr_info("Dumping the s5k83a register state for page 0x%x\n",
572 page);
ac3d5bfe
LK
573 for (address = 0; address <= 0xff; address++) {
574 u8 val = 0;
575 m5602_read_sensor(sd, address, &val, 1);
bdfe91f4 576 pr_info("register 0x%x contains 0x%x\n", address, val);
ac3d5bfe
LK
577 }
578 }
bdfe91f4 579 pr_info("s5k83a register state dump complete\n");
ac3d5bfe
LK
580
581 for (page = 0; page < 16; page++) {
582 m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
bdfe91f4
JP
583 pr_info("Probing for which registers that are read/write for page 0x%x\n",
584 page);
ac3d5bfe
LK
585 for (address = 0; address <= 0xff; address++) {
586 u8 old_val, ctrl_val, test_val = 0xff;
587
588 m5602_read_sensor(sd, address, &old_val, 1);
589 m5602_write_sensor(sd, address, &test_val, 1);
590 m5602_read_sensor(sd, address, &ctrl_val, 1);
591
592 if (ctrl_val == test_val)
bdfe91f4
JP
593 pr_info("register 0x%x is writeable\n",
594 address);
ac3d5bfe 595 else
bdfe91f4
JP
596 pr_info("register 0x%x is read only\n",
597 address);
ac3d5bfe
LK
598
599 /* Restore original val */
600 m5602_write_sensor(sd, address, &old_val, 1);
601 }
602 }
bdfe91f4 603 pr_info("Read/write register probing complete\n");
ac3d5bfe
LK
604 m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
605}