1// SPDX-License-Identifier: GPL-2.0-or-later
2/* Subdriver for the GL860 chip with the MI1320 sensor
3 * Author Olivier LORIN from own logs
4 */
5
6/* Sensor : MI1320 */
7
8#include "gl860.h"
9
10static struct validx tbl_common[] = {
11	{0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xba51, 0x0066}, {0xba02, 0x00f1},
12	{0xba05, 0x0067}, {0xba05, 0x00f1}, {0xbaa0, 0x0065}, {0xba00, 0x00f1},
13	{0xffff, 0xffff},
14	{0xba00, 0x00f0}, {0xba02, 0x00f1}, {0xbafa, 0x0028}, {0xba02, 0x00f1},
15	{0xba00, 0x00f0}, {0xba01, 0x00f1}, {0xbaf0, 0x0006}, {0xba0e, 0x00f1},
16	{0xba70, 0x0006}, {0xba0e, 0x00f1},
17	{0xffff, 0xffff},
18	{0xba74, 0x0006}, {0xba0e, 0x00f1},
19	{0xffff, 0xffff},
20	{0x0061, 0x0000}, {0x0068, 0x000d},
21};
22
23static struct validx tbl_init_at_startup[] = {
24	{0x0000, 0x0000}, {0x0010, 0x0010},
25	{35, 0xffff},
26	{0x0008, 0x00c0}, {0x0001, 0x00c1}, {0x0001, 0x00c2}, {0x0020, 0x0006},
27	{0x006a, 0x000d},
28};
29
30static struct validx tbl_sensor_settings_common[] = {
31	{0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042, 0x00c2}, {0x0040, 0x0000},
32	{0x006a, 0x0007}, {0x006a, 0x000d}, {0x0063, 0x0006},
33};
34static struct validx tbl_sensor_settings_1280[] = {
35	{0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xba5a, 0x0066}, {0xba02, 0x00f1},
36	{0xba05, 0x0067}, {0xba05, 0x00f1}, {0xba20, 0x0065}, {0xba00, 0x00f1},
37};
38static struct validx tbl_sensor_settings_800[] = {
39	{0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xba5a, 0x0066}, {0xba02, 0x00f1},
40	{0xba05, 0x0067}, {0xba05, 0x00f1}, {0xba20, 0x0065}, {0xba00, 0x00f1},
41};
42static struct validx tbl_sensor_settings_640[] = {
43	{0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xbaa0, 0x0065}, {0xba00, 0x00f1},
44	{0xba51, 0x0066}, {0xba02, 0x00f1}, {0xba05, 0x0067}, {0xba05, 0x00f1},
45	{0xba20, 0x0065}, {0xba00, 0x00f1},
46};
47static struct validx tbl_post_unset_alt[] = {
48	{0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xbaa0, 0x0065}, {0xba00, 0x00f1},
49	{0x0061, 0x0000}, {0x0068, 0x000d},
50};
51
52static u8 *tbl_1280[] = {
53	(u8[]){
54		0x0d, 0x80, 0xf1, 0x08, 0x03, 0x04, 0xf1, 0x00,
55		0x04, 0x05, 0xf1, 0x02, 0x05, 0x00, 0xf1, 0xf1,
56		0x06, 0x00, 0xf1, 0x0d, 0x20, 0x01, 0xf1, 0x00,
57		0x21, 0x84, 0xf1, 0x00, 0x0d, 0x00, 0xf1, 0x08,
58		0xf0, 0x00, 0xf1, 0x01, 0x34, 0x00, 0xf1, 0x00,
59		0x9b, 0x43, 0xf1, 0x00, 0xa6, 0x05, 0xf1, 0x00,
60		0xa9, 0x04, 0xf1, 0x00, 0xa1, 0x05, 0xf1, 0x00,
61		0xa4, 0x04, 0xf1, 0x00, 0xae, 0x0a, 0xf1, 0x08
62	}, (u8[]){
63		0xf0, 0x00, 0xf1, 0x02, 0x3a, 0x05, 0xf1, 0xf1,
64		0x3c, 0x05, 0xf1, 0xf1, 0x59, 0x01, 0xf1, 0x47,
65		0x5a, 0x01, 0xf1, 0x88, 0x5c, 0x0a, 0xf1, 0x06,
66		0x5d, 0x0e, 0xf1, 0x0a, 0x64, 0x5e, 0xf1, 0x1c,
67		0xd2, 0x00, 0xf1, 0xcf, 0xcb, 0x00, 0xf1, 0x01
68	}, (u8[]){
69		0xd3, 0x02, 0xd4, 0x28, 0xd5, 0x01, 0xd0, 0x02,
70		0xd1, 0x18, 0xd2, 0xc1
71	}
72};
73
74static u8 *tbl_800[] = {
75	(u8[]){
76		0x0d, 0x80, 0xf1, 0x08, 0x03, 0x03, 0xf1, 0xc0,
77		0x04, 0x05, 0xf1, 0x02, 0x05, 0x00, 0xf1, 0xf1,
78		0x06, 0x00, 0xf1, 0x0d, 0x20, 0x01, 0xf1, 0x00,
79		0x21, 0x84, 0xf1, 0x00, 0x0d, 0x00, 0xf1, 0x08,
80		0xf0, 0x00, 0xf1, 0x01, 0x34, 0x00, 0xf1, 0x00,
81		0x9b, 0x43, 0xf1, 0x00, 0xa6, 0x05, 0xf1, 0x00,
82		0xa9, 0x03, 0xf1, 0xc0, 0xa1, 0x03, 0xf1, 0x20,
83		0xa4, 0x02, 0xf1, 0x5a, 0xae, 0x0a, 0xf1, 0x08
84	}, (u8[]){
85		0xf0, 0x00, 0xf1, 0x02, 0x3a, 0x05, 0xf1, 0xf1,
86		0x3c, 0x05, 0xf1, 0xf1, 0x59, 0x01, 0xf1, 0x47,
87		0x5a, 0x01, 0xf1, 0x88, 0x5c, 0x0a, 0xf1, 0x06,
88		0x5d, 0x0e, 0xf1, 0x0a, 0x64, 0x5e, 0xf1, 0x1c,
89		0xd2, 0x00, 0xf1, 0xcf, 0xcb, 0x00, 0xf1, 0x01
90	}, (u8[]){
91		0xd3, 0x02, 0xd4, 0x18, 0xd5, 0x21, 0xd0, 0x02,
92		0xd1, 0x10, 0xd2, 0x59
93	}
94};
95
96static u8 *tbl_640[] = {
97	(u8[]){
98		0x0d, 0x80, 0xf1, 0x08, 0x03, 0x04, 0xf1, 0x04,
99		0x04, 0x05, 0xf1, 0x02, 0x07, 0x01, 0xf1, 0x7c,
100		0x08, 0x00, 0xf1, 0x0e, 0x21, 0x80, 0xf1, 0x00,
101		0x0d, 0x00, 0xf1, 0x08, 0xf0, 0x00, 0xf1, 0x01,
102		0x34, 0x10, 0xf1, 0x10, 0x3a, 0x43, 0xf1, 0x00,
103		0xa6, 0x05, 0xf1, 0x02, 0xa9, 0x04, 0xf1, 0x04,
104		0xa7, 0x02, 0xf1, 0x81, 0xaa, 0x01, 0xf1, 0xe2,
105		0xae, 0x0c, 0xf1, 0x09
106	}, (u8[]){
107		0xf0, 0x00, 0xf1, 0x02, 0x39, 0x03, 0xf1, 0xfc,
108		0x3b, 0x04, 0xf1, 0x04, 0x57, 0x01, 0xf1, 0xb6,
109		0x58, 0x02, 0xf1, 0x0d, 0x5c, 0x1f, 0xf1, 0x19,
110		0x5d, 0x24, 0xf1, 0x1e, 0x64, 0x5e, 0xf1, 0x1c,
111		0xd2, 0x00, 0xf1, 0x00, 0xcb, 0x00, 0xf1, 0x01
112	}, (u8[]){
113		0xd3, 0x02, 0xd4, 0x10, 0xd5, 0x81, 0xd0, 0x02,
114		0xd1, 0x08, 0xd2, 0xe1
115	}
116};
117
118static s32 tbl_sat[] = {0x25, 0x1d, 0x15, 0x0d, 0x05, 0x4d, 0x55, 0x5d, 0x2d};
119static s32 tbl_bright[] = {0, 8, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70};
120static s32 tbl_backlight[] = {0x0e, 0x06, 0x02};
121
122static s32 tbl_cntr1[] = {
123	0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, 0xc0, 0xc8, 0xd0, 0xe0, 0xf0};
124static s32 tbl_cntr2[] = {
125	0x70, 0x68, 0x60, 0x58, 0x50, 0x48, 0x40, 0x38, 0x30, 0x20, 0x10};
126
127static u8 dat_wbalNL[] =
128	"\xf0\x00\xf1\x01\x05\x00\xf1\x06" "\x3b\x04\xf1\x2a\x47\x10\xf1\x10"
129	"\x9d\x3c\xf1\xae\xaf\x10\xf1\x00" "\xf0\x00\xf1\x02\x2f\x91\xf1\x20"
130	"\x9c\x91\xf1\x20\x37\x03\xf1\x00" "\x9d\xc5\xf1\x0f\xf0\x00\xf1\x00";
131
132static u8 dat_wbalLL[] =
133	"\xf0\x00\xf1\x01\x05\x00\xf1\x0c" "\x3b\x04\xf1\x2a\x47\x40\xf1\x40"
134	"\x9d\x20\xf1\xae\xaf\x10\xf1\x00" "\xf0\x00\xf1\x02\x2f\xd1\xf1\x00"
135	"\x9c\xd1\xf1\x00\x37\x03\xf1\x00" "\x9d\xc5\xf1\x3f\xf0\x00\xf1\x00";
136
137static u8 dat_wbalBL[] =
138	"\xf0\x00\xf1\x01\x05\x00\xf1\x06" "\x47\x10\xf1\x30\x9d\x3c\xf1\xae"
139	"\xaf\x10\xf1\x00\xf0\x00\xf1\x02" "\x2f\x91\xf1\x20\x9c\x91\xf1\x20"
140	"\x37\x03\xf1\x00\x9d\xc5\xf1\x2f" "\xf0\x00\xf1\x00";
141
142static u8 dat_hvflip1[] = {0xf0, 0x00, 0xf1, 0x00};
143
144static u8 dat_common00[] =
145	"\x00\x01\x07\x6a\x06\x63\x0d\x6a" "\xc0\x00\x10\x10\xc1\x03\xc2\x42"
146	"\xd8\x04\x58\x00\x04\x02";
147static u8 dat_common01[] =
148	"\x0d\x00\xf1\x0b\x0d\x00\xf1\x08" "\x35\x00\xf1\x22\x68\x00\xf1\x5d"
149	"\xf0\x00\xf1\x01\x06\x70\xf1\x0e" "\xf0\x00\xf1\x02\xdd\x18\xf1\xe0";
150static u8 dat_common02[] =
151	"\x05\x01\xf1\x84\x06\x00\xf1\x44" "\x07\x00\xf1\xbe\x08\x00\xf1\x1e"
152	"\x20\x01\xf1\x03\x21\x84\xf1\x00" "\x22\x0d\xf1\x0f\x24\x80\xf1\x00"
153	"\x34\x18\xf1\x2d\x35\x00\xf1\x22" "\x43\x83\xf1\x83\x59\x00\xf1\xff";
154static u8 dat_common03[] =
155	"\xf0\x00\xf1\x02\x39\x06\xf1\x8c" "\x3a\x06\xf1\x8c\x3b\x03\xf1\xda"
156	"\x3c\x05\xf1\x30\x57\x01\xf1\x0c" "\x58\x01\xf1\x42\x59\x01\xf1\x0c"
157	"\x5a\x01\xf1\x42\x5c\x13\xf1\x0e" "\x5d\x17\xf1\x12\x64\x1e\xf1\x1c";
158static u8 dat_common04[] =
159	"\xf0\x00\xf1\x02\x24\x5f\xf1\x20" "\x28\xea\xf1\x02\x5f\x41\xf1\x43";
160static u8 dat_common05[] =
161	"\x02\x00\xf1\xee\x03\x29\xf1\x1a" "\x04\x02\xf1\xa4\x09\x00\xf1\x68"
162	"\x0a\x00\xf1\x2a\x0b\x00\xf1\x04" "\x0c\x00\xf1\x93\x0d\x00\xf1\x82"
163	"\x0e\x00\xf1\x40\x0f\x00\xf1\x5f" "\x10\x00\xf1\x4e\x11\x00\xf1\x5b";
164static u8 dat_common06[] =
165	"\x15\x00\xf1\xc9\x16\x00\xf1\x5e" "\x17\x00\xf1\x9d\x18\x00\xf1\x06"
166	"\x19\x00\xf1\x89\x1a\x00\xf1\x12" "\x1b\x00\xf1\xa1\x1c\x00\xf1\xe4"
167	"\x1d\x00\xf1\x7a\x1e\x00\xf1\x64" "\xf6\x00\xf1\x5f";
168static u8 dat_common07[] =
169	"\xf0\x00\xf1\x01\x53\x09\xf1\x03" "\x54\x3d\xf1\x1c\x55\x99\xf1\x72"
170	"\x56\xc1\xf1\xb1\x57\xd8\xf1\xce" "\x58\xe0\xf1\x00\xdc\x0a\xf1\x03"
171	"\xdd\x45\xf1\x20\xde\xae\xf1\x82" "\xdf\xdc\xf1\xc9\xe0\xf6\xf1\xea"
172	"\xe1\xff\xf1\x00";
173static u8 dat_common08[] =
174	"\xf0\x00\xf1\x01\x80\x00\xf1\x06" "\x81\xf6\xf1\x08\x82\xfb\xf1\xf7"
175	"\x83\x00\xf1\xfe\xb6\x07\xf1\x03" "\xb7\x18\xf1\x0c\x84\xfb\xf1\x06"
176	"\x85\xfb\xf1\xf9\x86\x00\xf1\xff" "\xb8\x07\xf1\x04\xb9\x16\xf1\x0a";
177static u8 dat_common09[] =
178	"\x87\xfa\xf1\x05\x88\xfc\xf1\xf9" "\x89\x00\xf1\xff\xba\x06\xf1\x03"
179	"\xbb\x17\xf1\x09\x8a\xe8\xf1\x14" "\x8b\xf7\xf1\xf0\x8c\xfd\xf1\xfa"
180	"\x8d\x00\xf1\x00\xbc\x05\xf1\x01" "\xbd\x0c\xf1\x08\xbe\x00\xf1\x14";
181static u8 dat_common10[] =
182	"\x8e\xea\xf1\x13\x8f\xf7\xf1\xf2" "\x90\xfd\xf1\xfa\x91\x00\xf1\x00"
183	"\xbf\x05\xf1\x01\xc0\x0a\xf1\x08" "\xc1\x00\xf1\x0c\x92\xed\xf1\x0f"
184	"\x93\xf9\xf1\xf4\x94\xfe\xf1\xfb" "\x95\x00\xf1\x00\xc2\x04\xf1\x01"
185	"\xc3\x0a\xf1\x07\xc4\x00\xf1\x10";
186static u8 dat_common11[] =
187	"\xf0\x00\xf1\x01\x05\x00\xf1\x06" "\x25\x00\xf1\x55\x34\x10\xf1\x10"
188	"\x35\xf0\xf1\x10\x3a\x02\xf1\x03" "\x3b\x04\xf1\x2a\x9b\x43\xf1\x00"
189	"\xa4\x03\xf1\xc0\xa7\x02\xf1\x81";
190
191static int  mi1320_init_at_startup(struct gspca_dev *gspca_dev);
192static int  mi1320_configure_alt(struct gspca_dev *gspca_dev);
193static int  mi1320_init_pre_alt(struct gspca_dev *gspca_dev);
194static int  mi1320_init_post_alt(struct gspca_dev *gspca_dev);
195static void mi1320_post_unset_alt(struct gspca_dev *gspca_dev);
196static int  mi1320_sensor_settings(struct gspca_dev *gspca_dev);
197static int  mi1320_camera_settings(struct gspca_dev *gspca_dev);
198/*==========================================================================*/
199
200void mi1320_init_settings(struct gspca_dev *gspca_dev)
201{
202	struct sd *sd = (struct sd *) gspca_dev;
203
204	sd->vcur.backlight  =  0;
205	sd->vcur.brightness =  0;
206	sd->vcur.sharpness  =  6;
207	sd->vcur.contrast   = 10;
208	sd->vcur.gamma      = 20;
209	sd->vcur.hue        =  0;
210	sd->vcur.saturation =  6;
211	sd->vcur.whitebal   =  0;
212	sd->vcur.mirror     = 0;
213	sd->vcur.flip       = 0;
214	sd->vcur.AC50Hz     = 1;
215
216	sd->vmax.backlight  =  2;
217	sd->vmax.brightness =  8;
218	sd->vmax.sharpness  =  7;
219	sd->vmax.contrast   =  0; /* 10 but not working with this driver */
220	sd->vmax.gamma      = 40;
221	sd->vmax.hue        =  5 + 1;
222	sd->vmax.saturation =  8;
223	sd->vmax.whitebal   =  2;
224	sd->vmax.mirror     = 1;
225	sd->vmax.flip       = 1;
226	sd->vmax.AC50Hz     = 1;
227
228	sd->dev_camera_settings = mi1320_camera_settings;
229	sd->dev_init_at_startup = mi1320_init_at_startup;
230	sd->dev_configure_alt   = mi1320_configure_alt;
231	sd->dev_init_pre_alt    = mi1320_init_pre_alt;
232	sd->dev_post_unset_alt  = mi1320_post_unset_alt;
233}
234
235/*==========================================================================*/
236
237static void common(struct gspca_dev *gspca_dev)
238{
239	s32 n; /* reserved for FETCH functions */
240
241	ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 22, dat_common00);
242	ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x0000, 0, NULL);
243	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 32, dat_common01);
244	n = fetch_validx(gspca_dev, tbl_common, ARRAY_SIZE(tbl_common));
245	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, dat_common02);
246	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, dat_common03);
247	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 16, dat_common04);
248	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, dat_common05);
249	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 44, dat_common06);
250	keep_on_fetching_validx(gspca_dev, tbl_common,
251					ARRAY_SIZE(tbl_common), n);
252	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 52, dat_common07);
253	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, dat_common08);
254	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, dat_common09);
255	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 56, dat_common10);
256	keep_on_fetching_validx(gspca_dev, tbl_common,
257					ARRAY_SIZE(tbl_common), n);
258	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 40, dat_common11);
259	keep_on_fetching_validx(gspca_dev, tbl_common,
260					ARRAY_SIZE(tbl_common), n);
261}
262
263static int mi1320_init_at_startup(struct gspca_dev *gspca_dev)
264{
265	fetch_validx(gspca_dev, tbl_init_at_startup,
266				ARRAY_SIZE(tbl_init_at_startup));
267
268	common(gspca_dev);
269
270/*	ctrl_out(gspca_dev, 0x40, 11, 0x0000, 0x0000, 0, NULL); */
271
272	return 0;
273}
274
275static int mi1320_init_pre_alt(struct gspca_dev *gspca_dev)
276{
277	struct sd *sd = (struct sd *) gspca_dev;
278
279	sd->mirrorMask = 0;
280
281	sd->vold.backlight  = -1;
282	sd->vold.brightness = -1;
283	sd->vold.sharpness  = -1;
284	sd->vold.contrast   = -1;
285	sd->vold.saturation = -1;
286	sd->vold.gamma    = -1;
287	sd->vold.hue      = -1;
288	sd->vold.whitebal = -1;
289	sd->vold.mirror   = -1;
290	sd->vold.flip     = -1;
291	sd->vold.AC50Hz   = -1;
292
293	common(gspca_dev);
294
295	mi1320_sensor_settings(gspca_dev);
296
297	mi1320_init_post_alt(gspca_dev);
298
299	return 0;
300}
301
302static int mi1320_init_post_alt(struct gspca_dev *gspca_dev)
303{
304	mi1320_camera_settings(gspca_dev);
305
306	return 0;
307}
308
309static int mi1320_sensor_settings(struct gspca_dev *gspca_dev)
310{
311	s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
312
313	ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL);
314
315	fetch_validx(gspca_dev, tbl_sensor_settings_common,
316				ARRAY_SIZE(tbl_sensor_settings_common));
317
318	switch (reso) {
319	case IMAGE_1280:
320		fetch_validx(gspca_dev, tbl_sensor_settings_1280,
321					ARRAY_SIZE(tbl_sensor_settings_1280));
322		ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 64, tbl_1280[0]);
323		ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 40, tbl_1280[1]);
324		ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, tbl_1280[2]);
325		break;
326
327	case IMAGE_800:
328		fetch_validx(gspca_dev, tbl_sensor_settings_800,
329					ARRAY_SIZE(tbl_sensor_settings_800));
330		ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 64, tbl_800[0]);
331		ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 40, tbl_800[1]);
332		ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, tbl_800[2]);
333		break;
334
335	default:
336		fetch_validx(gspca_dev, tbl_sensor_settings_640,
337					ARRAY_SIZE(tbl_sensor_settings_640));
338		ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 60, tbl_640[0]);
339		ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 40, tbl_640[1]);
340		ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, tbl_640[2]);
341		break;
342	}
343	return 0;
344}
345
346static int mi1320_configure_alt(struct gspca_dev *gspca_dev)
347{
348	s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
349
350	switch (reso) {
351	case IMAGE_640:
352		gspca_dev->alt = 3 + 1;
353		break;
354
355	case IMAGE_800:
356	case IMAGE_1280:
357		gspca_dev->alt = 1 + 1;
358		break;
359	}
360	return 0;
361}
362
363static int mi1320_camera_settings(struct gspca_dev *gspca_dev)
364{
365	struct sd *sd = (struct sd *) gspca_dev;
366
367	s32 backlight = sd->vcur.backlight;
368	s32 bright = sd->vcur.brightness;
369	s32 sharp  = sd->vcur.sharpness;
370	s32 cntr   = sd->vcur.contrast;
371	s32 gam	   = sd->vcur.gamma;
372	s32 hue    = sd->vcur.hue;
373	s32 sat	   = sd->vcur.saturation;
374	s32 wbal   = sd->vcur.whitebal;
375	s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) > 0);
376	s32 flip   = (((sd->vcur.flip   > 0) ^ sd->mirrorMask) > 0);
377	s32 freq   = (sd->vcur.AC50Hz > 0);
378	s32 i;
379
380	if (freq != sd->vold.AC50Hz) {
381		sd->vold.AC50Hz = freq;
382
383		freq = 2 * (freq == 0);
384		ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL);
385		ctrl_out(gspca_dev, 0x40, 1, 0xba02, 0x00f1, 0, NULL);
386		ctrl_out(gspca_dev, 0x40, 1, 0xba00       , 0x005b, 0, NULL);
387		ctrl_out(gspca_dev, 0x40, 1, 0xba01 + freq, 0x00f1, 0, NULL);
388	}
389
390	if (wbal != sd->vold.whitebal) {
391		sd->vold.whitebal = wbal;
392		if (wbal < 0 || wbal > sd->vmax.whitebal)
393			wbal = 0;
394
395		for (i = 0; i < 2; i++) {
396			if (wbal == 0) { /* Normal light */
397				ctrl_out(gspca_dev, 0x40, 1,
398						0x0010, 0x0010, 0, NULL);
399				ctrl_out(gspca_dev, 0x40, 1,
400						0x0003, 0x00c1, 0, NULL);
401				ctrl_out(gspca_dev, 0x40, 1,
402						0x0042, 0x00c2, 0, NULL);
403				ctrl_out(gspca_dev, 0x40, 3,
404						0xba00, 0x0200, 48, dat_wbalNL);
405			}
406
407			if (wbal == 1) { /* Low light */
408				ctrl_out(gspca_dev, 0x40, 1,
409						0x0010, 0x0010, 0, NULL);
410				ctrl_out(gspca_dev, 0x40, 1,
411						0x0004, 0x00c1, 0, NULL);
412				ctrl_out(gspca_dev, 0x40, 1,
413						0x0043, 0x00c2, 0, NULL);
414				ctrl_out(gspca_dev, 0x40, 3,
415						0xba00, 0x0200, 48, dat_wbalLL);
416			}
417
418			if (wbal == 2) { /* Back light */
419				ctrl_out(gspca_dev, 0x40, 1,
420						0x0010, 0x0010, 0, NULL);
421				ctrl_out(gspca_dev, 0x40, 1,
422						0x0003, 0x00c1, 0, NULL);
423				ctrl_out(gspca_dev, 0x40, 1,
424						0x0042, 0x00c2, 0, NULL);
425				ctrl_out(gspca_dev, 0x40, 3,
426						0xba00, 0x0200, 44, dat_wbalBL);
427			}
428		}
429	}
430
431	if (bright != sd->vold.brightness) {
432		sd->vold.brightness = bright;
433		if (bright < 0 || bright > sd->vmax.brightness)
434			bright = 0;
435
436		bright = tbl_bright[bright];
437		ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL);
438		ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL);
439		ctrl_out(gspca_dev, 0x40, 1, 0xba00 + bright, 0x0034, 0, NULL);
440		ctrl_out(gspca_dev, 0x40, 1, 0xba00 + bright, 0x00f1, 0, NULL);
441	}
442
443	if (sat != sd->vold.saturation) {
444		sd->vold.saturation = sat;
445		if (sat < 0 || sat > sd->vmax.saturation)
446			sat = 0;
447
448		sat = tbl_sat[sat];
449		ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL);
450		ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL);
451		ctrl_out(gspca_dev, 0x40, 1, 0xba00      , 0x0025, 0, NULL);
452		ctrl_out(gspca_dev, 0x40, 1, 0xba00 + sat, 0x00f1, 0, NULL);
453	}
454
455	if (sharp != sd->vold.sharpness) {
456		sd->vold.sharpness = sharp;
457		if (sharp < 0 || sharp > sd->vmax.sharpness)
458			sharp = 0;
459
460		ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL);
461		ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL);
462		ctrl_out(gspca_dev, 0x40, 1, 0xba00        , 0x0005, 0, NULL);
463		ctrl_out(gspca_dev, 0x40, 1, 0xba00 + sharp, 0x00f1, 0, NULL);
464	}
465
466	if (hue != sd->vold.hue) {
467		/* 0=normal  1=NB  2="sepia"  3=negative  4=other  5=other2 */
468		if (hue < 0 || hue > sd->vmax.hue)
469			hue = 0;
470		if (hue == sd->vmax.hue)
471			sd->swapRB = 1;
472		else
473			sd->swapRB = 0;
474
475		ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL);
476		ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL);
477		ctrl_out(gspca_dev, 0x40, 1, 0xba70, 0x00e2, 0, NULL);
478		ctrl_out(gspca_dev, 0x40, 1, 0xba00 + hue * (hue < 6), 0x00f1,
479							0, NULL);
480	}
481
482	if (backlight != sd->vold.backlight) {
483		sd->vold.backlight = backlight;
484		if (backlight < 0 || backlight > sd->vmax.backlight)
485			backlight = 0;
486
487		backlight = tbl_backlight[backlight];
488		for (i = 0; i < 2; i++) {
489			ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL);
490			ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL);
491			ctrl_out(gspca_dev, 0x40, 1, 0xba74, 0x0006, 0, NULL);
492			ctrl_out(gspca_dev, 0x40, 1, 0xba80 + backlight, 0x00f1,
493								0, NULL);
494		}
495	}
496
497	if (hue != sd->vold.hue) {
498		sd->vold.hue = hue;
499
500		ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL);
501		ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL);
502		ctrl_out(gspca_dev, 0x40, 1, 0xba70, 0x00e2, 0, NULL);
503		ctrl_out(gspca_dev, 0x40, 1, 0xba00 + hue * (hue < 6), 0x00f1,
504							0, NULL);
505	}
506
507	if (mirror != sd->vold.mirror || flip != sd->vold.flip) {
508		u8 dat_hvflip2[4] = {0x20, 0x01, 0xf1, 0x00};
509		sd->vold.mirror = mirror;
510		sd->vold.flip = flip;
511
512		dat_hvflip2[3] = flip + 2 * mirror;
513		ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 4, dat_hvflip1);
514		ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 4, dat_hvflip2);
515	}
516
517	if (gam != sd->vold.gamma) {
518		sd->vold.gamma = gam;
519		if (gam < 0 || gam > sd->vmax.gamma)
520			gam = 0;
521
522		gam = 2 * gam;
523		ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL);
524		ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL);
525		ctrl_out(gspca_dev, 0x40, 1, 0xba04      , 0x003b, 0, NULL);
526		ctrl_out(gspca_dev, 0x40, 1, 0xba02 + gam, 0x00f1, 0, NULL);
527	}
528
529	if (cntr != sd->vold.contrast) {
530		sd->vold.contrast = cntr;
531		if (cntr < 0 || cntr > sd->vmax.contrast)
532			cntr = 0;
533
534		ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL);
535		ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL);
536		ctrl_out(gspca_dev, 0x40, 1, 0xba00 + tbl_cntr1[cntr], 0x0035,
537							0, NULL);
538		ctrl_out(gspca_dev, 0x40, 1, 0xba00 + tbl_cntr2[cntr], 0x00f1,
539							0, NULL);
540	}
541
542	return 0;
543}
544
545static void mi1320_post_unset_alt(struct gspca_dev *gspca_dev)
546{
547	ctrl_out(gspca_dev, 0x40, 5, 0x0000, 0x0000, 0, NULL);
548
549	fetch_validx(gspca_dev, tbl_post_unset_alt,
550				ARRAY_SIZE(tbl_post_unset_alt));
551}
552