162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * T613 subdriver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2010 Jean-Francois Moine (http://moinejf.free.fr) 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci *Notes: * t613 + tas5130A 862306a36Sopenharmony_ci * * Focus to light do not balance well as in win. 962306a36Sopenharmony_ci * Quality in win is not good, but its kinda better. 1062306a36Sopenharmony_ci * * Fix some "extraneous bytes", most of apps will show the image anyway 1162306a36Sopenharmony_ci * * Gamma table, is there, but its really doing something? 1262306a36Sopenharmony_ci * * 7~8 Fps, its ok, max on win its 10. 1362306a36Sopenharmony_ci * Costantino Leandro 1462306a36Sopenharmony_ci */ 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#define MODULE_NAME "t613" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include <linux/input.h> 2162306a36Sopenharmony_ci#include <linux/slab.h> 2262306a36Sopenharmony_ci#include "gspca.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ciMODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>"); 2562306a36Sopenharmony_ciMODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver"); 2662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistruct sd { 2962306a36Sopenharmony_ci struct gspca_dev gspca_dev; /* !! must be the first item */ 3062306a36Sopenharmony_ci struct v4l2_ctrl *freq; 3162306a36Sopenharmony_ci struct { /* awb / color gains control cluster */ 3262306a36Sopenharmony_ci struct v4l2_ctrl *awb; 3362306a36Sopenharmony_ci struct v4l2_ctrl *gain; 3462306a36Sopenharmony_ci struct v4l2_ctrl *red_balance; 3562306a36Sopenharmony_ci struct v4l2_ctrl *blue_balance; 3662306a36Sopenharmony_ci }; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci u8 sensor; 3962306a36Sopenharmony_ci u8 button_pressed; 4062306a36Sopenharmony_ci}; 4162306a36Sopenharmony_cienum sensors { 4262306a36Sopenharmony_ci SENSOR_OM6802, 4362306a36Sopenharmony_ci SENSOR_OTHER, 4462306a36Sopenharmony_ci SENSOR_TAS5130A, 4562306a36Sopenharmony_ci SENSOR_LT168G, /* must verify if this is the actual model */ 4662306a36Sopenharmony_ci}; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic const struct v4l2_pix_format vga_mode_t16[] = { 4962306a36Sopenharmony_ci {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, 5062306a36Sopenharmony_ci .bytesperline = 160, 5162306a36Sopenharmony_ci .sizeimage = 160 * 120 * 4 / 8 + 590, 5262306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_JPEG, 5362306a36Sopenharmony_ci .priv = 4}, 5462306a36Sopenharmony_ci#if 0 /* HDG: broken with my test cam, so lets disable it */ 5562306a36Sopenharmony_ci {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, 5662306a36Sopenharmony_ci .bytesperline = 176, 5762306a36Sopenharmony_ci .sizeimage = 176 * 144 * 3 / 8 + 590, 5862306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_JPEG, 5962306a36Sopenharmony_ci .priv = 3}, 6062306a36Sopenharmony_ci#endif 6162306a36Sopenharmony_ci {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, 6262306a36Sopenharmony_ci .bytesperline = 320, 6362306a36Sopenharmony_ci .sizeimage = 320 * 240 * 3 / 8 + 590, 6462306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_JPEG, 6562306a36Sopenharmony_ci .priv = 2}, 6662306a36Sopenharmony_ci#if 0 /* HDG: broken with my test cam, so lets disable it */ 6762306a36Sopenharmony_ci {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, 6862306a36Sopenharmony_ci .bytesperline = 352, 6962306a36Sopenharmony_ci .sizeimage = 352 * 288 * 3 / 8 + 590, 7062306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_JPEG, 7162306a36Sopenharmony_ci .priv = 1}, 7262306a36Sopenharmony_ci#endif 7362306a36Sopenharmony_ci {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, 7462306a36Sopenharmony_ci .bytesperline = 640, 7562306a36Sopenharmony_ci .sizeimage = 640 * 480 * 3 / 8 + 590, 7662306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_JPEG, 7762306a36Sopenharmony_ci .priv = 0}, 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/* sensor specific data */ 8162306a36Sopenharmony_cistruct additional_sensor_data { 8262306a36Sopenharmony_ci const u8 n3[6]; 8362306a36Sopenharmony_ci const u8 *n4, n4sz; 8462306a36Sopenharmony_ci const u8 reg80, reg8e; 8562306a36Sopenharmony_ci const u8 nset8[6]; 8662306a36Sopenharmony_ci const u8 data1[10]; 8762306a36Sopenharmony_ci const u8 data2[9]; 8862306a36Sopenharmony_ci const u8 data3[9]; 8962306a36Sopenharmony_ci const u8 data5[6]; 9062306a36Sopenharmony_ci const u8 stream[4]; 9162306a36Sopenharmony_ci}; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic const u8 n4_om6802[] = { 9462306a36Sopenharmony_ci 0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c, 9562306a36Sopenharmony_ci 0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68, 9662306a36Sopenharmony_ci 0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1, 9762306a36Sopenharmony_ci 0xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8, 9862306a36Sopenharmony_ci 0xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48, 9962306a36Sopenharmony_ci 0xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0, 10062306a36Sopenharmony_ci 0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68, 10162306a36Sopenharmony_ci 0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40, 10262306a36Sopenharmony_ci 0xac, 0x84, 0xad, 0x86, 0xaf, 0x46 10362306a36Sopenharmony_ci}; 10462306a36Sopenharmony_cistatic const u8 n4_other[] = { 10562306a36Sopenharmony_ci 0x66, 0x00, 0x7f, 0x00, 0x80, 0xac, 0x81, 0x69, 10662306a36Sopenharmony_ci 0x84, 0x40, 0x85, 0x70, 0x86, 0x20, 0x8a, 0x68, 10762306a36Sopenharmony_ci 0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xff, 0x8e, 0xb8, 10862306a36Sopenharmony_ci 0x8f, 0x28, 0xa2, 0x60, 0xa5, 0x40, 0xa8, 0xa8, 10962306a36Sopenharmony_ci 0xac, 0x84, 0xad, 0x84, 0xae, 0x24, 0xaf, 0x56, 11062306a36Sopenharmony_ci 0xb0, 0x68, 0xb1, 0x00, 0xb2, 0x88, 0xbb, 0xc5, 11162306a36Sopenharmony_ci 0xbc, 0x4a, 0xbe, 0x36, 0xc2, 0x88, 0xc5, 0xc0, 11262306a36Sopenharmony_ci 0xc6, 0xda, 0xe9, 0x26, 0xeb, 0x00 11362306a36Sopenharmony_ci}; 11462306a36Sopenharmony_cistatic const u8 n4_tas5130a[] = { 11562306a36Sopenharmony_ci 0x80, 0x3c, 0x81, 0x68, 0x83, 0xa0, 0x84, 0x20, 11662306a36Sopenharmony_ci 0x8a, 0x68, 0x8b, 0x58, 0x8c, 0x88, 0x8e, 0xb4, 11762306a36Sopenharmony_ci 0x8f, 0x24, 0xa1, 0xb1, 0xa2, 0x30, 0xa5, 0x10, 11862306a36Sopenharmony_ci 0xa6, 0x4a, 0xae, 0x03, 0xb1, 0x44, 0xb2, 0x08, 11962306a36Sopenharmony_ci 0xb7, 0x06, 0xb9, 0xe7, 0xbb, 0xc4, 0xbc, 0x4a, 12062306a36Sopenharmony_ci 0xbe, 0x36, 0xbf, 0xff, 0xc2, 0x88, 0xc5, 0xc8, 12162306a36Sopenharmony_ci 0xc6, 0xda 12262306a36Sopenharmony_ci}; 12362306a36Sopenharmony_cistatic const u8 n4_lt168g[] = { 12462306a36Sopenharmony_ci 0x66, 0x01, 0x7f, 0x00, 0x80, 0x7c, 0x81, 0x28, 12562306a36Sopenharmony_ci 0x83, 0x44, 0x84, 0x20, 0x86, 0x20, 0x8a, 0x70, 12662306a36Sopenharmony_ci 0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xa0, 0x8e, 0xb3, 12762306a36Sopenharmony_ci 0x8f, 0x24, 0xa1, 0xb0, 0xa2, 0x38, 0xa5, 0x20, 12862306a36Sopenharmony_ci 0xa6, 0x4a, 0xa8, 0xe8, 0xaf, 0x38, 0xb0, 0x68, 12962306a36Sopenharmony_ci 0xb1, 0x44, 0xb2, 0x88, 0xbb, 0x86, 0xbd, 0x40, 13062306a36Sopenharmony_ci 0xbe, 0x26, 0xc1, 0x05, 0xc2, 0x88, 0xc5, 0xc0, 13162306a36Sopenharmony_ci 0xda, 0x8e, 0xdb, 0xca, 0xdc, 0xa8, 0xdd, 0x8c, 13262306a36Sopenharmony_ci 0xde, 0x44, 0xdf, 0x0c, 0xe9, 0x80 13362306a36Sopenharmony_ci}; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic const struct additional_sensor_data sensor_data[] = { 13662306a36Sopenharmony_ci[SENSOR_OM6802] = { 13762306a36Sopenharmony_ci .n3 = 13862306a36Sopenharmony_ci {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04}, 13962306a36Sopenharmony_ci .n4 = n4_om6802, 14062306a36Sopenharmony_ci .n4sz = sizeof n4_om6802, 14162306a36Sopenharmony_ci .reg80 = 0x3c, 14262306a36Sopenharmony_ci .reg8e = 0x33, 14362306a36Sopenharmony_ci .nset8 = {0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00}, 14462306a36Sopenharmony_ci .data1 = 14562306a36Sopenharmony_ci {0xc2, 0x28, 0x0f, 0x22, 0xcd, 0x27, 0x2c, 0x06, 14662306a36Sopenharmony_ci 0xb3, 0xfc}, 14762306a36Sopenharmony_ci .data2 = 14862306a36Sopenharmony_ci {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff, 14962306a36Sopenharmony_ci 0xff}, 15062306a36Sopenharmony_ci .data3 = 15162306a36Sopenharmony_ci {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff, 15262306a36Sopenharmony_ci 0xff}, 15362306a36Sopenharmony_ci .data5 = /* this could be removed later */ 15462306a36Sopenharmony_ci {0x0c, 0x03, 0xab, 0x13, 0x81, 0x23}, 15562306a36Sopenharmony_ci .stream = 15662306a36Sopenharmony_ci {0x0b, 0x04, 0x0a, 0x78}, 15762306a36Sopenharmony_ci }, 15862306a36Sopenharmony_ci[SENSOR_OTHER] = { 15962306a36Sopenharmony_ci .n3 = 16062306a36Sopenharmony_ci {0x61, 0xc2, 0x65, 0x88, 0x60, 0x00}, 16162306a36Sopenharmony_ci .n4 = n4_other, 16262306a36Sopenharmony_ci .n4sz = sizeof n4_other, 16362306a36Sopenharmony_ci .reg80 = 0xac, 16462306a36Sopenharmony_ci .reg8e = 0xb8, 16562306a36Sopenharmony_ci .nset8 = {0xa8, 0xa8, 0xc6, 0xda, 0xc0, 0x00}, 16662306a36Sopenharmony_ci .data1 = 16762306a36Sopenharmony_ci {0xc1, 0x48, 0x04, 0x1b, 0xca, 0x2e, 0x33, 0x3a, 16862306a36Sopenharmony_ci 0xe8, 0xfc}, 16962306a36Sopenharmony_ci .data2 = 17062306a36Sopenharmony_ci {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96, 17162306a36Sopenharmony_ci 0xd9}, 17262306a36Sopenharmony_ci .data3 = 17362306a36Sopenharmony_ci {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96, 17462306a36Sopenharmony_ci 0xd9}, 17562306a36Sopenharmony_ci .data5 = 17662306a36Sopenharmony_ci {0x0c, 0x03, 0xab, 0x29, 0x81, 0x69}, 17762306a36Sopenharmony_ci .stream = 17862306a36Sopenharmony_ci {0x0b, 0x04, 0x0a, 0x00}, 17962306a36Sopenharmony_ci }, 18062306a36Sopenharmony_ci[SENSOR_TAS5130A] = { 18162306a36Sopenharmony_ci .n3 = 18262306a36Sopenharmony_ci {0x61, 0xc2, 0x65, 0x0d, 0x60, 0x08}, 18362306a36Sopenharmony_ci .n4 = n4_tas5130a, 18462306a36Sopenharmony_ci .n4sz = sizeof n4_tas5130a, 18562306a36Sopenharmony_ci .reg80 = 0x3c, 18662306a36Sopenharmony_ci .reg8e = 0xb4, 18762306a36Sopenharmony_ci .nset8 = {0xa8, 0xf0, 0xc6, 0xda, 0xc0, 0x00}, 18862306a36Sopenharmony_ci .data1 = 18962306a36Sopenharmony_ci {0xbb, 0x28, 0x10, 0x10, 0xbb, 0x28, 0x1e, 0x27, 19062306a36Sopenharmony_ci 0xc8, 0xfc}, 19162306a36Sopenharmony_ci .data2 = 19262306a36Sopenharmony_ci {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8, 19362306a36Sopenharmony_ci 0xe0}, 19462306a36Sopenharmony_ci .data3 = 19562306a36Sopenharmony_ci {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8, 19662306a36Sopenharmony_ci 0xe0}, 19762306a36Sopenharmony_ci .data5 = 19862306a36Sopenharmony_ci {0x0c, 0x03, 0xab, 0x10, 0x81, 0x20}, 19962306a36Sopenharmony_ci .stream = 20062306a36Sopenharmony_ci {0x0b, 0x04, 0x0a, 0x40}, 20162306a36Sopenharmony_ci }, 20262306a36Sopenharmony_ci[SENSOR_LT168G] = { 20362306a36Sopenharmony_ci .n3 = {0x61, 0xc2, 0x65, 0x68, 0x60, 0x00}, 20462306a36Sopenharmony_ci .n4 = n4_lt168g, 20562306a36Sopenharmony_ci .n4sz = sizeof n4_lt168g, 20662306a36Sopenharmony_ci .reg80 = 0x7c, 20762306a36Sopenharmony_ci .reg8e = 0xb3, 20862306a36Sopenharmony_ci .nset8 = {0xa8, 0xf0, 0xc6, 0xba, 0xc0, 0x00}, 20962306a36Sopenharmony_ci .data1 = {0xc0, 0x38, 0x08, 0x10, 0xc0, 0x30, 0x10, 0x40, 21062306a36Sopenharmony_ci 0xb0, 0xf4}, 21162306a36Sopenharmony_ci .data2 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6, 21262306a36Sopenharmony_ci 0xff}, 21362306a36Sopenharmony_ci .data3 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6, 21462306a36Sopenharmony_ci 0xff}, 21562306a36Sopenharmony_ci .data5 = {0x0c, 0x03, 0xab, 0x4b, 0x81, 0x2b}, 21662306a36Sopenharmony_ci .stream = {0x0b, 0x04, 0x0a, 0x28}, 21762306a36Sopenharmony_ci }, 21862306a36Sopenharmony_ci}; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci#define MAX_EFFECTS 7 22162306a36Sopenharmony_cistatic const u8 effects_table[MAX_EFFECTS][6] = { 22262306a36Sopenharmony_ci {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00}, /* Normal */ 22362306a36Sopenharmony_ci {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04}, /* Repujar */ 22462306a36Sopenharmony_ci {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x20}, /* Monochrome */ 22562306a36Sopenharmony_ci {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x80}, /* Sepia */ 22662306a36Sopenharmony_ci {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x02}, /* Croquis */ 22762306a36Sopenharmony_ci {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x10}, /* Sun Effect */ 22862306a36Sopenharmony_ci {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40}, /* Negative */ 22962306a36Sopenharmony_ci}; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci#define GAMMA_MAX (15) 23262306a36Sopenharmony_cistatic const u8 gamma_table[GAMMA_MAX+1][17] = { 23362306a36Sopenharmony_ci/* gamma table from cam1690.ini */ 23462306a36Sopenharmony_ci {0x00, 0x00, 0x01, 0x04, 0x08, 0x0e, 0x16, 0x21, /* 0 */ 23562306a36Sopenharmony_ci 0x2e, 0x3d, 0x50, 0x65, 0x7d, 0x99, 0xb8, 0xdb, 23662306a36Sopenharmony_ci 0xff}, 23762306a36Sopenharmony_ci {0x00, 0x01, 0x03, 0x08, 0x0e, 0x16, 0x21, 0x2d, /* 1 */ 23862306a36Sopenharmony_ci 0x3c, 0x4d, 0x60, 0x75, 0x8d, 0xa6, 0xc2, 0xe1, 23962306a36Sopenharmony_ci 0xff}, 24062306a36Sopenharmony_ci {0x00, 0x01, 0x05, 0x0b, 0x12, 0x1c, 0x28, 0x35, /* 2 */ 24162306a36Sopenharmony_ci 0x45, 0x56, 0x69, 0x7e, 0x95, 0xad, 0xc7, 0xe3, 24262306a36Sopenharmony_ci 0xff}, 24362306a36Sopenharmony_ci {0x00, 0x02, 0x07, 0x0f, 0x18, 0x24, 0x30, 0x3f, /* 3 */ 24462306a36Sopenharmony_ci 0x4f, 0x61, 0x73, 0x88, 0x9d, 0xb4, 0xcd, 0xe6, 24562306a36Sopenharmony_ci 0xff}, 24662306a36Sopenharmony_ci {0x00, 0x04, 0x0b, 0x15, 0x20, 0x2d, 0x3b, 0x4a, /* 4 */ 24762306a36Sopenharmony_ci 0x5b, 0x6c, 0x7f, 0x92, 0xa7, 0xbc, 0xd2, 0xe9, 24862306a36Sopenharmony_ci 0xff}, 24962306a36Sopenharmony_ci {0x00, 0x07, 0x11, 0x15, 0x20, 0x2d, 0x48, 0x58, /* 5 */ 25062306a36Sopenharmony_ci 0x68, 0x79, 0x8b, 0x9d, 0xb0, 0xc4, 0xd7, 0xec, 25162306a36Sopenharmony_ci 0xff}, 25262306a36Sopenharmony_ci {0x00, 0x0c, 0x1a, 0x29, 0x38, 0x47, 0x57, 0x67, /* 6 */ 25362306a36Sopenharmony_ci 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 25462306a36Sopenharmony_ci 0xff}, 25562306a36Sopenharmony_ci {0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, /* 7 */ 25662306a36Sopenharmony_ci 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 25762306a36Sopenharmony_ci 0xff}, 25862306a36Sopenharmony_ci {0x00, 0x15, 0x27, 0x38, 0x49, 0x59, 0x69, 0x79, /* 8 */ 25962306a36Sopenharmony_ci 0x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe2, 0xf0, 26062306a36Sopenharmony_ci 0xff}, 26162306a36Sopenharmony_ci {0x00, 0x1c, 0x30, 0x43, 0x54, 0x65, 0x75, 0x84, /* 9 */ 26262306a36Sopenharmony_ci 0x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd8, 0xe5, 0xf2, 26362306a36Sopenharmony_ci 0xff}, 26462306a36Sopenharmony_ci {0x00, 0x24, 0x3b, 0x4f, 0x60, 0x70, 0x80, 0x8e, /* 10 */ 26562306a36Sopenharmony_ci 0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xdc, 0xe8, 0xf3, 26662306a36Sopenharmony_ci 0xff}, 26762306a36Sopenharmony_ci {0x00, 0x2a, 0x3c, 0x5d, 0x6e, 0x7e, 0x8d, 0x9b, /* 11 */ 26862306a36Sopenharmony_ci 0xa8, 0xb4, 0xc0, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5, 26962306a36Sopenharmony_ci 0xff}, 27062306a36Sopenharmony_ci {0x00, 0x3f, 0x5a, 0x6e, 0x7f, 0x8e, 0x9c, 0xa8, /* 12 */ 27162306a36Sopenharmony_ci 0xb4, 0xbf, 0xc9, 0xd3, 0xdc, 0xe5, 0xee, 0xf6, 27262306a36Sopenharmony_ci 0xff}, 27362306a36Sopenharmony_ci {0x00, 0x54, 0x6f, 0x83, 0x93, 0xa0, 0xad, 0xb7, /* 13 */ 27462306a36Sopenharmony_ci 0xc2, 0xcb, 0xd4, 0xdc, 0xe4, 0xeb, 0xf2, 0xf9, 27562306a36Sopenharmony_ci 0xff}, 27662306a36Sopenharmony_ci {0x00, 0x6e, 0x88, 0x9a, 0xa8, 0xb3, 0xbd, 0xc6, /* 14 */ 27762306a36Sopenharmony_ci 0xcf, 0xd6, 0xdd, 0xe3, 0xe9, 0xef, 0xf4, 0xfa, 27862306a36Sopenharmony_ci 0xff}, 27962306a36Sopenharmony_ci {0x00, 0x93, 0xa8, 0xb7, 0xc1, 0xca, 0xd2, 0xd8, /* 15 */ 28062306a36Sopenharmony_ci 0xde, 0xe3, 0xe8, 0xed, 0xf1, 0xf5, 0xf8, 0xfc, 28162306a36Sopenharmony_ci 0xff} 28262306a36Sopenharmony_ci}; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic const u8 tas5130a_sensor_init[][8] = { 28562306a36Sopenharmony_ci {0x62, 0x08, 0x63, 0x70, 0x64, 0x1d, 0x60, 0x09}, 28662306a36Sopenharmony_ci {0x62, 0x20, 0x63, 0x01, 0x64, 0x02, 0x60, 0x09}, 28762306a36Sopenharmony_ci {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09}, 28862306a36Sopenharmony_ci}; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic u8 sensor_reset[] = {0x61, 0x68, 0x62, 0xff, 0x60, 0x07}; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci/* read 1 byte */ 29362306a36Sopenharmony_cistatic u8 reg_r(struct gspca_dev *gspca_dev, 29462306a36Sopenharmony_ci u16 index) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci usb_control_msg(gspca_dev->dev, 29762306a36Sopenharmony_ci usb_rcvctrlpipe(gspca_dev->dev, 0), 29862306a36Sopenharmony_ci 0, /* request */ 29962306a36Sopenharmony_ci USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 30062306a36Sopenharmony_ci 0, /* value */ 30162306a36Sopenharmony_ci index, 30262306a36Sopenharmony_ci gspca_dev->usb_buf, 1, 500); 30362306a36Sopenharmony_ci return gspca_dev->usb_buf[0]; 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic void reg_w(struct gspca_dev *gspca_dev, 30762306a36Sopenharmony_ci u16 index) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci usb_control_msg(gspca_dev->dev, 31062306a36Sopenharmony_ci usb_sndctrlpipe(gspca_dev->dev, 0), 31162306a36Sopenharmony_ci 0, 31262306a36Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 31362306a36Sopenharmony_ci 0, index, 31462306a36Sopenharmony_ci NULL, 0, 500); 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic void reg_w_buf(struct gspca_dev *gspca_dev, 31862306a36Sopenharmony_ci const u8 *buffer, u16 len) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci if (len <= USB_BUF_SZ) { 32162306a36Sopenharmony_ci memcpy(gspca_dev->usb_buf, buffer, len); 32262306a36Sopenharmony_ci usb_control_msg(gspca_dev->dev, 32362306a36Sopenharmony_ci usb_sndctrlpipe(gspca_dev->dev, 0), 32462306a36Sopenharmony_ci 0, 32562306a36Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 32662306a36Sopenharmony_ci 0x01, 0, 32762306a36Sopenharmony_ci gspca_dev->usb_buf, len, 500); 32862306a36Sopenharmony_ci } else { 32962306a36Sopenharmony_ci u8 *tmpbuf; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci tmpbuf = kmemdup(buffer, len, GFP_KERNEL); 33262306a36Sopenharmony_ci if (!tmpbuf) { 33362306a36Sopenharmony_ci pr_err("Out of memory\n"); 33462306a36Sopenharmony_ci return; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci usb_control_msg(gspca_dev->dev, 33762306a36Sopenharmony_ci usb_sndctrlpipe(gspca_dev->dev, 0), 33862306a36Sopenharmony_ci 0, 33962306a36Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 34062306a36Sopenharmony_ci 0x01, 0, 34162306a36Sopenharmony_ci tmpbuf, len, 500); 34262306a36Sopenharmony_ci kfree(tmpbuf); 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci/* write values to consecutive registers */ 34762306a36Sopenharmony_cistatic void reg_w_ixbuf(struct gspca_dev *gspca_dev, 34862306a36Sopenharmony_ci u8 reg, 34962306a36Sopenharmony_ci const u8 *buffer, u16 len) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci int i; 35262306a36Sopenharmony_ci u8 *p, *tmpbuf; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci if (len * 2 <= USB_BUF_SZ) { 35562306a36Sopenharmony_ci p = tmpbuf = gspca_dev->usb_buf; 35662306a36Sopenharmony_ci } else { 35762306a36Sopenharmony_ci p = tmpbuf = kmalloc_array(len, 2, GFP_KERNEL); 35862306a36Sopenharmony_ci if (!tmpbuf) { 35962306a36Sopenharmony_ci pr_err("Out of memory\n"); 36062306a36Sopenharmony_ci return; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci i = len; 36462306a36Sopenharmony_ci while (--i >= 0) { 36562306a36Sopenharmony_ci *p++ = reg++; 36662306a36Sopenharmony_ci *p++ = *buffer++; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci usb_control_msg(gspca_dev->dev, 36962306a36Sopenharmony_ci usb_sndctrlpipe(gspca_dev->dev, 0), 37062306a36Sopenharmony_ci 0, 37162306a36Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 37262306a36Sopenharmony_ci 0x01, 0, 37362306a36Sopenharmony_ci tmpbuf, len * 2, 500); 37462306a36Sopenharmony_ci if (len * 2 > USB_BUF_SZ) 37562306a36Sopenharmony_ci kfree(tmpbuf); 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_cistatic void om6802_sensor_init(struct gspca_dev *gspca_dev) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci int i; 38162306a36Sopenharmony_ci const u8 *p; 38262306a36Sopenharmony_ci u8 byte; 38362306a36Sopenharmony_ci u8 val[6] = {0x62, 0, 0x64, 0, 0x60, 0x05}; 38462306a36Sopenharmony_ci static const u8 sensor_init[] = { 38562306a36Sopenharmony_ci 0xdf, 0x6d, 38662306a36Sopenharmony_ci 0xdd, 0x18, 38762306a36Sopenharmony_ci 0x5a, 0xe0, 38862306a36Sopenharmony_ci 0x5c, 0x07, 38962306a36Sopenharmony_ci 0x5d, 0xb0, 39062306a36Sopenharmony_ci 0x5e, 0x1e, 39162306a36Sopenharmony_ci 0x60, 0x71, 39262306a36Sopenharmony_ci 0xef, 0x00, 39362306a36Sopenharmony_ci 0xe9, 0x00, 39462306a36Sopenharmony_ci 0xea, 0x00, 39562306a36Sopenharmony_ci 0x90, 0x24, 39662306a36Sopenharmony_ci 0x91, 0xb2, 39762306a36Sopenharmony_ci 0x82, 0x32, 39862306a36Sopenharmony_ci 0xfd, 0x41, 39962306a36Sopenharmony_ci 0x00 /* table end */ 40062306a36Sopenharmony_ci }; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset); 40362306a36Sopenharmony_ci msleep(100); 40462306a36Sopenharmony_ci i = 4; 40562306a36Sopenharmony_ci while (--i > 0) { 40662306a36Sopenharmony_ci byte = reg_r(gspca_dev, 0x0060); 40762306a36Sopenharmony_ci if (!(byte & 0x01)) 40862306a36Sopenharmony_ci break; 40962306a36Sopenharmony_ci msleep(100); 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci byte = reg_r(gspca_dev, 0x0063); 41262306a36Sopenharmony_ci if (byte != 0x17) { 41362306a36Sopenharmony_ci pr_err("Bad sensor reset %02x\n", byte); 41462306a36Sopenharmony_ci /* continue? */ 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci p = sensor_init; 41862306a36Sopenharmony_ci while (*p != 0) { 41962306a36Sopenharmony_ci val[1] = *p++; 42062306a36Sopenharmony_ci val[3] = *p++; 42162306a36Sopenharmony_ci if (*p == 0) 42262306a36Sopenharmony_ci reg_w(gspca_dev, 0x3c80); 42362306a36Sopenharmony_ci reg_w_buf(gspca_dev, val, sizeof val); 42462306a36Sopenharmony_ci i = 4; 42562306a36Sopenharmony_ci while (--i >= 0) { 42662306a36Sopenharmony_ci msleep(15); 42762306a36Sopenharmony_ci byte = reg_r(gspca_dev, 0x60); 42862306a36Sopenharmony_ci if (!(byte & 0x01)) 42962306a36Sopenharmony_ci break; 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci msleep(15); 43362306a36Sopenharmony_ci reg_w(gspca_dev, 0x3c80); 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci/* this function is called at probe time */ 43762306a36Sopenharmony_cistatic int sd_config(struct gspca_dev *gspca_dev, 43862306a36Sopenharmony_ci const struct usb_device_id *id) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci struct cam *cam = &gspca_dev->cam; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci cam->cam_mode = vga_mode_t16; 44362306a36Sopenharmony_ci cam->nmodes = ARRAY_SIZE(vga_mode_t16); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci return 0; 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic void setbrightness(struct gspca_dev *gspca_dev, s32 brightness) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci u8 set6[4] = { 0x8f, 0x24, 0xc3, 0x00 }; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (brightness < 7) { 45362306a36Sopenharmony_ci set6[1] = 0x26; 45462306a36Sopenharmony_ci set6[3] = 0x70 - brightness * 0x10; 45562306a36Sopenharmony_ci } else { 45662306a36Sopenharmony_ci set6[3] = 0x00 + ((brightness - 7) * 0x10); 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci reg_w_buf(gspca_dev, set6, sizeof set6); 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic void setcontrast(struct gspca_dev *gspca_dev, s32 contrast) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci u16 reg_to_write; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci if (contrast < 7) 46762306a36Sopenharmony_ci reg_to_write = 0x8ea9 - contrast * 0x200; 46862306a36Sopenharmony_ci else 46962306a36Sopenharmony_ci reg_to_write = 0x00a9 + (contrast - 7) * 0x200; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci reg_w(gspca_dev, reg_to_write); 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_cistatic void setcolors(struct gspca_dev *gspca_dev, s32 val) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci u16 reg_to_write; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci reg_to_write = 0x80bb + val * 0x100; /* was 0xc0 */ 47962306a36Sopenharmony_ci reg_w(gspca_dev, reg_to_write); 48062306a36Sopenharmony_ci} 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_cistatic void setgamma(struct gspca_dev *gspca_dev, s32 val) 48362306a36Sopenharmony_ci{ 48462306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_CONF, "Gamma: %d\n", val); 48562306a36Sopenharmony_ci reg_w_ixbuf(gspca_dev, 0x90, 48662306a36Sopenharmony_ci gamma_table[val], sizeof gamma_table[0]); 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cistatic void setawb_n_RGB(struct gspca_dev *gspca_dev) 49062306a36Sopenharmony_ci{ 49162306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 49262306a36Sopenharmony_ci u8 all_gain_reg[8] = { 49362306a36Sopenharmony_ci 0x87, 0x00, 0x88, 0x00, 0x89, 0x00, 0x80, 0x00 }; 49462306a36Sopenharmony_ci s32 red_gain, blue_gain, green_gain; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci green_gain = sd->gain->val; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci red_gain = green_gain + sd->red_balance->val; 49962306a36Sopenharmony_ci if (red_gain > 0x40) 50062306a36Sopenharmony_ci red_gain = 0x40; 50162306a36Sopenharmony_ci else if (red_gain < 0x10) 50262306a36Sopenharmony_ci red_gain = 0x10; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci blue_gain = green_gain + sd->blue_balance->val; 50562306a36Sopenharmony_ci if (blue_gain > 0x40) 50662306a36Sopenharmony_ci blue_gain = 0x40; 50762306a36Sopenharmony_ci else if (blue_gain < 0x10) 50862306a36Sopenharmony_ci blue_gain = 0x10; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci all_gain_reg[1] = red_gain; 51162306a36Sopenharmony_ci all_gain_reg[3] = blue_gain; 51262306a36Sopenharmony_ci all_gain_reg[5] = green_gain; 51362306a36Sopenharmony_ci all_gain_reg[7] = sensor_data[sd->sensor].reg80; 51462306a36Sopenharmony_ci if (!sd->awb->val) 51562306a36Sopenharmony_ci all_gain_reg[7] &= ~0x04; /* AWB off */ 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg); 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_cistatic void setsharpness(struct gspca_dev *gspca_dev, s32 val) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci u16 reg_to_write; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci reg_to_write = 0x0aa6 + 0x1000 * val; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci reg_w(gspca_dev, reg_to_write); 52762306a36Sopenharmony_ci} 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_cistatic void setfreq(struct gspca_dev *gspca_dev, s32 val) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 53262306a36Sopenharmony_ci u8 reg66; 53362306a36Sopenharmony_ci u8 freq[4] = { 0x66, 0x00, 0xa8, 0xe8 }; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci switch (sd->sensor) { 53662306a36Sopenharmony_ci case SENSOR_LT168G: 53762306a36Sopenharmony_ci if (val != 0) 53862306a36Sopenharmony_ci freq[3] = 0xa8; 53962306a36Sopenharmony_ci reg66 = 0x41; 54062306a36Sopenharmony_ci break; 54162306a36Sopenharmony_ci case SENSOR_OM6802: 54262306a36Sopenharmony_ci reg66 = 0xca; 54362306a36Sopenharmony_ci break; 54462306a36Sopenharmony_ci default: 54562306a36Sopenharmony_ci reg66 = 0x40; 54662306a36Sopenharmony_ci break; 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci switch (val) { 54962306a36Sopenharmony_ci case 0: /* no flicker */ 55062306a36Sopenharmony_ci freq[3] = 0xf0; 55162306a36Sopenharmony_ci break; 55262306a36Sopenharmony_ci case 2: /* 60Hz */ 55362306a36Sopenharmony_ci reg66 &= ~0x40; 55462306a36Sopenharmony_ci break; 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci freq[1] = reg66; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci reg_w_buf(gspca_dev, freq, sizeof freq); 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci/* this function is called at probe and resume time */ 56262306a36Sopenharmony_cistatic int sd_init(struct gspca_dev *gspca_dev) 56362306a36Sopenharmony_ci{ 56462306a36Sopenharmony_ci /* some of this registers are not really needed, because 56562306a36Sopenharmony_ci * they are overridden by setbrigthness, setcontrast, etc., 56662306a36Sopenharmony_ci * but won't hurt anyway, and can help someone with similar webcam 56762306a36Sopenharmony_ci * to see the initial parameters.*/ 56862306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 56962306a36Sopenharmony_ci const struct additional_sensor_data *sensor; 57062306a36Sopenharmony_ci int i; 57162306a36Sopenharmony_ci u16 sensor_id; 57262306a36Sopenharmony_ci u8 test_byte = 0; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci static const u8 read_indexs[] = 57562306a36Sopenharmony_ci { 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5, 57662306a36Sopenharmony_ci 0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00 }; 57762306a36Sopenharmony_ci static const u8 n1[] = 57862306a36Sopenharmony_ci {0x08, 0x03, 0x09, 0x03, 0x12, 0x04}; 57962306a36Sopenharmony_ci static const u8 n2[] = 58062306a36Sopenharmony_ci {0x08, 0x00}; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci sensor_id = (reg_r(gspca_dev, 0x06) << 8) 58362306a36Sopenharmony_ci | reg_r(gspca_dev, 0x07); 58462306a36Sopenharmony_ci switch (sensor_id & 0xff0f) { 58562306a36Sopenharmony_ci case 0x0801: 58662306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_PROBE, "sensor tas5130a\n"); 58762306a36Sopenharmony_ci sd->sensor = SENSOR_TAS5130A; 58862306a36Sopenharmony_ci break; 58962306a36Sopenharmony_ci case 0x0802: 59062306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_PROBE, "sensor lt168g\n"); 59162306a36Sopenharmony_ci sd->sensor = SENSOR_LT168G; 59262306a36Sopenharmony_ci break; 59362306a36Sopenharmony_ci case 0x0803: 59462306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_PROBE, "sensor 'other'\n"); 59562306a36Sopenharmony_ci sd->sensor = SENSOR_OTHER; 59662306a36Sopenharmony_ci break; 59762306a36Sopenharmony_ci case 0x0807: 59862306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_PROBE, "sensor om6802\n"); 59962306a36Sopenharmony_ci sd->sensor = SENSOR_OM6802; 60062306a36Sopenharmony_ci break; 60162306a36Sopenharmony_ci default: 60262306a36Sopenharmony_ci pr_err("unknown sensor %04x\n", sensor_id); 60362306a36Sopenharmony_ci return -EINVAL; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci if (sd->sensor == SENSOR_OM6802) { 60762306a36Sopenharmony_ci reg_w_buf(gspca_dev, n1, sizeof n1); 60862306a36Sopenharmony_ci i = 5; 60962306a36Sopenharmony_ci while (--i >= 0) { 61062306a36Sopenharmony_ci reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset); 61162306a36Sopenharmony_ci test_byte = reg_r(gspca_dev, 0x0063); 61262306a36Sopenharmony_ci msleep(100); 61362306a36Sopenharmony_ci if (test_byte == 0x17) 61462306a36Sopenharmony_ci break; /* OK */ 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci if (i < 0) { 61762306a36Sopenharmony_ci pr_err("Bad sensor reset %02x\n", test_byte); 61862306a36Sopenharmony_ci return -EIO; 61962306a36Sopenharmony_ci } 62062306a36Sopenharmony_ci reg_w_buf(gspca_dev, n2, sizeof n2); 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci i = 0; 62462306a36Sopenharmony_ci while (read_indexs[i] != 0x00) { 62562306a36Sopenharmony_ci test_byte = reg_r(gspca_dev, read_indexs[i]); 62662306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_STREAM, "Reg 0x%02x = 0x%02x\n", 62762306a36Sopenharmony_ci read_indexs[i], test_byte); 62862306a36Sopenharmony_ci i++; 62962306a36Sopenharmony_ci } 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci sensor = &sensor_data[sd->sensor]; 63262306a36Sopenharmony_ci reg_w_buf(gspca_dev, sensor->n3, sizeof sensor->n3); 63362306a36Sopenharmony_ci reg_w_buf(gspca_dev, sensor->n4, sensor->n4sz); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci if (sd->sensor == SENSOR_LT168G) { 63662306a36Sopenharmony_ci test_byte = reg_r(gspca_dev, 0x80); 63762306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_STREAM, "Reg 0x%02x = 0x%02x\n", 0x80, 63862306a36Sopenharmony_ci test_byte); 63962306a36Sopenharmony_ci reg_w(gspca_dev, 0x6c80); 64062306a36Sopenharmony_ci } 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1); 64362306a36Sopenharmony_ci reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2); 64462306a36Sopenharmony_ci reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80); 64762306a36Sopenharmony_ci reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80); 64862306a36Sopenharmony_ci reg_w(gspca_dev, (sensor->reg8e << 8) + 0x8e); 64962306a36Sopenharmony_ci reg_w(gspca_dev, (0x20 << 8) + 0x87); 65062306a36Sopenharmony_ci reg_w(gspca_dev, (0x20 << 8) + 0x88); 65162306a36Sopenharmony_ci reg_w(gspca_dev, (0x20 << 8) + 0x89); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci reg_w_buf(gspca_dev, sensor->data5, sizeof sensor->data5); 65462306a36Sopenharmony_ci reg_w_buf(gspca_dev, sensor->nset8, sizeof sensor->nset8); 65562306a36Sopenharmony_ci reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci if (sd->sensor == SENSOR_LT168G) { 65862306a36Sopenharmony_ci test_byte = reg_r(gspca_dev, 0x80); 65962306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_STREAM, "Reg 0x%02x = 0x%02x\n", 0x80, 66062306a36Sopenharmony_ci test_byte); 66162306a36Sopenharmony_ci reg_w(gspca_dev, 0x6c80); 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1); 66562306a36Sopenharmony_ci reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2); 66662306a36Sopenharmony_ci reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci return 0; 66962306a36Sopenharmony_ci} 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_cistatic void setmirror(struct gspca_dev *gspca_dev, s32 val) 67262306a36Sopenharmony_ci{ 67362306a36Sopenharmony_ci u8 hflipcmd[8] = 67462306a36Sopenharmony_ci {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09}; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci if (val) 67762306a36Sopenharmony_ci hflipcmd[3] = 0x01; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci reg_w_buf(gspca_dev, hflipcmd, sizeof hflipcmd); 68062306a36Sopenharmony_ci} 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_cistatic void seteffect(struct gspca_dev *gspca_dev, s32 val) 68362306a36Sopenharmony_ci{ 68462306a36Sopenharmony_ci int idx = 0; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci switch (val) { 68762306a36Sopenharmony_ci case V4L2_COLORFX_NONE: 68862306a36Sopenharmony_ci break; 68962306a36Sopenharmony_ci case V4L2_COLORFX_BW: 69062306a36Sopenharmony_ci idx = 2; 69162306a36Sopenharmony_ci break; 69262306a36Sopenharmony_ci case V4L2_COLORFX_SEPIA: 69362306a36Sopenharmony_ci idx = 3; 69462306a36Sopenharmony_ci break; 69562306a36Sopenharmony_ci case V4L2_COLORFX_SKETCH: 69662306a36Sopenharmony_ci idx = 4; 69762306a36Sopenharmony_ci break; 69862306a36Sopenharmony_ci case V4L2_COLORFX_NEGATIVE: 69962306a36Sopenharmony_ci idx = 6; 70062306a36Sopenharmony_ci break; 70162306a36Sopenharmony_ci default: 70262306a36Sopenharmony_ci break; 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci reg_w_buf(gspca_dev, effects_table[idx], 70662306a36Sopenharmony_ci sizeof effects_table[0]); 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci if (val == V4L2_COLORFX_SKETCH) 70962306a36Sopenharmony_ci reg_w(gspca_dev, 0x4aa6); 71062306a36Sopenharmony_ci else 71162306a36Sopenharmony_ci reg_w(gspca_dev, 0xfaa6); 71262306a36Sopenharmony_ci} 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci/* Is this really needed? 71562306a36Sopenharmony_ci * i added some module parameters for test with some users */ 71662306a36Sopenharmony_cistatic void poll_sensor(struct gspca_dev *gspca_dev) 71762306a36Sopenharmony_ci{ 71862306a36Sopenharmony_ci static const u8 poll1[] = 71962306a36Sopenharmony_ci {0x67, 0x05, 0x68, 0x81, 0x69, 0x80, 0x6a, 0x82, 72062306a36Sopenharmony_ci 0x6b, 0x68, 0x6c, 0x69, 0x72, 0xd9, 0x73, 0x34, 72162306a36Sopenharmony_ci 0x74, 0x32, 0x75, 0x92, 0x76, 0x00, 0x09, 0x01, 72262306a36Sopenharmony_ci 0x60, 0x14}; 72362306a36Sopenharmony_ci static const u8 poll2[] = 72462306a36Sopenharmony_ci {0x67, 0x02, 0x68, 0x71, 0x69, 0x72, 0x72, 0xa9, 72562306a36Sopenharmony_ci 0x73, 0x02, 0x73, 0x02, 0x60, 0x14}; 72662306a36Sopenharmony_ci static const u8 noise03[] = /* (some differences / ms-drv) */ 72762306a36Sopenharmony_ci {0xa6, 0x0a, 0xea, 0xcf, 0xbe, 0x26, 0xb1, 0x5f, 72862306a36Sopenharmony_ci 0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c, 72962306a36Sopenharmony_ci 0xc2, 0x80, 0xc3, 0x10}; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_STREAM, "[Sensor requires polling]\n"); 73262306a36Sopenharmony_ci reg_w_buf(gspca_dev, poll1, sizeof poll1); 73362306a36Sopenharmony_ci reg_w_buf(gspca_dev, poll2, sizeof poll2); 73462306a36Sopenharmony_ci reg_w_buf(gspca_dev, noise03, sizeof noise03); 73562306a36Sopenharmony_ci} 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_cistatic int sd_start(struct gspca_dev *gspca_dev) 73862306a36Sopenharmony_ci{ 73962306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 74062306a36Sopenharmony_ci const struct additional_sensor_data *sensor; 74162306a36Sopenharmony_ci int i, mode; 74262306a36Sopenharmony_ci u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 }; 74362306a36Sopenharmony_ci static const u8 t3[] = 74462306a36Sopenharmony_ci { 0x07, 0x00, 0x88, 0x02, 0x06, 0x00, 0xe7, 0x01 }; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; 74762306a36Sopenharmony_ci switch (mode) { 74862306a36Sopenharmony_ci case 0: /* 640x480 (0x00) */ 74962306a36Sopenharmony_ci break; 75062306a36Sopenharmony_ci case 1: /* 352x288 */ 75162306a36Sopenharmony_ci t2[1] = 0x40; 75262306a36Sopenharmony_ci break; 75362306a36Sopenharmony_ci case 2: /* 320x240 */ 75462306a36Sopenharmony_ci t2[1] = 0x10; 75562306a36Sopenharmony_ci break; 75662306a36Sopenharmony_ci case 3: /* 176x144 */ 75762306a36Sopenharmony_ci t2[1] = 0x50; 75862306a36Sopenharmony_ci break; 75962306a36Sopenharmony_ci default: 76062306a36Sopenharmony_ci/* case 4: * 160x120 */ 76162306a36Sopenharmony_ci t2[1] = 0x20; 76262306a36Sopenharmony_ci break; 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci switch (sd->sensor) { 76662306a36Sopenharmony_ci case SENSOR_OM6802: 76762306a36Sopenharmony_ci om6802_sensor_init(gspca_dev); 76862306a36Sopenharmony_ci break; 76962306a36Sopenharmony_ci case SENSOR_TAS5130A: 77062306a36Sopenharmony_ci i = 0; 77162306a36Sopenharmony_ci for (;;) { 77262306a36Sopenharmony_ci reg_w_buf(gspca_dev, tas5130a_sensor_init[i], 77362306a36Sopenharmony_ci sizeof tas5130a_sensor_init[0]); 77462306a36Sopenharmony_ci if (i >= ARRAY_SIZE(tas5130a_sensor_init) - 1) 77562306a36Sopenharmony_ci break; 77662306a36Sopenharmony_ci i++; 77762306a36Sopenharmony_ci } 77862306a36Sopenharmony_ci reg_w(gspca_dev, 0x3c80); 77962306a36Sopenharmony_ci /* just in case and to keep sync with logs (for mine) */ 78062306a36Sopenharmony_ci reg_w_buf(gspca_dev, tas5130a_sensor_init[i], 78162306a36Sopenharmony_ci sizeof tas5130a_sensor_init[0]); 78262306a36Sopenharmony_ci reg_w(gspca_dev, 0x3c80); 78362306a36Sopenharmony_ci break; 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci sensor = &sensor_data[sd->sensor]; 78662306a36Sopenharmony_ci setfreq(gspca_dev, v4l2_ctrl_g_ctrl(sd->freq)); 78762306a36Sopenharmony_ci reg_r(gspca_dev, 0x0012); 78862306a36Sopenharmony_ci reg_w_buf(gspca_dev, t2, sizeof t2); 78962306a36Sopenharmony_ci reg_w_ixbuf(gspca_dev, 0xb3, t3, sizeof t3); 79062306a36Sopenharmony_ci reg_w(gspca_dev, 0x0013); 79162306a36Sopenharmony_ci msleep(15); 79262306a36Sopenharmony_ci reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream); 79362306a36Sopenharmony_ci reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci if (sd->sensor == SENSOR_OM6802) 79662306a36Sopenharmony_ci poll_sensor(gspca_dev); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci return 0; 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_cistatic void sd_stopN(struct gspca_dev *gspca_dev) 80262306a36Sopenharmony_ci{ 80362306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream, 80662306a36Sopenharmony_ci sizeof sensor_data[sd->sensor].stream); 80762306a36Sopenharmony_ci reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream, 80862306a36Sopenharmony_ci sizeof sensor_data[sd->sensor].stream); 80962306a36Sopenharmony_ci if (sd->sensor == SENSOR_OM6802) { 81062306a36Sopenharmony_ci msleep(20); 81162306a36Sopenharmony_ci reg_w(gspca_dev, 0x0309); 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_INPUT) 81462306a36Sopenharmony_ci /* If the last button state is pressed, release it now! */ 81562306a36Sopenharmony_ci if (sd->button_pressed) { 81662306a36Sopenharmony_ci input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); 81762306a36Sopenharmony_ci input_sync(gspca_dev->input_dev); 81862306a36Sopenharmony_ci sd->button_pressed = 0; 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci#endif 82162306a36Sopenharmony_ci} 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_cistatic void sd_pkt_scan(struct gspca_dev *gspca_dev, 82462306a36Sopenharmony_ci u8 *data, /* isoc packet */ 82562306a36Sopenharmony_ci int len) /* iso packet length */ 82662306a36Sopenharmony_ci{ 82762306a36Sopenharmony_ci struct sd *sd __maybe_unused = (struct sd *) gspca_dev; 82862306a36Sopenharmony_ci int pkt_type; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci if (data[0] == 0x5a) { 83162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_INPUT) 83262306a36Sopenharmony_ci if (len > 20) { 83362306a36Sopenharmony_ci u8 state = (data[20] & 0x80) ? 1 : 0; 83462306a36Sopenharmony_ci if (sd->button_pressed != state) { 83562306a36Sopenharmony_ci input_report_key(gspca_dev->input_dev, 83662306a36Sopenharmony_ci KEY_CAMERA, state); 83762306a36Sopenharmony_ci input_sync(gspca_dev->input_dev); 83862306a36Sopenharmony_ci sd->button_pressed = state; 83962306a36Sopenharmony_ci } 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci#endif 84262306a36Sopenharmony_ci /* Control Packet, after this came the header again, 84362306a36Sopenharmony_ci * but extra bytes came in the packet before this, 84462306a36Sopenharmony_ci * sometimes an EOF arrives, sometimes not... */ 84562306a36Sopenharmony_ci return; 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci data += 2; 84862306a36Sopenharmony_ci len -= 2; 84962306a36Sopenharmony_ci if (data[0] == 0xff && data[1] == 0xd8) 85062306a36Sopenharmony_ci pkt_type = FIRST_PACKET; 85162306a36Sopenharmony_ci else if (data[len - 2] == 0xff && data[len - 1] == 0xd9) 85262306a36Sopenharmony_ci pkt_type = LAST_PACKET; 85362306a36Sopenharmony_ci else 85462306a36Sopenharmony_ci pkt_type = INTER_PACKET; 85562306a36Sopenharmony_ci gspca_frame_add(gspca_dev, pkt_type, data, len); 85662306a36Sopenharmony_ci} 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_cistatic int sd_g_volatile_ctrl(struct v4l2_ctrl *ctrl) 85962306a36Sopenharmony_ci{ 86062306a36Sopenharmony_ci struct gspca_dev *gspca_dev = 86162306a36Sopenharmony_ci container_of(ctrl->handler, struct gspca_dev, ctrl_handler); 86262306a36Sopenharmony_ci struct sd *sd = (struct sd *)gspca_dev; 86362306a36Sopenharmony_ci s32 red_gain, blue_gain, green_gain; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci gspca_dev->usb_err = 0; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci switch (ctrl->id) { 86862306a36Sopenharmony_ci case V4L2_CID_AUTO_WHITE_BALANCE: 86962306a36Sopenharmony_ci red_gain = reg_r(gspca_dev, 0x0087); 87062306a36Sopenharmony_ci if (red_gain > 0x40) 87162306a36Sopenharmony_ci red_gain = 0x40; 87262306a36Sopenharmony_ci else if (red_gain < 0x10) 87362306a36Sopenharmony_ci red_gain = 0x10; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci blue_gain = reg_r(gspca_dev, 0x0088); 87662306a36Sopenharmony_ci if (blue_gain > 0x40) 87762306a36Sopenharmony_ci blue_gain = 0x40; 87862306a36Sopenharmony_ci else if (blue_gain < 0x10) 87962306a36Sopenharmony_ci blue_gain = 0x10; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci green_gain = reg_r(gspca_dev, 0x0089); 88262306a36Sopenharmony_ci if (green_gain > 0x40) 88362306a36Sopenharmony_ci green_gain = 0x40; 88462306a36Sopenharmony_ci else if (green_gain < 0x10) 88562306a36Sopenharmony_ci green_gain = 0x10; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci sd->gain->val = green_gain; 88862306a36Sopenharmony_ci sd->red_balance->val = red_gain - green_gain; 88962306a36Sopenharmony_ci sd->blue_balance->val = blue_gain - green_gain; 89062306a36Sopenharmony_ci break; 89162306a36Sopenharmony_ci } 89262306a36Sopenharmony_ci return 0; 89362306a36Sopenharmony_ci} 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_cistatic int sd_s_ctrl(struct v4l2_ctrl *ctrl) 89662306a36Sopenharmony_ci{ 89762306a36Sopenharmony_ci struct gspca_dev *gspca_dev = 89862306a36Sopenharmony_ci container_of(ctrl->handler, struct gspca_dev, ctrl_handler); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci gspca_dev->usb_err = 0; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci if (!gspca_dev->streaming) 90362306a36Sopenharmony_ci return 0; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci switch (ctrl->id) { 90662306a36Sopenharmony_ci case V4L2_CID_BRIGHTNESS: 90762306a36Sopenharmony_ci setbrightness(gspca_dev, ctrl->val); 90862306a36Sopenharmony_ci break; 90962306a36Sopenharmony_ci case V4L2_CID_CONTRAST: 91062306a36Sopenharmony_ci setcontrast(gspca_dev, ctrl->val); 91162306a36Sopenharmony_ci break; 91262306a36Sopenharmony_ci case V4L2_CID_SATURATION: 91362306a36Sopenharmony_ci setcolors(gspca_dev, ctrl->val); 91462306a36Sopenharmony_ci break; 91562306a36Sopenharmony_ci case V4L2_CID_GAMMA: 91662306a36Sopenharmony_ci setgamma(gspca_dev, ctrl->val); 91762306a36Sopenharmony_ci break; 91862306a36Sopenharmony_ci case V4L2_CID_HFLIP: 91962306a36Sopenharmony_ci setmirror(gspca_dev, ctrl->val); 92062306a36Sopenharmony_ci break; 92162306a36Sopenharmony_ci case V4L2_CID_SHARPNESS: 92262306a36Sopenharmony_ci setsharpness(gspca_dev, ctrl->val); 92362306a36Sopenharmony_ci break; 92462306a36Sopenharmony_ci case V4L2_CID_POWER_LINE_FREQUENCY: 92562306a36Sopenharmony_ci setfreq(gspca_dev, ctrl->val); 92662306a36Sopenharmony_ci break; 92762306a36Sopenharmony_ci case V4L2_CID_BACKLIGHT_COMPENSATION: 92862306a36Sopenharmony_ci reg_w(gspca_dev, ctrl->val ? 0xf48e : 0xb48e); 92962306a36Sopenharmony_ci break; 93062306a36Sopenharmony_ci case V4L2_CID_AUTO_WHITE_BALANCE: 93162306a36Sopenharmony_ci setawb_n_RGB(gspca_dev); 93262306a36Sopenharmony_ci break; 93362306a36Sopenharmony_ci case V4L2_CID_COLORFX: 93462306a36Sopenharmony_ci seteffect(gspca_dev, ctrl->val); 93562306a36Sopenharmony_ci break; 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci return gspca_dev->usb_err; 93862306a36Sopenharmony_ci} 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_cistatic const struct v4l2_ctrl_ops sd_ctrl_ops = { 94162306a36Sopenharmony_ci .g_volatile_ctrl = sd_g_volatile_ctrl, 94262306a36Sopenharmony_ci .s_ctrl = sd_s_ctrl, 94362306a36Sopenharmony_ci}; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_cistatic int sd_init_controls(struct gspca_dev *gspca_dev) 94662306a36Sopenharmony_ci{ 94762306a36Sopenharmony_ci struct sd *sd = (struct sd *)gspca_dev; 94862306a36Sopenharmony_ci struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci gspca_dev->vdev.ctrl_handler = hdl; 95162306a36Sopenharmony_ci v4l2_ctrl_handler_init(hdl, 12); 95262306a36Sopenharmony_ci v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 95362306a36Sopenharmony_ci V4L2_CID_BRIGHTNESS, 0, 14, 1, 8); 95462306a36Sopenharmony_ci v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 95562306a36Sopenharmony_ci V4L2_CID_CONTRAST, 0, 0x0d, 1, 7); 95662306a36Sopenharmony_ci v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 95762306a36Sopenharmony_ci V4L2_CID_SATURATION, 0, 0xf, 1, 5); 95862306a36Sopenharmony_ci v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 95962306a36Sopenharmony_ci V4L2_CID_GAMMA, 0, GAMMA_MAX, 1, 10); 96062306a36Sopenharmony_ci /* Activate lowlight, some apps don't bring up the 96162306a36Sopenharmony_ci backlight_compensation control) */ 96262306a36Sopenharmony_ci v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 96362306a36Sopenharmony_ci V4L2_CID_BACKLIGHT_COMPENSATION, 0, 1, 1, 1); 96462306a36Sopenharmony_ci if (sd->sensor == SENSOR_TAS5130A) 96562306a36Sopenharmony_ci v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 96662306a36Sopenharmony_ci V4L2_CID_HFLIP, 0, 1, 1, 0); 96762306a36Sopenharmony_ci sd->awb = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 96862306a36Sopenharmony_ci V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); 96962306a36Sopenharmony_ci sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 97062306a36Sopenharmony_ci V4L2_CID_GAIN, 0x10, 0x40, 1, 0x20); 97162306a36Sopenharmony_ci sd->blue_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 97262306a36Sopenharmony_ci V4L2_CID_BLUE_BALANCE, -0x30, 0x30, 1, 0); 97362306a36Sopenharmony_ci sd->red_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 97462306a36Sopenharmony_ci V4L2_CID_RED_BALANCE, -0x30, 0x30, 1, 0); 97562306a36Sopenharmony_ci v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 97662306a36Sopenharmony_ci V4L2_CID_SHARPNESS, 0, 15, 1, 6); 97762306a36Sopenharmony_ci v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops, 97862306a36Sopenharmony_ci V4L2_CID_COLORFX, V4L2_COLORFX_SKETCH, 97962306a36Sopenharmony_ci ~((1 << V4L2_COLORFX_NONE) | 98062306a36Sopenharmony_ci (1 << V4L2_COLORFX_BW) | 98162306a36Sopenharmony_ci (1 << V4L2_COLORFX_SEPIA) | 98262306a36Sopenharmony_ci (1 << V4L2_COLORFX_SKETCH) | 98362306a36Sopenharmony_ci (1 << V4L2_COLORFX_NEGATIVE)), 98462306a36Sopenharmony_ci V4L2_COLORFX_NONE); 98562306a36Sopenharmony_ci sd->freq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops, 98662306a36Sopenharmony_ci V4L2_CID_POWER_LINE_FREQUENCY, 98762306a36Sopenharmony_ci V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 1, 98862306a36Sopenharmony_ci V4L2_CID_POWER_LINE_FREQUENCY_50HZ); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci if (hdl->error) { 99162306a36Sopenharmony_ci pr_err("Could not initialize controls\n"); 99262306a36Sopenharmony_ci return hdl->error; 99362306a36Sopenharmony_ci } 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci v4l2_ctrl_auto_cluster(4, &sd->awb, 0, true); 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci return 0; 99862306a36Sopenharmony_ci} 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci/* sub-driver description */ 100162306a36Sopenharmony_cistatic const struct sd_desc sd_desc = { 100262306a36Sopenharmony_ci .name = MODULE_NAME, 100362306a36Sopenharmony_ci .config = sd_config, 100462306a36Sopenharmony_ci .init = sd_init, 100562306a36Sopenharmony_ci .init_controls = sd_init_controls, 100662306a36Sopenharmony_ci .start = sd_start, 100762306a36Sopenharmony_ci .stopN = sd_stopN, 100862306a36Sopenharmony_ci .pkt_scan = sd_pkt_scan, 100962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_INPUT) 101062306a36Sopenharmony_ci .other_input = 1, 101162306a36Sopenharmony_ci#endif 101262306a36Sopenharmony_ci}; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci/* -- module initialisation -- */ 101562306a36Sopenharmony_cistatic const struct usb_device_id device_table[] = { 101662306a36Sopenharmony_ci {USB_DEVICE(0x17a1, 0x0128)}, 101762306a36Sopenharmony_ci {} 101862306a36Sopenharmony_ci}; 101962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, device_table); 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci/* -- device connect -- */ 102262306a36Sopenharmony_cistatic int sd_probe(struct usb_interface *intf, 102362306a36Sopenharmony_ci const struct usb_device_id *id) 102462306a36Sopenharmony_ci{ 102562306a36Sopenharmony_ci return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), 102662306a36Sopenharmony_ci THIS_MODULE); 102762306a36Sopenharmony_ci} 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_cistatic struct usb_driver sd_driver = { 103062306a36Sopenharmony_ci .name = MODULE_NAME, 103162306a36Sopenharmony_ci .id_table = device_table, 103262306a36Sopenharmony_ci .probe = sd_probe, 103362306a36Sopenharmony_ci .disconnect = gspca_disconnect, 103462306a36Sopenharmony_ci#ifdef CONFIG_PM 103562306a36Sopenharmony_ci .suspend = gspca_suspend, 103662306a36Sopenharmony_ci .resume = gspca_resume, 103762306a36Sopenharmony_ci .reset_resume = gspca_resume, 103862306a36Sopenharmony_ci#endif 103962306a36Sopenharmony_ci}; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_cimodule_usb_driver(sd_driver); 1042