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