1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* Subdriver for the GL860 chip with the OV9655 sensor
3 * Author Olivier LORIN, from logs done by Simon (Sur3) and Almighurt
4 * on dsd's weblog
5 */
6
7 /* Sensor : OV9655 */
8
9 #include "gl860.h"
10
11 static struct validx tbl_init_at_startup[] = {
12 {0x0000, 0x0000}, {0x0010, 0x0010}, {0x0008, 0x00c0}, {0x0001, 0x00c1},
13 {0x0001, 0x00c2}, {0x0020, 0x0006}, {0x006a, 0x000d},
14
15 {0x0040, 0x0000},
16 };
17
18 static struct validx tbl_commmon[] = {
19 {0x0041, 0x0000}, {0x006a, 0x0007}, {0x0063, 0x0006}, {0x006a, 0x000d},
20 {0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0001, 0x00c1}, {0x0041, 0x00c2},
21 {0x0004, 0x00d8}, {0x0012, 0x0004}, {0x0000, 0x0058}, {0x0040, 0x0000},
22 {0x00f3, 0x0006}, {0x0058, 0x0000}, {0x0048, 0x0000}, {0x0061, 0x0000},
23 };
24
25 static s32 tbl_length[] = {12, 56, 52, 54, 56, 42, 32, 12};
26
27 static u8 *tbl_640[] = {
28 (u8[]){
29 0x00, 0x40, 0x07, 0x6a, 0x06, 0xf3, 0x0d, 0x6a,
30 0x10, 0x10, 0xc1, 0x01
31 }, (u8[]){
32 0x12, 0x80, 0x00, 0x00, 0x01, 0x98, 0x02, 0x80,
33 0x03, 0x12, 0x04, 0x03, 0x0b, 0x57, 0x0e, 0x61,
34 0x0f, 0x42, 0x11, 0x01, 0x12, 0x60, 0x13, 0x00,
35 0x14, 0x3a, 0x16, 0x24, 0x17, 0x14, 0x18, 0x00,
36 0x19, 0x01, 0x1a, 0x3d, 0x1e, 0x04, 0x24, 0x3c,
37 0x25, 0x36, 0x26, 0x72, 0x27, 0x08, 0x28, 0x08,
38 0x29, 0x15, 0x2a, 0x00, 0x2b, 0x00, 0x2c, 0x08
39 }, (u8[]){
40 0x32, 0xff, 0x33, 0x00, 0x34, 0x3d, 0x35, 0x00,
41 0x36, 0xfa, 0x38, 0x72, 0x39, 0x57, 0x3a, 0x00,
42 0x3b, 0x0c, 0x3d, 0x99, 0x3e, 0x0c, 0x3f, 0xc1,
43 0x40, 0xc0, 0x41, 0x00, 0x42, 0xc0, 0x43, 0x0a,
44 0x44, 0xf0, 0x45, 0x46, 0x46, 0x62, 0x47, 0x2a,
45 0x48, 0x3c, 0x4a, 0xee, 0x4b, 0xe7, 0x4c, 0xe7,
46 0x4d, 0xe7, 0x4e, 0xe7
47 }, (u8[]){
48 0x4f, 0x98, 0x50, 0x98, 0x51, 0x00, 0x52, 0x28,
49 0x53, 0x70, 0x54, 0x98, 0x58, 0x1a, 0x59, 0x85,
50 0x5a, 0xa9, 0x5b, 0x64, 0x5c, 0x84, 0x5d, 0x53,
51 0x5e, 0x0e, 0x5f, 0xf0, 0x60, 0xf0, 0x61, 0xf0,
52 0x62, 0x00, 0x63, 0x00, 0x64, 0x02, 0x65, 0x20,
53 0x66, 0x00, 0x69, 0x0a, 0x6b, 0x5a, 0x6c, 0x04,
54 0x6d, 0x55, 0x6e, 0x00, 0x6f, 0x9d
55 }, (u8[]){
56 0x70, 0x15, 0x71, 0x78, 0x72, 0x00, 0x73, 0x00,
57 0x74, 0x3a, 0x75, 0x35, 0x76, 0x01, 0x77, 0x02,
58 0x7a, 0x24, 0x7b, 0x04, 0x7c, 0x07, 0x7d, 0x10,
59 0x7e, 0x28, 0x7f, 0x36, 0x80, 0x44, 0x81, 0x52,
60 0x82, 0x60, 0x83, 0x6c, 0x84, 0x78, 0x85, 0x8c,
61 0x86, 0x9e, 0x87, 0xbb, 0x88, 0xd2, 0x89, 0xe5,
62 0x8a, 0x23, 0x8c, 0x8d, 0x90, 0x7c, 0x91, 0x7b
63 }, (u8[]){
64 0x9d, 0x02, 0x9e, 0x02, 0x9f, 0x74, 0xa0, 0x73,
65 0xa1, 0x40, 0xa4, 0x50, 0xa5, 0x68, 0xa6, 0x70,
66 0xa8, 0xc1, 0xa9, 0xef, 0xaa, 0x92, 0xab, 0x04,
67 0xac, 0x80, 0xad, 0x80, 0xae, 0x80, 0xaf, 0x80,
68 0xb2, 0xf2, 0xb3, 0x20, 0xb4, 0x20, 0xb5, 0x00,
69 0xb6, 0xaf
70 }, (u8[]){
71 0xbb, 0xae, 0xbc, 0x4f, 0xbd, 0x4e, 0xbe, 0x6a,
72 0xbf, 0x68, 0xc0, 0xaa, 0xc1, 0xc0, 0xc2, 0x01,
73 0xc3, 0x4e, 0xc6, 0x85, 0xc7, 0x81, 0xc9, 0xe0,
74 0xca, 0xe8, 0xcb, 0xf0, 0xcc, 0xd8, 0xcd, 0x93
75 }, (u8[]){
76 0xd0, 0x01, 0xd1, 0x08, 0xd2, 0xe0, 0xd3, 0x01,
77 0xd4, 0x10, 0xd5, 0x80
78 }
79 };
80
81 static u8 *tbl_1280[] = {
82 (u8[]){
83 0x00, 0x40, 0x07, 0x6a, 0x06, 0xf3, 0x0d, 0x6a,
84 0x10, 0x10, 0xc1, 0x01
85 },
86 (u8[]){
87 0x12, 0x80, 0x00, 0x00, 0x01, 0x98, 0x02, 0x80,
88 0x03, 0x12, 0x04, 0x01, 0x0b, 0x57, 0x0e, 0x61,
89 0x0f, 0x42, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00,
90 0x14, 0x3a, 0x16, 0x24, 0x17, 0x1b, 0x18, 0xbb,
91 0x19, 0x01, 0x1a, 0x81, 0x1e, 0x04, 0x24, 0x3c,
92 0x25, 0x36, 0x26, 0x72, 0x27, 0x08, 0x28, 0x08,
93 0x29, 0x15, 0x2a, 0x00, 0x2b, 0x00, 0x2c, 0x08
94 },
95 (u8[]){
96 0x32, 0xa4, 0x33, 0x00, 0x34, 0x3d, 0x35, 0x00,
97 0x36, 0xf8, 0x38, 0x72, 0x39, 0x57, 0x3a, 0x00,
98 0x3b, 0x0c, 0x3d, 0x99, 0x3e, 0x0c, 0x3f, 0xc2,
99 0x40, 0xc0, 0x41, 0x00, 0x42, 0xc0, 0x43, 0x0a,
100 0x44, 0xf0, 0x45, 0x46, 0x46, 0x62, 0x47, 0x2a,
101 0x48, 0x3c, 0x4a, 0xec, 0x4b, 0xe8, 0x4c, 0xe8,
102 0x4d, 0xe8, 0x4e, 0xe8
103 },
104 (u8[]){
105 0x4f, 0x98, 0x50, 0x98, 0x51, 0x00, 0x52, 0x28,
106 0x53, 0x70, 0x54, 0x98, 0x58, 0x1a, 0x59, 0x85,
107 0x5a, 0xa9, 0x5b, 0x64, 0x5c, 0x84, 0x5d, 0x53,
108 0x5e, 0x0e, 0x5f, 0xf0, 0x60, 0xf0, 0x61, 0xf0,
109 0x62, 0x00, 0x63, 0x00, 0x64, 0x02, 0x65, 0x20,
110 0x66, 0x00, 0x69, 0x02, 0x6b, 0x5a, 0x6c, 0x04,
111 0x6d, 0x55, 0x6e, 0x00, 0x6f, 0x9d
112 },
113 (u8[]){
114 0x70, 0x08, 0x71, 0x78, 0x72, 0x00, 0x73, 0x01,
115 0x74, 0x3a, 0x75, 0x35, 0x76, 0x01, 0x77, 0x02,
116 0x7a, 0x24, 0x7b, 0x04, 0x7c, 0x07, 0x7d, 0x10,
117 0x7e, 0x28, 0x7f, 0x36, 0x80, 0x44, 0x81, 0x52,
118 0x82, 0x60, 0x83, 0x6c, 0x84, 0x78, 0x85, 0x8c,
119 0x86, 0x9e, 0x87, 0xbb, 0x88, 0xd2, 0x89, 0xe5,
120 0x8a, 0x23, 0x8c, 0x0d, 0x90, 0x90, 0x91, 0x90
121 },
122 (u8[]){
123 0x9d, 0x02, 0x9e, 0x02, 0x9f, 0x94, 0xa0, 0x94,
124 0xa1, 0x01, 0xa4, 0x50, 0xa5, 0x68, 0xa6, 0x70,
125 0xa8, 0xc1, 0xa9, 0xef, 0xaa, 0x92, 0xab, 0x04,
126 0xac, 0x80, 0xad, 0x80, 0xae, 0x80, 0xaf, 0x80,
127 0xb2, 0xf2, 0xb3, 0x20, 0xb4, 0x20, 0xb5, 0x00,
128 0xb6, 0xaf
129 },
130 (u8[]){
131 0xbb, 0xae, 0xbc, 0x38, 0xbd, 0x39, 0xbe, 0x01,
132 0xbf, 0x01, 0xc0, 0xe2, 0xc1, 0xc0, 0xc2, 0x01,
133 0xc3, 0x4e, 0xc6, 0x85, 0xc7, 0x81, 0xc9, 0xe0,
134 0xca, 0xe8, 0xcb, 0xf0, 0xcc, 0xd8, 0xcd, 0x93
135 },
136 (u8[]){
137 0xd0, 0x21, 0xd1, 0x18, 0xd2, 0xe0, 0xd3, 0x01,
138 0xd4, 0x28, 0xd5, 0x00
139 }
140 };
141
142 static u8 c04[] = {0x04};
143 static u8 dat_post1[] = "\x04\x00\x10\x20\xa1\x00\x00\x02";
144 static u8 dat_post2[] = "\x10\x10\xc1\x02";
145 static u8 dat_post3[] = "\x04\x00\x10\x7c\xa1\x00\x00\x04";
146 static u8 dat_post4[] = "\x10\x02\xc1\x06";
147 static u8 dat_post5[] = "\x04\x00\x10\x7b\xa1\x00\x00\x08";
148 static u8 dat_post6[] = "\x10\x10\xc1\x05";
149 static u8 dat_post7[] = "\x04\x00\x10\x7c\xa1\x00\x00\x08";
150 static u8 dat_post8[] = "\x04\x00\x10\x7c\xa1\x00\x00\x09";
151
152 static struct validx tbl_init_post_alt[] = {
153 {0x6032, 0x00ff}, {0x6032, 0x00ff}, {0x6032, 0x00ff}, {0x603c, 0x00ff},
154 {0x6003, 0x00ff}, {0x6032, 0x00ff}, {0x6032, 0x00ff}, {0x6001, 0x00ff},
155 {0x6000, 0x801e},
156 {0xffff, 0xffff},
157 {0x6004, 0x001e}, {0x6000, 0x801e},
158 {0xffff, 0xffff},
159 {0x6004, 0x001e}, {0x6012, 0x0003}, {0x6000, 0x801e},
160 {0xffff, 0xffff},
161 {0x6004, 0x001e}, {0x6000, 0x801e},
162 {0xffff, 0xffff},
163 {0x6004, 0x001e}, {0x6012, 0x0003},
164 {0xffff, 0xffff},
165 {0x6000, 0x801e},
166 {0xffff, 0xffff},
167 {0x6004, 0x001e}, {0x6000, 0x801e},
168 {0xffff, 0xffff},
169 {0x6004, 0x001e}, {0x6012, 0x0003}, {0x6000, 0x801e},
170 {0xffff, 0xffff},
171 {0x6004, 0x001e}, {0x6000, 0x801e},
172 {0xffff, 0xffff},
173 {0x6004, 0x001e}, {0x6012, 0x0003},
174 {0xffff, 0xffff},
175 {0x6000, 0x801e},
176 {0xffff, 0xffff},
177 {0x6004, 0x001e}, {0x6000, 0x801e},
178 {0xffff, 0xffff},
179 {0x6004, 0x001e}, {0x6012, 0x0003},
180 };
181
182 static int ov9655_init_at_startup(struct gspca_dev *gspca_dev);
183 static int ov9655_configure_alt(struct gspca_dev *gspca_dev);
184 static int ov9655_init_pre_alt(struct gspca_dev *gspca_dev);
185 static int ov9655_init_post_alt(struct gspca_dev *gspca_dev);
186 static void ov9655_post_unset_alt(struct gspca_dev *gspca_dev);
187 static int ov9655_camera_settings(struct gspca_dev *gspca_dev);
188 /*==========================================================================*/
189
ov9655_init_settings(struct gspca_dev * gspca_dev)190 void ov9655_init_settings(struct gspca_dev *gspca_dev)
191 {
192 struct sd *sd = (struct sd *) gspca_dev;
193
194 sd->vcur.backlight = 0;
195 sd->vcur.brightness = 128;
196 sd->vcur.sharpness = 0;
197 sd->vcur.contrast = 0;
198 sd->vcur.gamma = 0;
199 sd->vcur.hue = 0;
200 sd->vcur.saturation = 0;
201 sd->vcur.whitebal = 0;
202
203 sd->vmax.backlight = 0;
204 sd->vmax.brightness = 255;
205 sd->vmax.sharpness = 0;
206 sd->vmax.contrast = 0;
207 sd->vmax.gamma = 0;
208 sd->vmax.hue = 0 + 1;
209 sd->vmax.saturation = 0;
210 sd->vmax.whitebal = 0;
211 sd->vmax.mirror = 0;
212 sd->vmax.flip = 0;
213 sd->vmax.AC50Hz = 0;
214
215 sd->dev_camera_settings = ov9655_camera_settings;
216 sd->dev_init_at_startup = ov9655_init_at_startup;
217 sd->dev_configure_alt = ov9655_configure_alt;
218 sd->dev_init_pre_alt = ov9655_init_pre_alt;
219 sd->dev_post_unset_alt = ov9655_post_unset_alt;
220 }
221
222 /*==========================================================================*/
223
ov9655_init_at_startup(struct gspca_dev * gspca_dev)224 static int ov9655_init_at_startup(struct gspca_dev *gspca_dev)
225 {
226 fetch_validx(gspca_dev, tbl_init_at_startup,
227 ARRAY_SIZE(tbl_init_at_startup));
228 fetch_validx(gspca_dev, tbl_commmon, ARRAY_SIZE(tbl_commmon));
229 /* ctrl_out(gspca_dev, 0x40, 11, 0x0000, 0x0000, 0, NULL);*/
230
231 return 0;
232 }
233
ov9655_init_pre_alt(struct gspca_dev * gspca_dev)234 static int ov9655_init_pre_alt(struct gspca_dev *gspca_dev)
235 {
236 struct sd *sd = (struct sd *) gspca_dev;
237
238 sd->vold.brightness = -1;
239 sd->vold.hue = -1;
240
241 fetch_validx(gspca_dev, tbl_commmon, ARRAY_SIZE(tbl_commmon));
242
243 ov9655_init_post_alt(gspca_dev);
244
245 return 0;
246 }
247
ov9655_init_post_alt(struct gspca_dev * gspca_dev)248 static int ov9655_init_post_alt(struct gspca_dev *gspca_dev)
249 {
250 s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
251 s32 n; /* reserved for FETCH functions */
252 s32 i;
253 u8 **tbl;
254
255 ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL);
256
257 tbl = (reso == IMAGE_640) ? tbl_640 : tbl_1280;
258
259 ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200,
260 tbl_length[0], tbl[0]);
261 for (i = 1; i < 7; i++)
262 ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200,
263 tbl_length[i], tbl[i]);
264 ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200,
265 tbl_length[7], tbl[7]);
266
267 n = fetch_validx(gspca_dev, tbl_init_post_alt,
268 ARRAY_SIZE(tbl_init_post_alt));
269
270 ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
271 keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
272 ARRAY_SIZE(tbl_init_post_alt), n);
273 ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
274 keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
275 ARRAY_SIZE(tbl_init_post_alt), n);
276 ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
277 keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
278 ARRAY_SIZE(tbl_init_post_alt), n);
279 ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
280 keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
281 ARRAY_SIZE(tbl_init_post_alt), n);
282 ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post1);
283 keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
284 ARRAY_SIZE(tbl_init_post_alt), n);
285
286 ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
287 keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
288 ARRAY_SIZE(tbl_init_post_alt), n);
289 ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
290 keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
291 ARRAY_SIZE(tbl_init_post_alt), n);
292 ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
293 keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
294 ARRAY_SIZE(tbl_init_post_alt), n);
295 ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
296 keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
297 ARRAY_SIZE(tbl_init_post_alt), n);
298 ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post1);
299 keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
300 ARRAY_SIZE(tbl_init_post_alt), n);
301
302 ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
303 keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
304 ARRAY_SIZE(tbl_init_post_alt), n);
305 ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
306 keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
307 ARRAY_SIZE(tbl_init_post_alt), n);
308
309 ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post1);
310
311 ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 4, dat_post2);
312 ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post3);
313
314 ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 4, dat_post4);
315 ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post5);
316
317 ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 4, dat_post6);
318 ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post7);
319
320 ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post8);
321
322 ov9655_camera_settings(gspca_dev);
323
324 return 0;
325 }
326
ov9655_configure_alt(struct gspca_dev * gspca_dev)327 static int ov9655_configure_alt(struct gspca_dev *gspca_dev)
328 {
329 s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
330
331 switch (reso) {
332 case IMAGE_640:
333 gspca_dev->alt = 1 + 1;
334 break;
335
336 default:
337 gspca_dev->alt = 1 + 1;
338 break;
339 }
340 return 0;
341 }
342
ov9655_camera_settings(struct gspca_dev * gspca_dev)343 static int ov9655_camera_settings(struct gspca_dev *gspca_dev)
344 {
345 struct sd *sd = (struct sd *) gspca_dev;
346
347 u8 dat_bright[] = "\x04\x00\x10\x7c\xa1\x00\x00\x70";
348
349 s32 bright = sd->vcur.brightness;
350 s32 hue = sd->vcur.hue;
351
352 if (bright != sd->vold.brightness) {
353 sd->vold.brightness = bright;
354 if (bright < 0 || bright > sd->vmax.brightness)
355 bright = 0;
356
357 dat_bright[3] = bright;
358 ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_bright);
359 }
360
361 if (hue != sd->vold.hue) {
362 sd->vold.hue = hue;
363 sd->swapRB = (hue != 0);
364 }
365
366 return 0;
367 }
368
ov9655_post_unset_alt(struct gspca_dev * gspca_dev)369 static void ov9655_post_unset_alt(struct gspca_dev *gspca_dev)
370 {
371 ctrl_out(gspca_dev, 0x40, 5, 0x0000, 0x0000, 0, NULL);
372 ctrl_out(gspca_dev, 0x40, 1, 0x0061, 0x0000, 0, NULL);
373 }
374