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