]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/media/usb/gspca/m5602/m5602_s5k83a.c
Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[mirror_ubuntu-jammy-kernel.git] / drivers / media / usb / gspca / m5602 / m5602_s5k83a.c
CommitLineData
a10e763b 1// SPDX-License-Identifier: GPL-2.0-only
c109f816
EA
2/*
3 * Driver for the s5k83a sensor
4 *
0c505e68 5 * Copyright (C) 2008 Erik Andrén
c109f816
EA
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
c109f816
EA
13 */
14
bdfe91f4
JP
15#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
16
ac3d5bfe 17#include <linux/kthread.h>
c109f816
EA
18#include "m5602_s5k83a.h"
19
c84e412f
HG
20static int s5k83a_s_ctrl(struct v4l2_ctrl *ctrl);
21
22static const struct v4l2_ctrl_ops s5k83a_ctrl_ops = {
23 .s_ctrl = s5k83a_s_ctrl,
24};
cf811d50 25
74cadfe1
EA
26static 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
1ab9e600
MCC
40static 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*/
80static 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
137static 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
658efb63 164static void s5k83a_dump_registers(struct sd *sd);
ac3d5bfe
LK
165static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data);
166static int s5k83a_set_led_indication(struct sd *sd, u8 val);
57851d0c
EA
167static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
168 __s32 vflip, __s32 hflip);
658efb63 169
c109f816
EA
170int s5k83a_probe(struct sd *sd)
171{
172 u8 prod_id = 0, ver_id = 0;
173 int i, err = 0;
c93396e1 174 struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
c109f816
EA
175
176 if (force_sensor) {
177 if (force_sensor == S5K83A_SENSOR) {
bdfe91f4 178 pr_info("Forcing a %s sensor\n", s5k83a.name);
c109f816
EA
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
37d5efb0 186 gspca_dbg(gspca_dev, D_PROBE, "Probing for a s5k83a sensor\n");
c109f816
EA
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)
6dc4cff0 192 err = m5602_write_sensor(sd, preinit_s5k83a[i][1],
c109f816
EA
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 */
6b9c0a2a 202 if (m5602_read_sensor(sd, 0x00, &prod_id, 1))
c109f816
EA
203 return -ENODEV;
204
6b9c0a2a 205 if (m5602_read_sensor(sd, 0x01, &ver_id, 1))
c109f816
EA
206 return -ENODEV;
207
208 if ((prod_id == 0xff) || (ver_id == 0xff))
209 return -ENODEV;
210 else
bdfe91f4 211 pr_info("Detected a s5k83a sensor\n");
c109f816
EA
212
213sensor_found:
74cadfe1
EA
214 sd->gspca_dev.cam.cam_mode = s5k83a_modes;
215 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k83a_modes);
ac3d5bfe
LK
216
217 /* null the pointer! thread is't running now */
c84e412f 218 sd->rotation_thread = NULL;
ac3d5bfe 219
c109f816
EA
220 return 0;
221}
222
c109f816
EA
223int 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];
6dc4cff0 239 err = m5602_write_sensor(sd,
c109f816
EA
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];
6dc4cff0 246 err = m5602_write_sensor(sd,
c109f816
EA
247 init_s5k83a[i][1], data, 2);
248 break;
249 default:
bdfe91f4 250 pr_info("Invalid stream command, exiting init\n");
c109f816
EA
251 return -EINVAL;
252 }
253 }
254
255 if (dump_sensor)
256 s5k83a_dump_registers(sd);
257
c84e412f
HG
258 return err;
259}
57851d0c 260
c84e412f
HG
261int s5k83a_init_controls(struct sd *sd)
262{
263 struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
57851d0c 264
c84e412f
HG
265 sd->gspca_dev.vdev.ctrl_handler = hdl;
266 v4l2_ctrl_handler_init(hdl, 6);
57851d0c 267
c84e412f
HG
268 v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_BRIGHTNESS,
269 0, 255, 1, S5K83A_DEFAULT_BRIGHTNESS);
57851d0c 270
c84e412f
HG
271 v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_EXPOSURE,
272 0, S5K83A_MAXIMUM_EXPOSURE, 1,
273 S5K83A_DEFAULT_EXPOSURE);
57851d0c 274
c84e412f
HG
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;
c109f816
EA
291}
292
ac3d5bfe
LK
293static int rotation_thread_function(void *data)
294{
295 struct sd *sd = (struct sd *) data;
ac3d5bfe
LK
296 u8 reg, previous_rotation = 0;
297 __s32 vflip, hflip;
298
299 set_current_state(TASK_INTERRUPTIBLE);
63f2f417 300 while (!schedule_timeout(msecs_to_jiffies(100))) {
ac3d5bfe
LK
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;
bdfe91f4 307 pr_info("Camera was flipped\n");
ac3d5bfe 308
c84e412f
HG
309 hflip = sd->hflip->val;
310 vflip = sd->vflip->val;
ac3d5bfe
LK
311
312 if (reg) {
313 vflip = !vflip;
314 hflip = !hflip;
315 }
1b844b53
EA
316 s5k83a_set_flip_real((struct gspca_dev *) sd,
317 vflip, hflip);
ac3d5bfe
LK
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) {
c84e412f
HG
326 hflip = sd->hflip->val;
327 vflip = sd->vflip->val;
ac3d5bfe
LK
328 s5k83a_set_flip_real((struct gspca_dev *) sd, vflip, hflip);
329 }
330
c84e412f 331 sd->rotation_thread = NULL;
ac3d5bfe
LK
332 return 0;
333}
334
4a7581f0
LK
335int s5k83a_start(struct sd *sd)
336{
cde41bb2 337 int i, err = 0;
ac3d5bfe
LK
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 */
c84e412f
HG
342 sd->rotation_thread = kthread_create(rotation_thread_function,
343 sd, "rotation thread");
13174c38
PB
344 if (IS_ERR(sd->rotation_thread)) {
345 err = PTR_ERR(sd->rotation_thread);
346 sd->rotation_thread = NULL;
347 return err;
348 }
c84e412f 349 wake_up_process(sd->rotation_thread);
ac3d5bfe 350
cde41bb2
EA
351 /* Preinit the sensor */
352 for (i = 0; i < ARRAY_SIZE(start_s5k83a) && !err; i++) {
353 u8 data[2] = {start_s5k83a[i][2], start_s5k83a[i][3]};
354 if (start_s5k83a[i][0] == SENSOR)
355 err = m5602_write_sensor(sd, start_s5k83a[i][1],
356 data, 2);
357 else
358 err = m5602_write_bridge(sd, start_s5k83a[i][1],
359 data[0]);
360 }
361 if (err < 0)
362 return err;
363
4a7581f0
LK
364 return s5k83a_set_led_indication(sd, 1);
365}
366
367int s5k83a_stop(struct sd *sd)
368{
c84e412f
HG
369 if (sd->rotation_thread)
370 kthread_stop(sd->rotation_thread);
ac3d5bfe 371
4a7581f0
LK
372 return s5k83a_set_led_indication(sd, 0);
373}
374
ac3d5bfe 375void s5k83a_disconnect(struct sd *sd)
c109f816 376{
ac3d5bfe 377 s5k83a_stop(sd);
c109f816 378
ac3d5bfe 379 sd->sensor = NULL;
c109f816
EA
380}
381
cf811d50 382static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
c109f816
EA
383{
384 int err;
385 u8 data[2];
386 struct sd *sd = (struct sd *) gspca_dev;
387
388 data[0] = 0x00;
389 data[1] = 0x20;
6dc4cff0 390 err = m5602_write_sensor(sd, 0x14, data, 2);
c109f816 391 if (err < 0)
051781b3 392 return err;
c109f816
EA
393
394 data[0] = 0x01;
395 data[1] = 0x00;
6dc4cff0 396 err = m5602_write_sensor(sd, 0x0d, data, 2);
c109f816 397 if (err < 0)
051781b3 398 return err;
c109f816
EA
399
400 /* FIXME: This is not sane, we need to figure out the composition
401 of these registers */
ac3d5bfe
LK
402 data[0] = val >> 3; /* gain, high 5 bits */
403 data[1] = val >> 1; /* gain, high 7 bits */
404 err = m5602_write_sensor(sd, S5K83A_GAIN, data, 2);
c109f816 405
7b2cd079 406 return err;
c109f816
EA
407}
408
cf811d50 409static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
c109f816
EA
410{
411 int err;
412 u8 data[1];
413 struct sd *sd = (struct sd *) gspca_dev;
414
415 data[0] = val;
ac3d5bfe 416 err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 1);
7b2cd079 417 return err;
c109f816
EA
418}
419
cf811d50 420static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
c109f816 421{
18f8fae1 422 int err;
c109f816
EA
423 u8 data[2];
424 struct sd *sd = (struct sd *) gspca_dev;
425
426 data[0] = 0;
427 data[1] = val;
ac3d5bfe 428 err = m5602_write_sensor(sd, S5K83A_EXPOSURE, data, 2);
7b2cd079 429 return err;
c109f816 430}
18f8fae1 431
57851d0c
EA
432static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
433 __s32 vflip, __s32 hflip)
18f8fae1
EA
434{
435 int err;
436 u8 data[1];
437 struct sd *sd = (struct sd *) gspca_dev;
438
439 data[0] = 0x05;
6dc4cff0 440 err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
18f8fae1 441 if (err < 0)
051781b3 442 return err;
18f8fae1 443
ac3d5bfe
LK
444 /* six bit is vflip, seven is hflip */
445 data[0] = S5K83A_FLIP_MASK;
446 data[0] = (vflip) ? data[0] | 0x40 : data[0];
447 data[0] = (hflip) ? data[0] | 0x80 : data[0];
18f8fae1 448
6dc4cff0 449 err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1);
18f8fae1 450 if (err < 0)
051781b3 451 return err;
18f8fae1 452
ac3d5bfe 453 data[0] = (vflip) ? 0x0b : 0x0a;
6dc4cff0 454 err = m5602_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1);
ac3d5bfe
LK
455 if (err < 0)
456 return err;
18f8fae1 457
ac3d5bfe
LK
458 data[0] = (hflip) ? 0x0a : 0x0b;
459 err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1);
7b2cd079 460 return err;
18f8fae1
EA
461}
462
c84e412f 463static int s5k83a_set_hvflip(struct gspca_dev *gspca_dev)
18f8fae1
EA
464{
465 int err;
ac3d5bfe 466 u8 reg;
18f8fae1 467 struct sd *sd = (struct sd *) gspca_dev;
c84e412f
HG
468 int hflip = sd->hflip->val;
469 int vflip = sd->vflip->val;
ac3d5bfe
LK
470
471 err = s5k83a_get_rotation(sd, &reg);
18f8fae1 472 if (err < 0)
051781b3 473 return err;
ac3d5bfe 474 if (reg) {
ac3d5bfe 475 hflip = !hflip;
c84e412f 476 vflip = !vflip;
ac3d5bfe 477 }
18f8fae1 478
c84e412f 479 err = s5k83a_set_flip_real(gspca_dev, vflip, hflip);
7b2cd079 480 return err;
18f8fae1
EA
481}
482
c84e412f 483static int s5k83a_s_ctrl(struct v4l2_ctrl *ctrl)
18f8fae1 484{
c84e412f
HG
485 struct gspca_dev *gspca_dev =
486 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
18f8fae1 487 int err;
18f8fae1 488
c84e412f
HG
489 if (!gspca_dev->streaming)
490 return 0;
491
492 switch (ctrl->id) {
493 case V4L2_CID_BRIGHTNESS:
494 err = s5k83a_set_brightness(gspca_dev, ctrl->val);
495 break;
496 case V4L2_CID_EXPOSURE:
497 err = s5k83a_set_exposure(gspca_dev, ctrl->val);
498 break;
499 case V4L2_CID_GAIN:
500 err = s5k83a_set_gain(gspca_dev, ctrl->val);
501 break;
502 case V4L2_CID_HFLIP:
503 err = s5k83a_set_hvflip(gspca_dev);
504 break;
505 default:
506 return -EINVAL;
ac3d5bfe 507 }
18f8fae1 508
7b2cd079 509 return err;
18f8fae1 510}
4a7581f0 511
ac3d5bfe 512static int s5k83a_set_led_indication(struct sd *sd, u8 val)
4a7581f0
LK
513{
514 int err = 0;
515 u8 data[1];
516
517 err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, data);
518 if (err < 0)
519 return err;
520
521 if (val)
522 data[0] = data[0] | S5K83A_GPIO_LED_MASK;
523 else
524 data[0] = data[0] & ~S5K83A_GPIO_LED_MASK;
525
526 err = m5602_write_bridge(sd, M5602_XB_GPIO_DAT, data[0]);
527
57851d0c 528 return err;
4a7581f0 529}
ac3d5bfe
LK
530
531/* Get camera rotation on Acer notebooks */
532static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data)
533{
534 int err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, reg_data);
535 *reg_data = (*reg_data & S5K83A_GPIO_ROTATION_MASK) ? 0 : 1;
536 return err;
537}
538
539static void s5k83a_dump_registers(struct sd *sd)
540{
541 int address;
542 u8 page, old_page;
543 m5602_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
544
545 for (page = 0; page < 16; page++) {
546 m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
bdfe91f4
JP
547 pr_info("Dumping the s5k83a register state for page 0x%x\n",
548 page);
ac3d5bfe
LK
549 for (address = 0; address <= 0xff; address++) {
550 u8 val = 0;
551 m5602_read_sensor(sd, address, &val, 1);
bdfe91f4 552 pr_info("register 0x%x contains 0x%x\n", address, val);
ac3d5bfe
LK
553 }
554 }
bdfe91f4 555 pr_info("s5k83a register state dump complete\n");
ac3d5bfe
LK
556
557 for (page = 0; page < 16; page++) {
558 m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
bdfe91f4
JP
559 pr_info("Probing for which registers that are read/write for page 0x%x\n",
560 page);
ac3d5bfe
LK
561 for (address = 0; address <= 0xff; address++) {
562 u8 old_val, ctrl_val, test_val = 0xff;
563
564 m5602_read_sensor(sd, address, &old_val, 1);
565 m5602_write_sensor(sd, address, &test_val, 1);
566 m5602_read_sensor(sd, address, &ctrl_val, 1);
567
568 if (ctrl_val == test_val)
bdfe91f4
JP
569 pr_info("register 0x%x is writeable\n",
570 address);
ac3d5bfe 571 else
bdfe91f4
JP
572 pr_info("register 0x%x is read only\n",
573 address);
ac3d5bfe
LK
574
575 /* Restore original val */
576 m5602_write_sensor(sd, address, &old_val, 1);
577 }
578 }
bdfe91f4 579 pr_info("Read/write register probing complete\n");
ac3d5bfe
LK
580 m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
581}