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 
10 static 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 
23 static 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 
30 static struct validx tbl_sensor_settings_common[] = {
31 	{0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042, 0x00c2}, {0x0040, 0x0000},
32 	{0x006a, 0x0007}, {0x006a, 0x000d}, {0x0063, 0x0006},
33 };
34 static 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 };
38 static 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 };
42 static 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 };
47 static struct validx tbl_post_unset_alt[] = {
48 	{0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xbaa0, 0x0065}, {0xba00, 0x00f1},
49 	{0x0061, 0x0000}, {0x0068, 0x000d},
50 };
51 
52 static 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 
74 static 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 
96 static 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 
118 static s32 tbl_sat[] = {0x25, 0x1d, 0x15, 0x0d, 0x05, 0x4d, 0x55, 0x5d, 0x2d};
119 static s32 tbl_bright[] = {0, 8, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70};
120 static s32 tbl_backlight[] = {0x0e, 0x06, 0x02};
121 
122 static s32 tbl_cntr1[] = {
123 	0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, 0xc0, 0xc8, 0xd0, 0xe0, 0xf0};
124 static s32 tbl_cntr2[] = {
125 	0x70, 0x68, 0x60, 0x58, 0x50, 0x48, 0x40, 0x38, 0x30, 0x20, 0x10};
126 
127 static 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 
132 static 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 
137 static 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 
142 static u8 dat_hvflip1[] = {0xf0, 0x00, 0xf1, 0x00};
143 
144 static 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";
147 static 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";
150 static 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";
154 static 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";
158 static u8 dat_common04[] =
159 	"\xf0\x00\xf1\x02\x24\x5f\xf1\x20" "\x28\xea\xf1\x02\x5f\x41\xf1\x43";
160 static 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";
164 static 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";
168 static 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";
173 static 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";
177 static 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";
181 static 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";
186 static 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 
191 static int  mi1320_init_at_startup(struct gspca_dev *gspca_dev);
192 static int  mi1320_configure_alt(struct gspca_dev *gspca_dev);
193 static int  mi1320_init_pre_alt(struct gspca_dev *gspca_dev);
194 static int  mi1320_init_post_alt(struct gspca_dev *gspca_dev);
195 static void mi1320_post_unset_alt(struct gspca_dev *gspca_dev);
196 static int  mi1320_sensor_settings(struct gspca_dev *gspca_dev);
197 static int  mi1320_camera_settings(struct gspca_dev *gspca_dev);
198 /*==========================================================================*/
199 
200 void 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 
237 static 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 
263 static 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 
275 static 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 
302 static int mi1320_init_post_alt(struct gspca_dev *gspca_dev)
303 {
304 	mi1320_camera_settings(gspca_dev);
305 
306 	return 0;
307 }
308 
309 static 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 
346 static 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 
363 static 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 
545 static 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