1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Driver for the s5k83a sensor
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2008 Erik Andrén
6*4882a593Smuzhiyun * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
7*4882a593Smuzhiyun * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * Portions of code to USB interface and ALi driver software,
10*4882a593Smuzhiyun * Copyright (c) 2006 Willem Duinker
11*4882a593Smuzhiyun * v4l2 interface modeled after the V4L2 driver
12*4882a593Smuzhiyun * for SN9C10x PC Camera Controllers
13*4882a593Smuzhiyun */
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include <linux/kthread.h>
18*4882a593Smuzhiyun #include "m5602_s5k83a.h"
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun static int s5k83a_s_ctrl(struct v4l2_ctrl *ctrl);
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun static const struct v4l2_ctrl_ops s5k83a_ctrl_ops = {
23*4882a593Smuzhiyun .s_ctrl = s5k83a_s_ctrl,
24*4882a593Smuzhiyun };
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun static struct v4l2_pix_format s5k83a_modes[] = {
27*4882a593Smuzhiyun {
28*4882a593Smuzhiyun 640,
29*4882a593Smuzhiyun 480,
30*4882a593Smuzhiyun V4L2_PIX_FMT_SBGGR8,
31*4882a593Smuzhiyun V4L2_FIELD_NONE,
32*4882a593Smuzhiyun .sizeimage =
33*4882a593Smuzhiyun 640 * 480,
34*4882a593Smuzhiyun .bytesperline = 640,
35*4882a593Smuzhiyun .colorspace = V4L2_COLORSPACE_SRGB,
36*4882a593Smuzhiyun .priv = 0
37*4882a593Smuzhiyun }
38*4882a593Smuzhiyun };
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun static const unsigned char preinit_s5k83a[][4] = {
41*4882a593Smuzhiyun {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
42*4882a593Smuzhiyun {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
43*4882a593Smuzhiyun {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
44*4882a593Smuzhiyun {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
45*4882a593Smuzhiyun {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
46*4882a593Smuzhiyun {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00},
47*4882a593Smuzhiyun {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00},
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
50*4882a593Smuzhiyun {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
51*4882a593Smuzhiyun {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
52*4882a593Smuzhiyun {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
53*4882a593Smuzhiyun {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
54*4882a593Smuzhiyun {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
55*4882a593Smuzhiyun {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
56*4882a593Smuzhiyun {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
57*4882a593Smuzhiyun {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
58*4882a593Smuzhiyun {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
59*4882a593Smuzhiyun {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
60*4882a593Smuzhiyun {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
61*4882a593Smuzhiyun {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
62*4882a593Smuzhiyun {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
63*4882a593Smuzhiyun {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
64*4882a593Smuzhiyun {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
65*4882a593Smuzhiyun {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
66*4882a593Smuzhiyun {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
67*4882a593Smuzhiyun {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
68*4882a593Smuzhiyun {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
69*4882a593Smuzhiyun {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00},
70*4882a593Smuzhiyun {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
71*4882a593Smuzhiyun {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
72*4882a593Smuzhiyun {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
73*4882a593Smuzhiyun {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
74*4882a593Smuzhiyun {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
75*4882a593Smuzhiyun };
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun /* This could probably be considerably shortened.
78*4882a593Smuzhiyun I don't have the hardware to experiment with it, patches welcome
79*4882a593Smuzhiyun */
80*4882a593Smuzhiyun static const unsigned char init_s5k83a[][4] = {
81*4882a593Smuzhiyun /* The following sequence is useless after a clean boot
82*4882a593Smuzhiyun but is necessary after resume from suspend */
83*4882a593Smuzhiyun {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
84*4882a593Smuzhiyun {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
85*4882a593Smuzhiyun {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
86*4882a593Smuzhiyun {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
87*4882a593Smuzhiyun {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
88*4882a593Smuzhiyun {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
89*4882a593Smuzhiyun {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
90*4882a593Smuzhiyun {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
91*4882a593Smuzhiyun {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
92*4882a593Smuzhiyun {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
93*4882a593Smuzhiyun {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
94*4882a593Smuzhiyun {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
95*4882a593Smuzhiyun {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
96*4882a593Smuzhiyun {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
97*4882a593Smuzhiyun {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
98*4882a593Smuzhiyun {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
99*4882a593Smuzhiyun {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
100*4882a593Smuzhiyun {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
101*4882a593Smuzhiyun {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
102*4882a593Smuzhiyun {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
103*4882a593Smuzhiyun {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
104*4882a593Smuzhiyun {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
105*4882a593Smuzhiyun {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
106*4882a593Smuzhiyun {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
107*4882a593Smuzhiyun {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun {SENSOR, S5K83A_PAGE_MAP, 0x04, 0x00},
110*4882a593Smuzhiyun {SENSOR, 0xaf, 0x01, 0x00},
111*4882a593Smuzhiyun {SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00},
112*4882a593Smuzhiyun {SENSOR, 0x7b, 0xff, 0x00},
113*4882a593Smuzhiyun {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
114*4882a593Smuzhiyun {SENSOR, 0x01, 0x50, 0x00},
115*4882a593Smuzhiyun {SENSOR, 0x12, 0x20, 0x00},
116*4882a593Smuzhiyun {SENSOR, 0x17, 0x40, 0x00},
117*4882a593Smuzhiyun {SENSOR, 0x1c, 0x00, 0x00},
118*4882a593Smuzhiyun {SENSOR, 0x02, 0x70, 0x00},
119*4882a593Smuzhiyun {SENSOR, 0x03, 0x0b, 0x00},
120*4882a593Smuzhiyun {SENSOR, 0x04, 0xf0, 0x00},
121*4882a593Smuzhiyun {SENSOR, 0x05, 0x0b, 0x00},
122*4882a593Smuzhiyun {SENSOR, 0x06, 0x71, 0x00},
123*4882a593Smuzhiyun {SENSOR, 0x07, 0xe8, 0x00}, /* 488 */
124*4882a593Smuzhiyun {SENSOR, 0x08, 0x02, 0x00},
125*4882a593Smuzhiyun {SENSOR, 0x09, 0x88, 0x00}, /* 648 */
126*4882a593Smuzhiyun {SENSOR, 0x14, 0x00, 0x00},
127*4882a593Smuzhiyun {SENSOR, 0x15, 0x20, 0x00}, /* 32 */
128*4882a593Smuzhiyun {SENSOR, 0x19, 0x00, 0x00},
129*4882a593Smuzhiyun {SENSOR, 0x1a, 0x98, 0x00}, /* 152 */
130*4882a593Smuzhiyun {SENSOR, 0x0f, 0x02, 0x00},
131*4882a593Smuzhiyun {SENSOR, 0x10, 0xe5, 0x00}, /* 741 */
132*4882a593Smuzhiyun /* normal colors
133*4882a593Smuzhiyun (this is value after boot, but after tries can be different) */
134*4882a593Smuzhiyun {SENSOR, 0x00, 0x06, 0x00},
135*4882a593Smuzhiyun };
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun static const unsigned char start_s5k83a[][4] = {
138*4882a593Smuzhiyun {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
139*4882a593Smuzhiyun {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
140*4882a593Smuzhiyun {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
141*4882a593Smuzhiyun {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
142*4882a593Smuzhiyun {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
143*4882a593Smuzhiyun {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
144*4882a593Smuzhiyun {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
145*4882a593Smuzhiyun {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
146*4882a593Smuzhiyun {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
147*4882a593Smuzhiyun {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
148*4882a593Smuzhiyun {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
149*4882a593Smuzhiyun {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
150*4882a593Smuzhiyun {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00}, /* 484 */
151*4882a593Smuzhiyun {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
152*4882a593Smuzhiyun {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
153*4882a593Smuzhiyun {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
154*4882a593Smuzhiyun {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
155*4882a593Smuzhiyun {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
156*4882a593Smuzhiyun {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
157*4882a593Smuzhiyun {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
158*4882a593Smuzhiyun {BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00}, /* 639 */
159*4882a593Smuzhiyun {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
160*4882a593Smuzhiyun {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
161*4882a593Smuzhiyun {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
162*4882a593Smuzhiyun };
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun static void s5k83a_dump_registers(struct sd *sd);
165*4882a593Smuzhiyun static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data);
166*4882a593Smuzhiyun static int s5k83a_set_led_indication(struct sd *sd, u8 val);
167*4882a593Smuzhiyun static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
168*4882a593Smuzhiyun __s32 vflip, __s32 hflip);
169*4882a593Smuzhiyun
s5k83a_probe(struct sd * sd)170*4882a593Smuzhiyun int s5k83a_probe(struct sd *sd)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun u8 prod_id = 0, ver_id = 0;
173*4882a593Smuzhiyun int i, err = 0;
174*4882a593Smuzhiyun struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun if (force_sensor) {
177*4882a593Smuzhiyun if (force_sensor == S5K83A_SENSOR) {
178*4882a593Smuzhiyun pr_info("Forcing a %s sensor\n", s5k83a.name);
179*4882a593Smuzhiyun goto sensor_found;
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun /* If we want to force another sensor, don't try to probe this
182*4882a593Smuzhiyun * one */
183*4882a593Smuzhiyun return -ENODEV;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun gspca_dbg(gspca_dev, D_PROBE, "Probing for a s5k83a sensor\n");
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun /* Preinit the sensor */
189*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(preinit_s5k83a) && !err; i++) {
190*4882a593Smuzhiyun u8 data[2] = {preinit_s5k83a[i][2], preinit_s5k83a[i][3]};
191*4882a593Smuzhiyun if (preinit_s5k83a[i][0] == SENSOR)
192*4882a593Smuzhiyun err = m5602_write_sensor(sd, preinit_s5k83a[i][1],
193*4882a593Smuzhiyun data, 2);
194*4882a593Smuzhiyun else
195*4882a593Smuzhiyun err = m5602_write_bridge(sd, preinit_s5k83a[i][1],
196*4882a593Smuzhiyun data[0]);
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun /* We don't know what register (if any) that contain the product id
200*4882a593Smuzhiyun * Just pick the first addresses that seem to produce the same results
201*4882a593Smuzhiyun * on multiple machines */
202*4882a593Smuzhiyun if (m5602_read_sensor(sd, 0x00, &prod_id, 1))
203*4882a593Smuzhiyun return -ENODEV;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun if (m5602_read_sensor(sd, 0x01, &ver_id, 1))
206*4882a593Smuzhiyun return -ENODEV;
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun if ((prod_id == 0xff) || (ver_id == 0xff))
209*4882a593Smuzhiyun return -ENODEV;
210*4882a593Smuzhiyun else
211*4882a593Smuzhiyun pr_info("Detected a s5k83a sensor\n");
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun sensor_found:
214*4882a593Smuzhiyun sd->gspca_dev.cam.cam_mode = s5k83a_modes;
215*4882a593Smuzhiyun sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k83a_modes);
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun /* null the pointer! thread is't running now */
218*4882a593Smuzhiyun sd->rotation_thread = NULL;
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun return 0;
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun
s5k83a_init(struct sd * sd)223*4882a593Smuzhiyun int s5k83a_init(struct sd *sd)
224*4882a593Smuzhiyun {
225*4882a593Smuzhiyun int i, err = 0;
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(init_s5k83a) && !err; i++) {
228*4882a593Smuzhiyun u8 data[2] = {0x00, 0x00};
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun switch (init_s5k83a[i][0]) {
231*4882a593Smuzhiyun case BRIDGE:
232*4882a593Smuzhiyun err = m5602_write_bridge(sd,
233*4882a593Smuzhiyun init_s5k83a[i][1],
234*4882a593Smuzhiyun init_s5k83a[i][2]);
235*4882a593Smuzhiyun break;
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun case SENSOR:
238*4882a593Smuzhiyun data[0] = init_s5k83a[i][2];
239*4882a593Smuzhiyun err = m5602_write_sensor(sd,
240*4882a593Smuzhiyun init_s5k83a[i][1], data, 1);
241*4882a593Smuzhiyun break;
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun case SENSOR_LONG:
244*4882a593Smuzhiyun data[0] = init_s5k83a[i][2];
245*4882a593Smuzhiyun data[1] = init_s5k83a[i][3];
246*4882a593Smuzhiyun err = m5602_write_sensor(sd,
247*4882a593Smuzhiyun init_s5k83a[i][1], data, 2);
248*4882a593Smuzhiyun break;
249*4882a593Smuzhiyun default:
250*4882a593Smuzhiyun pr_info("Invalid stream command, exiting init\n");
251*4882a593Smuzhiyun return -EINVAL;
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun if (dump_sensor)
256*4882a593Smuzhiyun s5k83a_dump_registers(sd);
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun return err;
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun
s5k83a_init_controls(struct sd * sd)261*4882a593Smuzhiyun int s5k83a_init_controls(struct sd *sd)
262*4882a593Smuzhiyun {
263*4882a593Smuzhiyun struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun sd->gspca_dev.vdev.ctrl_handler = hdl;
266*4882a593Smuzhiyun v4l2_ctrl_handler_init(hdl, 6);
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_BRIGHTNESS,
269*4882a593Smuzhiyun 0, 255, 1, S5K83A_DEFAULT_BRIGHTNESS);
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_EXPOSURE,
272*4882a593Smuzhiyun 0, S5K83A_MAXIMUM_EXPOSURE, 1,
273*4882a593Smuzhiyun S5K83A_DEFAULT_EXPOSURE);
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_GAIN,
276*4882a593Smuzhiyun 0, 255, 1, S5K83A_DEFAULT_GAIN);
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun sd->hflip = v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_HFLIP,
279*4882a593Smuzhiyun 0, 1, 1, 0);
280*4882a593Smuzhiyun sd->vflip = v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_VFLIP,
281*4882a593Smuzhiyun 0, 1, 1, 0);
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun if (hdl->error) {
284*4882a593Smuzhiyun pr_err("Could not initialize controls\n");
285*4882a593Smuzhiyun return hdl->error;
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun v4l2_ctrl_cluster(2, &sd->hflip);
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun return 0;
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun
rotation_thread_function(void * data)293*4882a593Smuzhiyun static int rotation_thread_function(void *data)
294*4882a593Smuzhiyun {
295*4882a593Smuzhiyun struct sd *sd = (struct sd *) data;
296*4882a593Smuzhiyun u8 reg, previous_rotation = 0;
297*4882a593Smuzhiyun __s32 vflip, hflip;
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun set_current_state(TASK_INTERRUPTIBLE);
300*4882a593Smuzhiyun while (!schedule_timeout(msecs_to_jiffies(100))) {
301*4882a593Smuzhiyun if (mutex_lock_interruptible(&sd->gspca_dev.usb_lock))
302*4882a593Smuzhiyun break;
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun s5k83a_get_rotation(sd, ®);
305*4882a593Smuzhiyun if (previous_rotation != reg) {
306*4882a593Smuzhiyun previous_rotation = reg;
307*4882a593Smuzhiyun pr_info("Camera was flipped\n");
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun hflip = sd->hflip->val;
310*4882a593Smuzhiyun vflip = sd->vflip->val;
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun if (reg) {
313*4882a593Smuzhiyun vflip = !vflip;
314*4882a593Smuzhiyun hflip = !hflip;
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun s5k83a_set_flip_real((struct gspca_dev *) sd,
317*4882a593Smuzhiyun vflip, hflip);
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun mutex_unlock(&sd->gspca_dev.usb_lock);
321*4882a593Smuzhiyun set_current_state(TASK_INTERRUPTIBLE);
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun /* return to "front" flip */
325*4882a593Smuzhiyun if (previous_rotation) {
326*4882a593Smuzhiyun hflip = sd->hflip->val;
327*4882a593Smuzhiyun vflip = sd->vflip->val;
328*4882a593Smuzhiyun s5k83a_set_flip_real((struct gspca_dev *) sd, vflip, hflip);
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun sd->rotation_thread = NULL;
332*4882a593Smuzhiyun return 0;
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun
s5k83a_start(struct sd * sd)335*4882a593Smuzhiyun int s5k83a_start(struct sd *sd)
336*4882a593Smuzhiyun {
337*4882a593Smuzhiyun int i, err = 0;
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun /* Create another thread, polling the GPIO ports of the camera to check
340*4882a593Smuzhiyun if it got rotated. This is how the windows driver does it so we have
341*4882a593Smuzhiyun to assume that there is no better way of accomplishing this */
342*4882a593Smuzhiyun sd->rotation_thread = kthread_create(rotation_thread_function,
343*4882a593Smuzhiyun sd, "rotation thread");
344*4882a593Smuzhiyun if (IS_ERR(sd->rotation_thread)) {
345*4882a593Smuzhiyun err = PTR_ERR(sd->rotation_thread);
346*4882a593Smuzhiyun sd->rotation_thread = NULL;
347*4882a593Smuzhiyun return err;
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun wake_up_process(sd->rotation_thread);
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun /* Preinit the sensor */
352*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(start_s5k83a) && !err; i++) {
353*4882a593Smuzhiyun u8 data[2] = {start_s5k83a[i][2], start_s5k83a[i][3]};
354*4882a593Smuzhiyun if (start_s5k83a[i][0] == SENSOR)
355*4882a593Smuzhiyun err = m5602_write_sensor(sd, start_s5k83a[i][1],
356*4882a593Smuzhiyun data, 2);
357*4882a593Smuzhiyun else
358*4882a593Smuzhiyun err = m5602_write_bridge(sd, start_s5k83a[i][1],
359*4882a593Smuzhiyun data[0]);
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun if (err < 0)
362*4882a593Smuzhiyun return err;
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun return s5k83a_set_led_indication(sd, 1);
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun
s5k83a_stop(struct sd * sd)367*4882a593Smuzhiyun int s5k83a_stop(struct sd *sd)
368*4882a593Smuzhiyun {
369*4882a593Smuzhiyun if (sd->rotation_thread)
370*4882a593Smuzhiyun kthread_stop(sd->rotation_thread);
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun return s5k83a_set_led_indication(sd, 0);
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun
s5k83a_disconnect(struct sd * sd)375*4882a593Smuzhiyun void s5k83a_disconnect(struct sd *sd)
376*4882a593Smuzhiyun {
377*4882a593Smuzhiyun s5k83a_stop(sd);
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun sd->sensor = NULL;
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun
s5k83a_set_gain(struct gspca_dev * gspca_dev,__s32 val)382*4882a593Smuzhiyun static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
383*4882a593Smuzhiyun {
384*4882a593Smuzhiyun int err;
385*4882a593Smuzhiyun u8 data[2];
386*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun data[0] = 0x00;
389*4882a593Smuzhiyun data[1] = 0x20;
390*4882a593Smuzhiyun err = m5602_write_sensor(sd, 0x14, data, 2);
391*4882a593Smuzhiyun if (err < 0)
392*4882a593Smuzhiyun return err;
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun data[0] = 0x01;
395*4882a593Smuzhiyun data[1] = 0x00;
396*4882a593Smuzhiyun err = m5602_write_sensor(sd, 0x0d, data, 2);
397*4882a593Smuzhiyun if (err < 0)
398*4882a593Smuzhiyun return err;
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun /* FIXME: This is not sane, we need to figure out the composition
401*4882a593Smuzhiyun of these registers */
402*4882a593Smuzhiyun data[0] = val >> 3; /* gain, high 5 bits */
403*4882a593Smuzhiyun data[1] = val >> 1; /* gain, high 7 bits */
404*4882a593Smuzhiyun err = m5602_write_sensor(sd, S5K83A_GAIN, data, 2);
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun return err;
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun
s5k83a_set_brightness(struct gspca_dev * gspca_dev,__s32 val)409*4882a593Smuzhiyun static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
410*4882a593Smuzhiyun {
411*4882a593Smuzhiyun int err;
412*4882a593Smuzhiyun u8 data[1];
413*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun data[0] = val;
416*4882a593Smuzhiyun err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 1);
417*4882a593Smuzhiyun return err;
418*4882a593Smuzhiyun }
419*4882a593Smuzhiyun
s5k83a_set_exposure(struct gspca_dev * gspca_dev,__s32 val)420*4882a593Smuzhiyun static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
421*4882a593Smuzhiyun {
422*4882a593Smuzhiyun int err;
423*4882a593Smuzhiyun u8 data[2];
424*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun data[0] = 0;
427*4882a593Smuzhiyun data[1] = val;
428*4882a593Smuzhiyun err = m5602_write_sensor(sd, S5K83A_EXPOSURE, data, 2);
429*4882a593Smuzhiyun return err;
430*4882a593Smuzhiyun }
431*4882a593Smuzhiyun
s5k83a_set_flip_real(struct gspca_dev * gspca_dev,__s32 vflip,__s32 hflip)432*4882a593Smuzhiyun static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
433*4882a593Smuzhiyun __s32 vflip, __s32 hflip)
434*4882a593Smuzhiyun {
435*4882a593Smuzhiyun int err;
436*4882a593Smuzhiyun u8 data[1];
437*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun data[0] = 0x05;
440*4882a593Smuzhiyun err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
441*4882a593Smuzhiyun if (err < 0)
442*4882a593Smuzhiyun return err;
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun /* six bit is vflip, seven is hflip */
445*4882a593Smuzhiyun data[0] = S5K83A_FLIP_MASK;
446*4882a593Smuzhiyun data[0] = (vflip) ? data[0] | 0x40 : data[0];
447*4882a593Smuzhiyun data[0] = (hflip) ? data[0] | 0x80 : data[0];
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1);
450*4882a593Smuzhiyun if (err < 0)
451*4882a593Smuzhiyun return err;
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun data[0] = (vflip) ? 0x0b : 0x0a;
454*4882a593Smuzhiyun err = m5602_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1);
455*4882a593Smuzhiyun if (err < 0)
456*4882a593Smuzhiyun return err;
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun data[0] = (hflip) ? 0x0a : 0x0b;
459*4882a593Smuzhiyun err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1);
460*4882a593Smuzhiyun return err;
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun
s5k83a_set_hvflip(struct gspca_dev * gspca_dev)463*4882a593Smuzhiyun static int s5k83a_set_hvflip(struct gspca_dev *gspca_dev)
464*4882a593Smuzhiyun {
465*4882a593Smuzhiyun int err;
466*4882a593Smuzhiyun u8 reg;
467*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
468*4882a593Smuzhiyun int hflip = sd->hflip->val;
469*4882a593Smuzhiyun int vflip = sd->vflip->val;
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun err = s5k83a_get_rotation(sd, ®);
472*4882a593Smuzhiyun if (err < 0)
473*4882a593Smuzhiyun return err;
474*4882a593Smuzhiyun if (reg) {
475*4882a593Smuzhiyun hflip = !hflip;
476*4882a593Smuzhiyun vflip = !vflip;
477*4882a593Smuzhiyun }
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun err = s5k83a_set_flip_real(gspca_dev, vflip, hflip);
480*4882a593Smuzhiyun return err;
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun
s5k83a_s_ctrl(struct v4l2_ctrl * ctrl)483*4882a593Smuzhiyun static int s5k83a_s_ctrl(struct v4l2_ctrl *ctrl)
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun struct gspca_dev *gspca_dev =
486*4882a593Smuzhiyun container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
487*4882a593Smuzhiyun int err;
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun if (!gspca_dev->streaming)
490*4882a593Smuzhiyun return 0;
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun switch (ctrl->id) {
493*4882a593Smuzhiyun case V4L2_CID_BRIGHTNESS:
494*4882a593Smuzhiyun err = s5k83a_set_brightness(gspca_dev, ctrl->val);
495*4882a593Smuzhiyun break;
496*4882a593Smuzhiyun case V4L2_CID_EXPOSURE:
497*4882a593Smuzhiyun err = s5k83a_set_exposure(gspca_dev, ctrl->val);
498*4882a593Smuzhiyun break;
499*4882a593Smuzhiyun case V4L2_CID_GAIN:
500*4882a593Smuzhiyun err = s5k83a_set_gain(gspca_dev, ctrl->val);
501*4882a593Smuzhiyun break;
502*4882a593Smuzhiyun case V4L2_CID_HFLIP:
503*4882a593Smuzhiyun err = s5k83a_set_hvflip(gspca_dev);
504*4882a593Smuzhiyun break;
505*4882a593Smuzhiyun default:
506*4882a593Smuzhiyun return -EINVAL;
507*4882a593Smuzhiyun }
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun return err;
510*4882a593Smuzhiyun }
511*4882a593Smuzhiyun
s5k83a_set_led_indication(struct sd * sd,u8 val)512*4882a593Smuzhiyun static int s5k83a_set_led_indication(struct sd *sd, u8 val)
513*4882a593Smuzhiyun {
514*4882a593Smuzhiyun int err = 0;
515*4882a593Smuzhiyun u8 data[1];
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, data);
518*4882a593Smuzhiyun if (err < 0)
519*4882a593Smuzhiyun return err;
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun if (val)
522*4882a593Smuzhiyun data[0] = data[0] | S5K83A_GPIO_LED_MASK;
523*4882a593Smuzhiyun else
524*4882a593Smuzhiyun data[0] = data[0] & ~S5K83A_GPIO_LED_MASK;
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun err = m5602_write_bridge(sd, M5602_XB_GPIO_DAT, data[0]);
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun return err;
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun /* Get camera rotation on Acer notebooks */
s5k83a_get_rotation(struct sd * sd,u8 * reg_data)532*4882a593Smuzhiyun static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data)
533*4882a593Smuzhiyun {
534*4882a593Smuzhiyun int err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, reg_data);
535*4882a593Smuzhiyun *reg_data = (*reg_data & S5K83A_GPIO_ROTATION_MASK) ? 0 : 1;
536*4882a593Smuzhiyun return err;
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun
s5k83a_dump_registers(struct sd * sd)539*4882a593Smuzhiyun static void s5k83a_dump_registers(struct sd *sd)
540*4882a593Smuzhiyun {
541*4882a593Smuzhiyun int address;
542*4882a593Smuzhiyun u8 page, old_page;
543*4882a593Smuzhiyun m5602_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun for (page = 0; page < 16; page++) {
546*4882a593Smuzhiyun m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
547*4882a593Smuzhiyun pr_info("Dumping the s5k83a register state for page 0x%x\n",
548*4882a593Smuzhiyun page);
549*4882a593Smuzhiyun for (address = 0; address <= 0xff; address++) {
550*4882a593Smuzhiyun u8 val = 0;
551*4882a593Smuzhiyun m5602_read_sensor(sd, address, &val, 1);
552*4882a593Smuzhiyun pr_info("register 0x%x contains 0x%x\n", address, val);
553*4882a593Smuzhiyun }
554*4882a593Smuzhiyun }
555*4882a593Smuzhiyun pr_info("s5k83a register state dump complete\n");
556*4882a593Smuzhiyun
557*4882a593Smuzhiyun for (page = 0; page < 16; page++) {
558*4882a593Smuzhiyun m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
559*4882a593Smuzhiyun pr_info("Probing for which registers that are read/write for page 0x%x\n",
560*4882a593Smuzhiyun page);
561*4882a593Smuzhiyun for (address = 0; address <= 0xff; address++) {
562*4882a593Smuzhiyun u8 old_val, ctrl_val, test_val = 0xff;
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun m5602_read_sensor(sd, address, &old_val, 1);
565*4882a593Smuzhiyun m5602_write_sensor(sd, address, &test_val, 1);
566*4882a593Smuzhiyun m5602_read_sensor(sd, address, &ctrl_val, 1);
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun if (ctrl_val == test_val)
569*4882a593Smuzhiyun pr_info("register 0x%x is writeable\n",
570*4882a593Smuzhiyun address);
571*4882a593Smuzhiyun else
572*4882a593Smuzhiyun pr_info("register 0x%x is read only\n",
573*4882a593Smuzhiyun address);
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun /* Restore original val */
576*4882a593Smuzhiyun m5602_write_sensor(sd, address, &old_val, 1);
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun }
579*4882a593Smuzhiyun pr_info("Read/write register probing complete\n");
580*4882a593Smuzhiyun m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
581*4882a593Smuzhiyun }
582