162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *		sonix sn9c102 (bayer) library
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2009-2011 Jean-François Moine <http://moinejf.free.fr>
662306a36Sopenharmony_ci * Copyright (C) 2003 2004 Michel Xhaard mxhaard@magic.fr
762306a36Sopenharmony_ci * Add Pas106 Stefano Mozzi (C) 2004
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci/* Some documentation on known sonixb registers:
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ciReg	Use
1362306a36Sopenharmony_cisn9c101 / sn9c102:
1462306a36Sopenharmony_ci0x10	high nibble red gain low nibble blue gain
1562306a36Sopenharmony_ci0x11	low nibble green gain
1662306a36Sopenharmony_cisn9c103:
1762306a36Sopenharmony_ci0x05	red gain 0-127
1862306a36Sopenharmony_ci0x06	blue gain 0-127
1962306a36Sopenharmony_ci0x07	green gain 0-127
2062306a36Sopenharmony_ciall:
2162306a36Sopenharmony_ci0x08-0x0f i2c / 3wire registers
2262306a36Sopenharmony_ci0x12	hstart
2362306a36Sopenharmony_ci0x13	vstart
2462306a36Sopenharmony_ci0x15	hsize (hsize = register-value * 16)
2562306a36Sopenharmony_ci0x16	vsize (vsize = register-value * 16)
2662306a36Sopenharmony_ci0x17	bit 0 toggle compression quality (according to sn9c102 driver)
2762306a36Sopenharmony_ci0x18	bit 7 enables compression, bit 4-5 set image down scaling:
2862306a36Sopenharmony_ci	00 scale 1, 01 scale 1/2, 10, scale 1/4
2962306a36Sopenharmony_ci0x19	high-nibble is sensor clock divider, changes exposure on sensors which
3062306a36Sopenharmony_ci	use a clock generated by the bridge. Some sensors have their own clock.
3162306a36Sopenharmony_ci0x1c	auto_exposure area (for avg_lum) startx (startx = register-value * 32)
3262306a36Sopenharmony_ci0x1d	auto_exposure area (for avg_lum) starty (starty = register-value * 32)
3362306a36Sopenharmony_ci0x1e	auto_exposure area (for avg_lum) stopx (hsize = (0x1e - 0x1c) * 32)
3462306a36Sopenharmony_ci0x1f	auto_exposure area (for avg_lum) stopy (vsize = (0x1f - 0x1d) * 32)
3562306a36Sopenharmony_ci*/
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#define MODULE_NAME "sonixb"
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#include <linux/input.h>
4062306a36Sopenharmony_ci#include "gspca.h"
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ciMODULE_AUTHOR("Jean-François Moine <http://moinejf.free.fr>");
4362306a36Sopenharmony_ciMODULE_DESCRIPTION("GSPCA/SN9C102 USB Camera Driver");
4462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci/* specific webcam descriptor */
4762306a36Sopenharmony_cistruct sd {
4862306a36Sopenharmony_ci	struct gspca_dev gspca_dev;	/* !! must be the first item */
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	struct v4l2_ctrl *brightness;
5162306a36Sopenharmony_ci	struct v4l2_ctrl *plfreq;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	atomic_t avg_lum;
5462306a36Sopenharmony_ci	int prev_avg_lum;
5562306a36Sopenharmony_ci	int exposure_knee;
5662306a36Sopenharmony_ci	int header_read;
5762306a36Sopenharmony_ci	u8 header[12]; /* Header without sof marker */
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	unsigned char autogain_ignore_frames;
6062306a36Sopenharmony_ci	unsigned char frames_to_drop;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	__u8 bridge;			/* Type of bridge */
6362306a36Sopenharmony_ci#define BRIDGE_101 0
6462306a36Sopenharmony_ci#define BRIDGE_102 0 /* We make no difference between 101 and 102 */
6562306a36Sopenharmony_ci#define BRIDGE_103 1
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	__u8 sensor;			/* Type of image sensor chip */
6862306a36Sopenharmony_ci#define SENSOR_HV7131D 0
6962306a36Sopenharmony_ci#define SENSOR_HV7131R 1
7062306a36Sopenharmony_ci#define SENSOR_OV6650 2
7162306a36Sopenharmony_ci#define SENSOR_OV7630 3
7262306a36Sopenharmony_ci#define SENSOR_PAS106 4
7362306a36Sopenharmony_ci#define SENSOR_PAS202 5
7462306a36Sopenharmony_ci#define SENSOR_TAS5110C 6
7562306a36Sopenharmony_ci#define SENSOR_TAS5110D 7
7662306a36Sopenharmony_ci#define SENSOR_TAS5130CXX 8
7762306a36Sopenharmony_ci	__u8 reg11;
7862306a36Sopenharmony_ci};
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_citypedef const __u8 sensor_init_t[8];
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistruct sensor_data {
8362306a36Sopenharmony_ci	const __u8 *bridge_init;
8462306a36Sopenharmony_ci	sensor_init_t *sensor_init;
8562306a36Sopenharmony_ci	int sensor_init_size;
8662306a36Sopenharmony_ci	int flags;
8762306a36Sopenharmony_ci	__u8 sensor_addr;
8862306a36Sopenharmony_ci};
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci/* sensor_data flags */
9162306a36Sopenharmony_ci#define F_SIF		0x01	/* sif or vga */
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci/* priv field of struct v4l2_pix_format flags (do not use low nibble!) */
9462306a36Sopenharmony_ci#define MODE_RAW 0x10		/* raw bayer mode */
9562306a36Sopenharmony_ci#define MODE_REDUCED_SIF 0x20	/* vga mode (320x240 / 160x120) on sif cam */
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci#define COMP 0xc7		/* 0x87 //0x07 */
9862306a36Sopenharmony_ci#define COMP1 0xc9		/* 0x89 //0x09 */
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci#define MCK_INIT 0x63
10162306a36Sopenharmony_ci#define MCK_INIT1 0x20		/*fixme: Bayer - 0x50 for JPEG ??*/
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci#define SYS_CLK 0x04
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci#define SENS(bridge, sensor, _flags, _sensor_addr) \
10662306a36Sopenharmony_ci{ \
10762306a36Sopenharmony_ci	.bridge_init = bridge, \
10862306a36Sopenharmony_ci	.sensor_init = sensor, \
10962306a36Sopenharmony_ci	.sensor_init_size = sizeof(sensor), \
11062306a36Sopenharmony_ci	.flags = _flags, .sensor_addr = _sensor_addr \
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci/* We calculate the autogain at the end of the transfer of a frame, at this
11462306a36Sopenharmony_ci   moment a frame with the old settings is being captured and transmitted. So
11562306a36Sopenharmony_ci   if we adjust the gain or exposure we must ignore at least the next frame for
11662306a36Sopenharmony_ci   the new settings to come into effect before doing any other adjustments. */
11762306a36Sopenharmony_ci#define AUTOGAIN_IGNORE_FRAMES 1
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic const struct v4l2_pix_format vga_mode[] = {
12062306a36Sopenharmony_ci	{160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
12162306a36Sopenharmony_ci		.bytesperline = 160,
12262306a36Sopenharmony_ci		.sizeimage = 160 * 120,
12362306a36Sopenharmony_ci		.colorspace = V4L2_COLORSPACE_SRGB,
12462306a36Sopenharmony_ci		.priv = 2 | MODE_RAW},
12562306a36Sopenharmony_ci	{160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
12662306a36Sopenharmony_ci		.bytesperline = 160,
12762306a36Sopenharmony_ci		.sizeimage = 160 * 120 * 5 / 4,
12862306a36Sopenharmony_ci		.colorspace = V4L2_COLORSPACE_SRGB,
12962306a36Sopenharmony_ci		.priv = 2},
13062306a36Sopenharmony_ci	{320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
13162306a36Sopenharmony_ci		.bytesperline = 320,
13262306a36Sopenharmony_ci		.sizeimage = 320 * 240 * 5 / 4,
13362306a36Sopenharmony_ci		.colorspace = V4L2_COLORSPACE_SRGB,
13462306a36Sopenharmony_ci		.priv = 1},
13562306a36Sopenharmony_ci	{640, 480, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
13662306a36Sopenharmony_ci		.bytesperline = 640,
13762306a36Sopenharmony_ci		.sizeimage = 640 * 480 * 5 / 4,
13862306a36Sopenharmony_ci		.colorspace = V4L2_COLORSPACE_SRGB,
13962306a36Sopenharmony_ci		.priv = 0},
14062306a36Sopenharmony_ci};
14162306a36Sopenharmony_cistatic const struct v4l2_pix_format sif_mode[] = {
14262306a36Sopenharmony_ci	{160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
14362306a36Sopenharmony_ci		.bytesperline = 160,
14462306a36Sopenharmony_ci		.sizeimage = 160 * 120,
14562306a36Sopenharmony_ci		.colorspace = V4L2_COLORSPACE_SRGB,
14662306a36Sopenharmony_ci		.priv = 1 | MODE_RAW | MODE_REDUCED_SIF},
14762306a36Sopenharmony_ci	{160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
14862306a36Sopenharmony_ci		.bytesperline = 160,
14962306a36Sopenharmony_ci		.sizeimage = 160 * 120 * 5 / 4,
15062306a36Sopenharmony_ci		.colorspace = V4L2_COLORSPACE_SRGB,
15162306a36Sopenharmony_ci		.priv = 1 | MODE_REDUCED_SIF},
15262306a36Sopenharmony_ci	{176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
15362306a36Sopenharmony_ci		.bytesperline = 176,
15462306a36Sopenharmony_ci		.sizeimage = 176 * 144,
15562306a36Sopenharmony_ci		.colorspace = V4L2_COLORSPACE_SRGB,
15662306a36Sopenharmony_ci		.priv = 1 | MODE_RAW},
15762306a36Sopenharmony_ci	{176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
15862306a36Sopenharmony_ci		.bytesperline = 176,
15962306a36Sopenharmony_ci		.sizeimage = 176 * 144 * 5 / 4,
16062306a36Sopenharmony_ci		.colorspace = V4L2_COLORSPACE_SRGB,
16162306a36Sopenharmony_ci		.priv = 1},
16262306a36Sopenharmony_ci	{320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
16362306a36Sopenharmony_ci		.bytesperline = 320,
16462306a36Sopenharmony_ci		.sizeimage = 320 * 240 * 5 / 4,
16562306a36Sopenharmony_ci		.colorspace = V4L2_COLORSPACE_SRGB,
16662306a36Sopenharmony_ci		.priv = 0 | MODE_REDUCED_SIF},
16762306a36Sopenharmony_ci	{352, 288, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
16862306a36Sopenharmony_ci		.bytesperline = 352,
16962306a36Sopenharmony_ci		.sizeimage = 352 * 288 * 5 / 4,
17062306a36Sopenharmony_ci		.colorspace = V4L2_COLORSPACE_SRGB,
17162306a36Sopenharmony_ci		.priv = 0},
17262306a36Sopenharmony_ci};
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_cistatic const __u8 initHv7131d[] = {
17562306a36Sopenharmony_ci	0x04, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
17662306a36Sopenharmony_ci	0x00, 0x00,
17762306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x02, 0x02, 0x00,
17862306a36Sopenharmony_ci	0x28, 0x1e, 0x60, 0x8e, 0x42,
17962306a36Sopenharmony_ci};
18062306a36Sopenharmony_cistatic const __u8 hv7131d_sensor_init[][8] = {
18162306a36Sopenharmony_ci	{0xa0, 0x11, 0x01, 0x04, 0x00, 0x00, 0x00, 0x17},
18262306a36Sopenharmony_ci	{0xa0, 0x11, 0x02, 0x00, 0x00, 0x00, 0x00, 0x17},
18362306a36Sopenharmony_ci	{0xa0, 0x11, 0x28, 0x00, 0x00, 0x00, 0x00, 0x17},
18462306a36Sopenharmony_ci	{0xa0, 0x11, 0x30, 0x30, 0x00, 0x00, 0x00, 0x17}, /* reset level */
18562306a36Sopenharmony_ci	{0xa0, 0x11, 0x34, 0x02, 0x00, 0x00, 0x00, 0x17}, /* pixel bias volt */
18662306a36Sopenharmony_ci};
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistatic const __u8 initHv7131r[] = {
18962306a36Sopenharmony_ci	0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
19062306a36Sopenharmony_ci	0x00, 0x00,
19162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x02, 0x01, 0x00,
19262306a36Sopenharmony_ci	0x28, 0x1e, 0x60, 0x8a, 0x20,
19362306a36Sopenharmony_ci};
19462306a36Sopenharmony_cistatic const __u8 hv7131r_sensor_init[][8] = {
19562306a36Sopenharmony_ci	{0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10},
19662306a36Sopenharmony_ci	{0xa0, 0x11, 0x01, 0x08, 0x2a, 0x2e, 0x00, 0x10},
19762306a36Sopenharmony_ci	{0xb0, 0x11, 0x20, 0x00, 0xd0, 0x2e, 0x00, 0x10},
19862306a36Sopenharmony_ci	{0xc0, 0x11, 0x25, 0x03, 0x0e, 0x28, 0x00, 0x16},
19962306a36Sopenharmony_ci	{0xa0, 0x11, 0x30, 0x10, 0x0e, 0x28, 0x00, 0x15},
20062306a36Sopenharmony_ci};
20162306a36Sopenharmony_cistatic const __u8 initOv6650[] = {
20262306a36Sopenharmony_ci	0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
20362306a36Sopenharmony_ci	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
20462306a36Sopenharmony_ci	0x00, 0x01, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x8b,
20562306a36Sopenharmony_ci	0x10,
20662306a36Sopenharmony_ci};
20762306a36Sopenharmony_cistatic const __u8 ov6650_sensor_init[][8] = {
20862306a36Sopenharmony_ci	/* Bright, contrast, etc are set through SCBB interface.
20962306a36Sopenharmony_ci	 * AVCAP on win2 do not send any data on this controls. */
21062306a36Sopenharmony_ci	/* Anyway, some registers appears to alter bright and constrat */
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	/* Reset sensor */
21362306a36Sopenharmony_ci	{0xa0, 0x60, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
21462306a36Sopenharmony_ci	/* Set clock register 0x11 low nibble is clock divider */
21562306a36Sopenharmony_ci	{0xd0, 0x60, 0x11, 0xc0, 0x1b, 0x18, 0xc1, 0x10},
21662306a36Sopenharmony_ci	/* Next some unknown stuff */
21762306a36Sopenharmony_ci	{0xb0, 0x60, 0x15, 0x00, 0x02, 0x18, 0xc1, 0x10},
21862306a36Sopenharmony_ci/*	{0xa0, 0x60, 0x1b, 0x01, 0x02, 0x18, 0xc1, 0x10},
21962306a36Sopenharmony_ci		 * THIS SET GREEN SCREEN
22062306a36Sopenharmony_ci		 * (pixels could be innverted in decode kind of "brg",
22162306a36Sopenharmony_ci		 * but blue wont be there. Avoid this data ... */
22262306a36Sopenharmony_ci	{0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, /* format out? */
22362306a36Sopenharmony_ci	{0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10},
22462306a36Sopenharmony_ci	{0xa0, 0x60, 0x30, 0x3d, 0x0a, 0xd8, 0xa4, 0x10},
22562306a36Sopenharmony_ci	/* Enable rgb brightness control */
22662306a36Sopenharmony_ci	{0xa0, 0x60, 0x61, 0x08, 0x00, 0x00, 0x00, 0x10},
22762306a36Sopenharmony_ci	/* HDG: Note windows uses the line below, which sets both register 0x60
22862306a36Sopenharmony_ci	   and 0x61 I believe these registers of the ov6650 are identical as
22962306a36Sopenharmony_ci	   those of the ov7630, because if this is true the windows settings
23062306a36Sopenharmony_ci	   add a bit additional red gain and a lot additional blue gain, which
23162306a36Sopenharmony_ci	   matches my findings that the windows settings make blue much too
23262306a36Sopenharmony_ci	   blue and red a little too red.
23362306a36Sopenharmony_ci	{0xb0, 0x60, 0x60, 0x66, 0x68, 0xd8, 0xa4, 0x10}, */
23462306a36Sopenharmony_ci	/* Some more unknown stuff */
23562306a36Sopenharmony_ci	{0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10},
23662306a36Sopenharmony_ci	{0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */
23762306a36Sopenharmony_ci};
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic const __u8 initOv7630[] = {
24062306a36Sopenharmony_ci	0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,	/* r01 .. r08 */
24162306a36Sopenharmony_ci	0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* r09 .. r10 */
24262306a36Sopenharmony_ci	0x00, 0x01, 0x01, 0x0a,				/* r11 .. r14 */
24362306a36Sopenharmony_ci	0x28, 0x1e,			/* H & V sizes     r15 .. r16 */
24462306a36Sopenharmony_ci	0x68, 0x8f, MCK_INIT1,				/* r17 .. r19 */
24562306a36Sopenharmony_ci};
24662306a36Sopenharmony_cistatic const __u8 ov7630_sensor_init[][8] = {
24762306a36Sopenharmony_ci	{0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
24862306a36Sopenharmony_ci	{0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10},
24962306a36Sopenharmony_ci/*	{0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10},	   jfm */
25062306a36Sopenharmony_ci	{0xd0, 0x21, 0x12, 0x5c, 0x00, 0x80, 0x34, 0x10},	/* jfm */
25162306a36Sopenharmony_ci	{0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10},
25262306a36Sopenharmony_ci	{0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10},
25362306a36Sopenharmony_ci	{0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10},
25462306a36Sopenharmony_ci	{0xd0, 0x21, 0x26, 0xa0, 0x9a, 0xa0, 0x30, 0x10},
25562306a36Sopenharmony_ci	{0xb0, 0x21, 0x2a, 0x80, 0x00, 0xa0, 0x30, 0x10},
25662306a36Sopenharmony_ci	{0xb0, 0x21, 0x2f, 0x3d, 0x24, 0xa0, 0x30, 0x10},
25762306a36Sopenharmony_ci	{0xa0, 0x21, 0x32, 0x86, 0x24, 0xa0, 0x30, 0x10},
25862306a36Sopenharmony_ci	{0xb0, 0x21, 0x60, 0xa9, 0x4a, 0xa0, 0x30, 0x10},
25962306a36Sopenharmony_ci/*	{0xb0, 0x21, 0x60, 0xa9, 0x42, 0xa0, 0x30, 0x10},	 * jfm */
26062306a36Sopenharmony_ci	{0xa0, 0x21, 0x65, 0x00, 0x42, 0xa0, 0x30, 0x10},
26162306a36Sopenharmony_ci	{0xa0, 0x21, 0x69, 0x38, 0x42, 0xa0, 0x30, 0x10},
26262306a36Sopenharmony_ci	{0xc0, 0x21, 0x6f, 0x88, 0x0b, 0x00, 0x30, 0x10},
26362306a36Sopenharmony_ci	{0xc0, 0x21, 0x74, 0x21, 0x8e, 0x00, 0x30, 0x10},
26462306a36Sopenharmony_ci	{0xa0, 0x21, 0x7d, 0xf7, 0x8e, 0x00, 0x30, 0x10},
26562306a36Sopenharmony_ci	{0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10},
26662306a36Sopenharmony_ci};
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_cistatic const __u8 initPas106[] = {
26962306a36Sopenharmony_ci	0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
27062306a36Sopenharmony_ci	0x00, 0x00,
27162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x04, 0x01, 0x00,
27262306a36Sopenharmony_ci	0x16, 0x12, 0x24, COMP1, MCK_INIT1,
27362306a36Sopenharmony_ci};
27462306a36Sopenharmony_ci/* compression 0x86 mckinit1 0x2b */
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci/* "Known" PAS106B registers:
27762306a36Sopenharmony_ci  0x02 clock divider
27862306a36Sopenharmony_ci  0x03 Variable framerate bits 4-11
27962306a36Sopenharmony_ci  0x04 Var framerate bits 0-3, one must leave the 4 msb's at 0 !!
28062306a36Sopenharmony_ci       The variable framerate control must never be set lower then 300,
28162306a36Sopenharmony_ci       which sets the framerate at 90 / reg02, otherwise vsync is lost.
28262306a36Sopenharmony_ci  0x05 Shutter Time Line Offset, this can be used as an exposure control:
28362306a36Sopenharmony_ci       0 = use full frame time, 255 = no exposure at all
28462306a36Sopenharmony_ci       Note this may never be larger then "var-framerate control" / 2 - 2.
28562306a36Sopenharmony_ci       When var-framerate control is < 514, no exposure is reached at the max
28662306a36Sopenharmony_ci       allowed value for the framerate control value, rather then at 255.
28762306a36Sopenharmony_ci  0x06 Shutter Time Pixel Offset, like reg05 this influences exposure, but
28862306a36Sopenharmony_ci       only a very little bit, leave at 0xcd
28962306a36Sopenharmony_ci  0x07 offset sign bit (bit0 1 > negative offset)
29062306a36Sopenharmony_ci  0x08 offset
29162306a36Sopenharmony_ci  0x09 Blue Gain
29262306a36Sopenharmony_ci  0x0a Green1 Gain
29362306a36Sopenharmony_ci  0x0b Green2 Gain
29462306a36Sopenharmony_ci  0x0c Red Gain
29562306a36Sopenharmony_ci  0x0e Global gain
29662306a36Sopenharmony_ci  0x13 Write 1 to commit settings to sensor
29762306a36Sopenharmony_ci*/
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistatic const __u8 pas106_sensor_init[][8] = {
30062306a36Sopenharmony_ci	/* Pixel Clock Divider 6 */
30162306a36Sopenharmony_ci	{ 0xa1, 0x40, 0x02, 0x04, 0x00, 0x00, 0x00, 0x14 },
30262306a36Sopenharmony_ci	/* Frame Time MSB (also seen as 0x12) */
30362306a36Sopenharmony_ci	{ 0xa1, 0x40, 0x03, 0x13, 0x00, 0x00, 0x00, 0x14 },
30462306a36Sopenharmony_ci	/* Frame Time LSB (also seen as 0x05) */
30562306a36Sopenharmony_ci	{ 0xa1, 0x40, 0x04, 0x06, 0x00, 0x00, 0x00, 0x14 },
30662306a36Sopenharmony_ci	/* Shutter Time Line Offset (also seen as 0x6d) */
30762306a36Sopenharmony_ci	{ 0xa1, 0x40, 0x05, 0x65, 0x00, 0x00, 0x00, 0x14 },
30862306a36Sopenharmony_ci	/* Shutter Time Pixel Offset (also seen as 0xb1) */
30962306a36Sopenharmony_ci	{ 0xa1, 0x40, 0x06, 0xcd, 0x00, 0x00, 0x00, 0x14 },
31062306a36Sopenharmony_ci	/* Black Level Subtract Sign (also seen 0x00) */
31162306a36Sopenharmony_ci	{ 0xa1, 0x40, 0x07, 0xc1, 0x00, 0x00, 0x00, 0x14 },
31262306a36Sopenharmony_ci	/* Black Level Subtract Level (also seen 0x01) */
31362306a36Sopenharmony_ci	{ 0xa1, 0x40, 0x08, 0x06, 0x00, 0x00, 0x00, 0x14 },
31462306a36Sopenharmony_ci	{ 0xa1, 0x40, 0x08, 0x06, 0x00, 0x00, 0x00, 0x14 },
31562306a36Sopenharmony_ci	/* Color Gain B Pixel 5 a */
31662306a36Sopenharmony_ci	{ 0xa1, 0x40, 0x09, 0x05, 0x00, 0x00, 0x00, 0x14 },
31762306a36Sopenharmony_ci	/* Color Gain G1 Pixel 1 5 */
31862306a36Sopenharmony_ci	{ 0xa1, 0x40, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x14 },
31962306a36Sopenharmony_ci	/* Color Gain G2 Pixel 1 0 5 */
32062306a36Sopenharmony_ci	{ 0xa1, 0x40, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x14 },
32162306a36Sopenharmony_ci	/* Color Gain R Pixel 3 1 */
32262306a36Sopenharmony_ci	{ 0xa1, 0x40, 0x0c, 0x05, 0x00, 0x00, 0x00, 0x14 },
32362306a36Sopenharmony_ci	/* Color GainH  Pixel */
32462306a36Sopenharmony_ci	{ 0xa1, 0x40, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x14 },
32562306a36Sopenharmony_ci	/* Global Gain */
32662306a36Sopenharmony_ci	{ 0xa1, 0x40, 0x0e, 0x0e, 0x00, 0x00, 0x00, 0x14 },
32762306a36Sopenharmony_ci	/* Contrast */
32862306a36Sopenharmony_ci	{ 0xa1, 0x40, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x14 },
32962306a36Sopenharmony_ci	/* H&V synchro polarity */
33062306a36Sopenharmony_ci	{ 0xa1, 0x40, 0x10, 0x06, 0x00, 0x00, 0x00, 0x14 },
33162306a36Sopenharmony_ci	/* ?default */
33262306a36Sopenharmony_ci	{ 0xa1, 0x40, 0x11, 0x06, 0x00, 0x00, 0x00, 0x14 },
33362306a36Sopenharmony_ci	/* DAC scale */
33462306a36Sopenharmony_ci	{ 0xa1, 0x40, 0x12, 0x06, 0x00, 0x00, 0x00, 0x14 },
33562306a36Sopenharmony_ci	/* ?default */
33662306a36Sopenharmony_ci	{ 0xa1, 0x40, 0x14, 0x02, 0x00, 0x00, 0x00, 0x14 },
33762306a36Sopenharmony_ci	/* Validate Settings */
33862306a36Sopenharmony_ci	{ 0xa1, 0x40, 0x13, 0x01, 0x00, 0x00, 0x00, 0x14 },
33962306a36Sopenharmony_ci};
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_cistatic const __u8 initPas202[] = {
34262306a36Sopenharmony_ci	0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
34362306a36Sopenharmony_ci	0x00, 0x00,
34462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x06, 0x03, 0x0a,
34562306a36Sopenharmony_ci	0x28, 0x1e, 0x20, 0x89, 0x20,
34662306a36Sopenharmony_ci};
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci/* "Known" PAS202BCB registers:
34962306a36Sopenharmony_ci  0x02 clock divider
35062306a36Sopenharmony_ci  0x04 Variable framerate bits 6-11 (*)
35162306a36Sopenharmony_ci  0x05 Var framerate  bits 0-5, one must leave the 2 msb's at 0 !!
35262306a36Sopenharmony_ci  0x07 Blue Gain
35362306a36Sopenharmony_ci  0x08 Green Gain
35462306a36Sopenharmony_ci  0x09 Red Gain
35562306a36Sopenharmony_ci  0x0b offset sign bit (bit0 1 > negative offset)
35662306a36Sopenharmony_ci  0x0c offset
35762306a36Sopenharmony_ci  0x0e Unknown image is slightly brighter when bit 0 is 0, if reg0f is 0 too,
35862306a36Sopenharmony_ci       leave at 1 otherwise we get a jump in our exposure control
35962306a36Sopenharmony_ci  0x0f Exposure 0-255, 0 = use full frame time, 255 = no exposure at all
36062306a36Sopenharmony_ci  0x10 Master gain 0 - 31
36162306a36Sopenharmony_ci  0x11 write 1 to apply changes
36262306a36Sopenharmony_ci  (*) The variable framerate control must never be set lower then 500
36362306a36Sopenharmony_ci      which sets the framerate at 30 / reg02, otherwise vsync is lost.
36462306a36Sopenharmony_ci*/
36562306a36Sopenharmony_cistatic const __u8 pas202_sensor_init[][8] = {
36662306a36Sopenharmony_ci	/* Set the clock divider to 4 -> 30 / 4 = 7.5 fps, we would like
36762306a36Sopenharmony_ci	   to set it lower, but for some reason the bridge starts missing
36862306a36Sopenharmony_ci	   vsync's then */
36962306a36Sopenharmony_ci	{0xa0, 0x40, 0x02, 0x04, 0x00, 0x00, 0x00, 0x10},
37062306a36Sopenharmony_ci	{0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10},
37162306a36Sopenharmony_ci	{0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10},
37262306a36Sopenharmony_ci	{0xd0, 0x40, 0x0c, 0x00, 0x0c, 0x01, 0x32, 0x10},
37362306a36Sopenharmony_ci	{0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10},
37462306a36Sopenharmony_ci	{0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10},
37562306a36Sopenharmony_ci	{0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10},
37662306a36Sopenharmony_ci	{0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
37762306a36Sopenharmony_ci	{0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10},
37862306a36Sopenharmony_ci	{0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
37962306a36Sopenharmony_ci};
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_cistatic const __u8 initTas5110c[] = {
38262306a36Sopenharmony_ci	0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
38362306a36Sopenharmony_ci	0x00, 0x00,
38462306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x45, 0x09, 0x0a,
38562306a36Sopenharmony_ci	0x16, 0x12, 0x60, 0x86, 0x2b,
38662306a36Sopenharmony_ci};
38762306a36Sopenharmony_ci/* Same as above, except a different hstart */
38862306a36Sopenharmony_cistatic const __u8 initTas5110d[] = {
38962306a36Sopenharmony_ci	0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
39062306a36Sopenharmony_ci	0x00, 0x00,
39162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x41, 0x09, 0x0a,
39262306a36Sopenharmony_ci	0x16, 0x12, 0x60, 0x86, 0x2b,
39362306a36Sopenharmony_ci};
39462306a36Sopenharmony_ci/* tas5110c is 3 wire, tas5110d is 2 wire (regular i2c) */
39562306a36Sopenharmony_cistatic const __u8 tas5110c_sensor_init[][8] = {
39662306a36Sopenharmony_ci	{0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10},
39762306a36Sopenharmony_ci	{0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10},
39862306a36Sopenharmony_ci};
39962306a36Sopenharmony_ci/* Known TAS5110D registers
40062306a36Sopenharmony_ci * reg02: gain, bit order reversed!! 0 == max gain, 255 == min gain
40162306a36Sopenharmony_ci * reg03: bit3: vflip, bit4: ~hflip, bit7: ~gainboost (~ == inverted)
40262306a36Sopenharmony_ci *        Note: writing reg03 seems to only work when written together with 02
40362306a36Sopenharmony_ci */
40462306a36Sopenharmony_cistatic const __u8 tas5110d_sensor_init[][8] = {
40562306a36Sopenharmony_ci	{0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17}, /* reset */
40662306a36Sopenharmony_ci};
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_cistatic const __u8 initTas5130[] = {
40962306a36Sopenharmony_ci	0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
41062306a36Sopenharmony_ci	0x00, 0x00,
41162306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x68, 0x0c, 0x0a,
41262306a36Sopenharmony_ci	0x28, 0x1e, 0x60, COMP, MCK_INIT,
41362306a36Sopenharmony_ci};
41462306a36Sopenharmony_cistatic const __u8 tas5130_sensor_init[][8] = {
41562306a36Sopenharmony_ci/*	{0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
41662306a36Sopenharmony_ci					* shutter 0x47 short exposure? */
41762306a36Sopenharmony_ci	{0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10},
41862306a36Sopenharmony_ci					/* shutter 0x01 long exposure */
41962306a36Sopenharmony_ci	{0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
42062306a36Sopenharmony_ci};
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_cistatic const struct sensor_data sensor_data[] = {
42362306a36Sopenharmony_ci	SENS(initHv7131d, hv7131d_sensor_init, 0, 0),
42462306a36Sopenharmony_ci	SENS(initHv7131r, hv7131r_sensor_init, 0, 0),
42562306a36Sopenharmony_ci	SENS(initOv6650, ov6650_sensor_init, F_SIF, 0x60),
42662306a36Sopenharmony_ci	SENS(initOv7630, ov7630_sensor_init, 0, 0x21),
42762306a36Sopenharmony_ci	SENS(initPas106, pas106_sensor_init, F_SIF, 0),
42862306a36Sopenharmony_ci	SENS(initPas202, pas202_sensor_init, 0, 0),
42962306a36Sopenharmony_ci	SENS(initTas5110c, tas5110c_sensor_init, F_SIF, 0),
43062306a36Sopenharmony_ci	SENS(initTas5110d, tas5110d_sensor_init, F_SIF, 0),
43162306a36Sopenharmony_ci	SENS(initTas5130, tas5130_sensor_init, 0, 0),
43262306a36Sopenharmony_ci};
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci/* get one byte in gspca_dev->usb_buf */
43562306a36Sopenharmony_cistatic void reg_r(struct gspca_dev *gspca_dev,
43662306a36Sopenharmony_ci		  __u16 value)
43762306a36Sopenharmony_ci{
43862306a36Sopenharmony_ci	int res;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	if (gspca_dev->usb_err < 0)
44162306a36Sopenharmony_ci		return;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	res = usb_control_msg(gspca_dev->dev,
44462306a36Sopenharmony_ci			usb_rcvctrlpipe(gspca_dev->dev, 0),
44562306a36Sopenharmony_ci			0,			/* request */
44662306a36Sopenharmony_ci			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
44762306a36Sopenharmony_ci			value,
44862306a36Sopenharmony_ci			0,			/* index */
44962306a36Sopenharmony_ci			gspca_dev->usb_buf, 1,
45062306a36Sopenharmony_ci			500);
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	if (res < 0) {
45362306a36Sopenharmony_ci		dev_err(gspca_dev->v4l2_dev.dev,
45462306a36Sopenharmony_ci			"Error reading register %02x: %d\n", value, res);
45562306a36Sopenharmony_ci		gspca_dev->usb_err = res;
45662306a36Sopenharmony_ci		/*
45762306a36Sopenharmony_ci		 * Make sure the result is zeroed to avoid uninitialized
45862306a36Sopenharmony_ci		 * values.
45962306a36Sopenharmony_ci		 */
46062306a36Sopenharmony_ci		gspca_dev->usb_buf[0] = 0;
46162306a36Sopenharmony_ci	}
46262306a36Sopenharmony_ci}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_cistatic void reg_w(struct gspca_dev *gspca_dev,
46562306a36Sopenharmony_ci		  __u16 value,
46662306a36Sopenharmony_ci		  const __u8 *buffer,
46762306a36Sopenharmony_ci		  int len)
46862306a36Sopenharmony_ci{
46962306a36Sopenharmony_ci	int res;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	if (gspca_dev->usb_err < 0)
47262306a36Sopenharmony_ci		return;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	memcpy(gspca_dev->usb_buf, buffer, len);
47562306a36Sopenharmony_ci	res = usb_control_msg(gspca_dev->dev,
47662306a36Sopenharmony_ci			usb_sndctrlpipe(gspca_dev->dev, 0),
47762306a36Sopenharmony_ci			0x08,			/* request */
47862306a36Sopenharmony_ci			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
47962306a36Sopenharmony_ci			value,
48062306a36Sopenharmony_ci			0,			/* index */
48162306a36Sopenharmony_ci			gspca_dev->usb_buf, len,
48262306a36Sopenharmony_ci			500);
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	if (res < 0) {
48562306a36Sopenharmony_ci		dev_err(gspca_dev->v4l2_dev.dev,
48662306a36Sopenharmony_ci			"Error writing register %02x: %d\n", value, res);
48762306a36Sopenharmony_ci		gspca_dev->usb_err = res;
48862306a36Sopenharmony_ci	}
48962306a36Sopenharmony_ci}
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_cistatic void i2c_w(struct gspca_dev *gspca_dev, const u8 *buf)
49262306a36Sopenharmony_ci{
49362306a36Sopenharmony_ci	int retry = 60;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	if (gspca_dev->usb_err < 0)
49662306a36Sopenharmony_ci		return;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	/* is i2c ready */
49962306a36Sopenharmony_ci	reg_w(gspca_dev, 0x08, buf, 8);
50062306a36Sopenharmony_ci	while (retry--) {
50162306a36Sopenharmony_ci		if (gspca_dev->usb_err < 0)
50262306a36Sopenharmony_ci			return;
50362306a36Sopenharmony_ci		msleep(1);
50462306a36Sopenharmony_ci		reg_r(gspca_dev, 0x08);
50562306a36Sopenharmony_ci		if (gspca_dev->usb_buf[0] & 0x04) {
50662306a36Sopenharmony_ci			if (gspca_dev->usb_buf[0] & 0x08) {
50762306a36Sopenharmony_ci				dev_err(gspca_dev->v4l2_dev.dev,
50862306a36Sopenharmony_ci					"i2c error writing %8ph\n", buf);
50962306a36Sopenharmony_ci				gspca_dev->usb_err = -EIO;
51062306a36Sopenharmony_ci			}
51162306a36Sopenharmony_ci			return;
51262306a36Sopenharmony_ci		}
51362306a36Sopenharmony_ci	}
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	dev_err(gspca_dev->v4l2_dev.dev, "i2c write timeout\n");
51662306a36Sopenharmony_ci	gspca_dev->usb_err = -EIO;
51762306a36Sopenharmony_ci}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_cistatic void i2c_w_vector(struct gspca_dev *gspca_dev,
52062306a36Sopenharmony_ci			const __u8 buffer[][8], int len)
52162306a36Sopenharmony_ci{
52262306a36Sopenharmony_ci	for (;;) {
52362306a36Sopenharmony_ci		if (gspca_dev->usb_err < 0)
52462306a36Sopenharmony_ci			return;
52562306a36Sopenharmony_ci		i2c_w(gspca_dev, *buffer);
52662306a36Sopenharmony_ci		len -= 8;
52762306a36Sopenharmony_ci		if (len <= 0)
52862306a36Sopenharmony_ci			break;
52962306a36Sopenharmony_ci		buffer++;
53062306a36Sopenharmony_ci	}
53162306a36Sopenharmony_ci}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_cistatic void setbrightness(struct gspca_dev *gspca_dev)
53462306a36Sopenharmony_ci{
53562306a36Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	switch (sd->sensor) {
53862306a36Sopenharmony_ci	case  SENSOR_OV6650:
53962306a36Sopenharmony_ci	case  SENSOR_OV7630: {
54062306a36Sopenharmony_ci		__u8 i2cOV[] =
54162306a36Sopenharmony_ci			{0xa0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10};
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci		/* change reg 0x06 */
54462306a36Sopenharmony_ci		i2cOV[1] = sensor_data[sd->sensor].sensor_addr;
54562306a36Sopenharmony_ci		i2cOV[3] = sd->brightness->val;
54662306a36Sopenharmony_ci		i2c_w(gspca_dev, i2cOV);
54762306a36Sopenharmony_ci		break;
54862306a36Sopenharmony_ci	}
54962306a36Sopenharmony_ci	case SENSOR_PAS106:
55062306a36Sopenharmony_ci	case SENSOR_PAS202: {
55162306a36Sopenharmony_ci		__u8 i2cpbright[] =
55262306a36Sopenharmony_ci			{0xb0, 0x40, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x16};
55362306a36Sopenharmony_ci		__u8 i2cpdoit[] =
55462306a36Sopenharmony_ci			{0xa0, 0x40, 0x11, 0x01, 0x00, 0x00, 0x00, 0x16};
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci		/* PAS106 uses reg 7 and 8 instead of b and c */
55762306a36Sopenharmony_ci		if (sd->sensor == SENSOR_PAS106) {
55862306a36Sopenharmony_ci			i2cpbright[2] = 7;
55962306a36Sopenharmony_ci			i2cpdoit[2] = 0x13;
56062306a36Sopenharmony_ci		}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci		if (sd->brightness->val < 127) {
56362306a36Sopenharmony_ci			/* change reg 0x0b, signreg */
56462306a36Sopenharmony_ci			i2cpbright[3] = 0x01;
56562306a36Sopenharmony_ci			/* set reg 0x0c, offset */
56662306a36Sopenharmony_ci			i2cpbright[4] = 127 - sd->brightness->val;
56762306a36Sopenharmony_ci		} else
56862306a36Sopenharmony_ci			i2cpbright[4] = sd->brightness->val - 127;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci		i2c_w(gspca_dev, i2cpbright);
57162306a36Sopenharmony_ci		i2c_w(gspca_dev, i2cpdoit);
57262306a36Sopenharmony_ci		break;
57362306a36Sopenharmony_ci	}
57462306a36Sopenharmony_ci	default:
57562306a36Sopenharmony_ci		break;
57662306a36Sopenharmony_ci	}
57762306a36Sopenharmony_ci}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_cistatic void setgain(struct gspca_dev *gspca_dev)
58062306a36Sopenharmony_ci{
58162306a36Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
58262306a36Sopenharmony_ci	u8 gain = gspca_dev->gain->val;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	switch (sd->sensor) {
58562306a36Sopenharmony_ci	case SENSOR_HV7131D: {
58662306a36Sopenharmony_ci		__u8 i2c[] =
58762306a36Sopenharmony_ci			{0xc0, 0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x17};
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci		i2c[3] = 0x3f - gain;
59062306a36Sopenharmony_ci		i2c[4] = 0x3f - gain;
59162306a36Sopenharmony_ci		i2c[5] = 0x3f - gain;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci		i2c_w(gspca_dev, i2c);
59462306a36Sopenharmony_ci		break;
59562306a36Sopenharmony_ci	}
59662306a36Sopenharmony_ci	case SENSOR_TAS5110C:
59762306a36Sopenharmony_ci	case SENSOR_TAS5130CXX: {
59862306a36Sopenharmony_ci		__u8 i2c[] =
59962306a36Sopenharmony_ci			{0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci		i2c[4] = 255 - gain;
60262306a36Sopenharmony_ci		i2c_w(gspca_dev, i2c);
60362306a36Sopenharmony_ci		break;
60462306a36Sopenharmony_ci	}
60562306a36Sopenharmony_ci	case SENSOR_TAS5110D: {
60662306a36Sopenharmony_ci		__u8 i2c[] = {
60762306a36Sopenharmony_ci			0xb0, 0x61, 0x02, 0x00, 0x10, 0x00, 0x00, 0x17 };
60862306a36Sopenharmony_ci		gain = 255 - gain;
60962306a36Sopenharmony_ci		/* The bits in the register are the wrong way around!! */
61062306a36Sopenharmony_ci		i2c[3] |= (gain & 0x80) >> 7;
61162306a36Sopenharmony_ci		i2c[3] |= (gain & 0x40) >> 5;
61262306a36Sopenharmony_ci		i2c[3] |= (gain & 0x20) >> 3;
61362306a36Sopenharmony_ci		i2c[3] |= (gain & 0x10) >> 1;
61462306a36Sopenharmony_ci		i2c[3] |= (gain & 0x08) << 1;
61562306a36Sopenharmony_ci		i2c[3] |= (gain & 0x04) << 3;
61662306a36Sopenharmony_ci		i2c[3] |= (gain & 0x02) << 5;
61762306a36Sopenharmony_ci		i2c[3] |= (gain & 0x01) << 7;
61862306a36Sopenharmony_ci		i2c_w(gspca_dev, i2c);
61962306a36Sopenharmony_ci		break;
62062306a36Sopenharmony_ci	}
62162306a36Sopenharmony_ci	case SENSOR_OV6650:
62262306a36Sopenharmony_ci	case SENSOR_OV7630: {
62362306a36Sopenharmony_ci		__u8 i2c[] = {0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci		/*
62662306a36Sopenharmony_ci		 * The ov7630's gain is weird, at 32 the gain drops to the
62762306a36Sopenharmony_ci		 * same level as at 16, so skip 32-47 (of the 0-63 scale).
62862306a36Sopenharmony_ci		 */
62962306a36Sopenharmony_ci		if (sd->sensor == SENSOR_OV7630 && gain >= 32)
63062306a36Sopenharmony_ci			gain += 16;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci		i2c[1] = sensor_data[sd->sensor].sensor_addr;
63362306a36Sopenharmony_ci		i2c[3] = gain;
63462306a36Sopenharmony_ci		i2c_w(gspca_dev, i2c);
63562306a36Sopenharmony_ci		break;
63662306a36Sopenharmony_ci	}
63762306a36Sopenharmony_ci	case SENSOR_PAS106:
63862306a36Sopenharmony_ci	case SENSOR_PAS202: {
63962306a36Sopenharmony_ci		__u8 i2cpgain[] =
64062306a36Sopenharmony_ci			{0xa0, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x15};
64162306a36Sopenharmony_ci		__u8 i2cpcolorgain[] =
64262306a36Sopenharmony_ci			{0xc0, 0x40, 0x07, 0x00, 0x00, 0x00, 0x00, 0x15};
64362306a36Sopenharmony_ci		__u8 i2cpdoit[] =
64462306a36Sopenharmony_ci			{0xa0, 0x40, 0x11, 0x01, 0x00, 0x00, 0x00, 0x16};
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci		/* PAS106 uses different regs (and has split green gains) */
64762306a36Sopenharmony_ci		if (sd->sensor == SENSOR_PAS106) {
64862306a36Sopenharmony_ci			i2cpgain[2] = 0x0e;
64962306a36Sopenharmony_ci			i2cpcolorgain[0] = 0xd0;
65062306a36Sopenharmony_ci			i2cpcolorgain[2] = 0x09;
65162306a36Sopenharmony_ci			i2cpdoit[2] = 0x13;
65262306a36Sopenharmony_ci		}
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci		i2cpgain[3] = gain;
65562306a36Sopenharmony_ci		i2cpcolorgain[3] = gain >> 1;
65662306a36Sopenharmony_ci		i2cpcolorgain[4] = gain >> 1;
65762306a36Sopenharmony_ci		i2cpcolorgain[5] = gain >> 1;
65862306a36Sopenharmony_ci		i2cpcolorgain[6] = gain >> 1;
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci		i2c_w(gspca_dev, i2cpgain);
66162306a36Sopenharmony_ci		i2c_w(gspca_dev, i2cpcolorgain);
66262306a36Sopenharmony_ci		i2c_w(gspca_dev, i2cpdoit);
66362306a36Sopenharmony_ci		break;
66462306a36Sopenharmony_ci	}
66562306a36Sopenharmony_ci	default:
66662306a36Sopenharmony_ci		if (sd->bridge == BRIDGE_103) {
66762306a36Sopenharmony_ci			u8 buf[3] = { gain, gain, gain }; /* R, G, B */
66862306a36Sopenharmony_ci			reg_w(gspca_dev, 0x05, buf, 3);
66962306a36Sopenharmony_ci		} else {
67062306a36Sopenharmony_ci			u8 buf[2];
67162306a36Sopenharmony_ci			buf[0] = gain << 4 | gain; /* Red and blue */
67262306a36Sopenharmony_ci			buf[1] = gain; /* Green */
67362306a36Sopenharmony_ci			reg_w(gspca_dev, 0x10, buf, 2);
67462306a36Sopenharmony_ci		}
67562306a36Sopenharmony_ci	}
67662306a36Sopenharmony_ci}
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_cistatic void setexposure(struct gspca_dev *gspca_dev)
67962306a36Sopenharmony_ci{
68062306a36Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	switch (sd->sensor) {
68362306a36Sopenharmony_ci	case SENSOR_HV7131D: {
68462306a36Sopenharmony_ci		/* Note the datasheet wrongly says line mode exposure uses reg
68562306a36Sopenharmony_ci		   0x26 and 0x27, testing has shown 0x25 + 0x26 */
68662306a36Sopenharmony_ci		__u8 i2c[] = {0xc0, 0x11, 0x25, 0x00, 0x00, 0x00, 0x00, 0x17};
68762306a36Sopenharmony_ci		u16 reg = gspca_dev->exposure->val;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci		i2c[3] = reg >> 8;
69062306a36Sopenharmony_ci		i2c[4] = reg & 0xff;
69162306a36Sopenharmony_ci		i2c_w(gspca_dev, i2c);
69262306a36Sopenharmony_ci		break;
69362306a36Sopenharmony_ci	}
69462306a36Sopenharmony_ci	case SENSOR_TAS5110C:
69562306a36Sopenharmony_ci	case SENSOR_TAS5110D: {
69662306a36Sopenharmony_ci		/* register 19's high nibble contains the sn9c10x clock divider
69762306a36Sopenharmony_ci		   The high nibble configures the no fps according to the
69862306a36Sopenharmony_ci		   formula: 60 / high_nibble. With a maximum of 30 fps */
69962306a36Sopenharmony_ci		u8 reg = gspca_dev->exposure->val;
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci		reg = (reg << 4) | 0x0b;
70262306a36Sopenharmony_ci		reg_w(gspca_dev, 0x19, &reg, 1);
70362306a36Sopenharmony_ci		break;
70462306a36Sopenharmony_ci	}
70562306a36Sopenharmony_ci	case SENSOR_OV6650:
70662306a36Sopenharmony_ci	case SENSOR_OV7630: {
70762306a36Sopenharmony_ci		/* The ov6650 / ov7630 have 2 registers which both influence
70862306a36Sopenharmony_ci		   exposure, register 11, whose low nibble sets the nr off fps
70962306a36Sopenharmony_ci		   according to: fps = 30 / (low_nibble + 1)
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci		   The fps configures the maximum exposure setting, but it is
71262306a36Sopenharmony_ci		   possible to use less exposure then what the fps maximum
71362306a36Sopenharmony_ci		   allows by setting register 10. register 10 configures the
71462306a36Sopenharmony_ci		   actual exposure as quotient of the full exposure, with 0
71562306a36Sopenharmony_ci		   being no exposure at all (not very useful) and reg10_max
71662306a36Sopenharmony_ci		   being max exposure possible at that framerate.
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci		   The code maps our 0 - 510 ms exposure ctrl to these 2
71962306a36Sopenharmony_ci		   registers, trying to keep fps as high as possible.
72062306a36Sopenharmony_ci		*/
72162306a36Sopenharmony_ci		__u8 i2c[] = {0xb0, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10};
72262306a36Sopenharmony_ci		int reg10, reg11, reg10_max;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci		/* ov6645 datasheet says reg10_max is 9a, but that uses
72562306a36Sopenharmony_ci		   tline * 2 * reg10 as formula for calculating texpo, the
72662306a36Sopenharmony_ci		   ov6650 probably uses the same formula as the 7730 which uses
72762306a36Sopenharmony_ci		   tline * 4 * reg10, which explains why the reg10max we've
72862306a36Sopenharmony_ci		   found experimentally for the ov6650 is exactly half that of
72962306a36Sopenharmony_ci		   the ov6645. The ov7630 datasheet says the max is 0x41. */
73062306a36Sopenharmony_ci		if (sd->sensor == SENSOR_OV6650) {
73162306a36Sopenharmony_ci			reg10_max = 0x4d;
73262306a36Sopenharmony_ci			i2c[4] = 0xc0; /* OV6650 needs non default vsync pol */
73362306a36Sopenharmony_ci		} else
73462306a36Sopenharmony_ci			reg10_max = 0x41;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci		reg11 = (15 * gspca_dev->exposure->val + 999) / 1000;
73762306a36Sopenharmony_ci		if (reg11 < 1)
73862306a36Sopenharmony_ci			reg11 = 1;
73962306a36Sopenharmony_ci		else if (reg11 > 16)
74062306a36Sopenharmony_ci			reg11 = 16;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci		/* In 640x480, if the reg11 has less than 4, the image is
74362306a36Sopenharmony_ci		   unstable (the bridge goes into a higher compression mode
74462306a36Sopenharmony_ci		   which we have not reverse engineered yet). */
74562306a36Sopenharmony_ci		if (gspca_dev->pixfmt.width == 640 && reg11 < 4)
74662306a36Sopenharmony_ci			reg11 = 4;
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci		/* frame exposure time in ms = 1000 * reg11 / 30    ->
74962306a36Sopenharmony_ci		reg10 = (gspca_dev->exposure->val / 2) * reg10_max
75062306a36Sopenharmony_ci				/ (1000 * reg11 / 30) */
75162306a36Sopenharmony_ci		reg10 = (gspca_dev->exposure->val * 15 * reg10_max)
75262306a36Sopenharmony_ci				/ (1000 * reg11);
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci		/* Don't allow this to get below 10 when using autogain, the
75562306a36Sopenharmony_ci		   steps become very large (relatively) when below 10 causing
75662306a36Sopenharmony_ci		   the image to oscillate from much too dark, to much too bright
75762306a36Sopenharmony_ci		   and back again. */
75862306a36Sopenharmony_ci		if (gspca_dev->autogain->val && reg10 < 10)
75962306a36Sopenharmony_ci			reg10 = 10;
76062306a36Sopenharmony_ci		else if (reg10 > reg10_max)
76162306a36Sopenharmony_ci			reg10 = reg10_max;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci		/* Write reg 10 and reg11 low nibble */
76462306a36Sopenharmony_ci		i2c[1] = sensor_data[sd->sensor].sensor_addr;
76562306a36Sopenharmony_ci		i2c[3] = reg10;
76662306a36Sopenharmony_ci		i2c[4] |= reg11 - 1;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci		/* If register 11 didn't change, don't change it */
76962306a36Sopenharmony_ci		if (sd->reg11 == reg11)
77062306a36Sopenharmony_ci			i2c[0] = 0xa0;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci		i2c_w(gspca_dev, i2c);
77362306a36Sopenharmony_ci		if (gspca_dev->usb_err == 0)
77462306a36Sopenharmony_ci			sd->reg11 = reg11;
77562306a36Sopenharmony_ci		break;
77662306a36Sopenharmony_ci	}
77762306a36Sopenharmony_ci	case SENSOR_PAS202: {
77862306a36Sopenharmony_ci		__u8 i2cpframerate[] =
77962306a36Sopenharmony_ci			{0xb0, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x16};
78062306a36Sopenharmony_ci		__u8 i2cpexpo[] =
78162306a36Sopenharmony_ci			{0xa0, 0x40, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x16};
78262306a36Sopenharmony_ci		const __u8 i2cpdoit[] =
78362306a36Sopenharmony_ci			{0xa0, 0x40, 0x11, 0x01, 0x00, 0x00, 0x00, 0x16};
78462306a36Sopenharmony_ci		int framerate_ctrl;
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci		/* The exposure knee for the autogain algorithm is 200
78762306a36Sopenharmony_ci		   (100 ms / 10 fps on other sensors), for values below this
78862306a36Sopenharmony_ci		   use the control for setting the partial frame expose time,
78962306a36Sopenharmony_ci		   above that use variable framerate. This way we run at max
79062306a36Sopenharmony_ci		   framerate (640x480@7.5 fps, 320x240@10fps) until the knee
79162306a36Sopenharmony_ci		   is reached. Using the variable framerate control above 200
79262306a36Sopenharmony_ci		   is better then playing around with both clockdiv + partial
79362306a36Sopenharmony_ci		   frame exposure times (like we are doing with the ov chips),
79462306a36Sopenharmony_ci		   as that sometimes leads to jumps in the exposure control,
79562306a36Sopenharmony_ci		   which are bad for auto exposure. */
79662306a36Sopenharmony_ci		if (gspca_dev->exposure->val < 200) {
79762306a36Sopenharmony_ci			i2cpexpo[3] = 255 - (gspca_dev->exposure->val * 255)
79862306a36Sopenharmony_ci						/ 200;
79962306a36Sopenharmony_ci			framerate_ctrl = 500;
80062306a36Sopenharmony_ci		} else {
80162306a36Sopenharmony_ci			/* The PAS202's exposure control goes from 0 - 4095,
80262306a36Sopenharmony_ci			   but anything below 500 causes vsync issues, so scale
80362306a36Sopenharmony_ci			   our 200-1023 to 500-4095 */
80462306a36Sopenharmony_ci			framerate_ctrl = (gspca_dev->exposure->val - 200)
80562306a36Sopenharmony_ci							* 1000 / 229 +  500;
80662306a36Sopenharmony_ci		}
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci		i2cpframerate[3] = framerate_ctrl >> 6;
80962306a36Sopenharmony_ci		i2cpframerate[4] = framerate_ctrl & 0x3f;
81062306a36Sopenharmony_ci		i2c_w(gspca_dev, i2cpframerate);
81162306a36Sopenharmony_ci		i2c_w(gspca_dev, i2cpexpo);
81262306a36Sopenharmony_ci		i2c_w(gspca_dev, i2cpdoit);
81362306a36Sopenharmony_ci		break;
81462306a36Sopenharmony_ci	}
81562306a36Sopenharmony_ci	case SENSOR_PAS106: {
81662306a36Sopenharmony_ci		__u8 i2cpframerate[] =
81762306a36Sopenharmony_ci			{0xb1, 0x40, 0x03, 0x00, 0x00, 0x00, 0x00, 0x14};
81862306a36Sopenharmony_ci		__u8 i2cpexpo[] =
81962306a36Sopenharmony_ci			{0xa1, 0x40, 0x05, 0x00, 0x00, 0x00, 0x00, 0x14};
82062306a36Sopenharmony_ci		const __u8 i2cpdoit[] =
82162306a36Sopenharmony_ci			{0xa1, 0x40, 0x13, 0x01, 0x00, 0x00, 0x00, 0x14};
82262306a36Sopenharmony_ci		int framerate_ctrl;
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci		/* For values below 150 use partial frame exposure, above
82562306a36Sopenharmony_ci		   that use framerate ctrl */
82662306a36Sopenharmony_ci		if (gspca_dev->exposure->val < 150) {
82762306a36Sopenharmony_ci			i2cpexpo[3] = 150 - gspca_dev->exposure->val;
82862306a36Sopenharmony_ci			framerate_ctrl = 300;
82962306a36Sopenharmony_ci		} else {
83062306a36Sopenharmony_ci			/* The PAS106's exposure control goes from 0 - 4095,
83162306a36Sopenharmony_ci			   but anything below 300 causes vsync issues, so scale
83262306a36Sopenharmony_ci			   our 150-1023 to 300-4095 */
83362306a36Sopenharmony_ci			framerate_ctrl = (gspca_dev->exposure->val - 150)
83462306a36Sopenharmony_ci						* 1000 / 230 + 300;
83562306a36Sopenharmony_ci		}
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci		i2cpframerate[3] = framerate_ctrl >> 4;
83862306a36Sopenharmony_ci		i2cpframerate[4] = framerate_ctrl & 0x0f;
83962306a36Sopenharmony_ci		i2c_w(gspca_dev, i2cpframerate);
84062306a36Sopenharmony_ci		i2c_w(gspca_dev, i2cpexpo);
84162306a36Sopenharmony_ci		i2c_w(gspca_dev, i2cpdoit);
84262306a36Sopenharmony_ci		break;
84362306a36Sopenharmony_ci	}
84462306a36Sopenharmony_ci	default:
84562306a36Sopenharmony_ci		break;
84662306a36Sopenharmony_ci	}
84762306a36Sopenharmony_ci}
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_cistatic void setfreq(struct gspca_dev *gspca_dev)
85062306a36Sopenharmony_ci{
85162306a36Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	if (sd->sensor == SENSOR_OV6650 || sd->sensor == SENSOR_OV7630) {
85462306a36Sopenharmony_ci		/* Framerate adjust register for artificial light 50 hz flicker
85562306a36Sopenharmony_ci		   compensation, for the ov6650 this is identical to ov6630
85662306a36Sopenharmony_ci		   0x2b register, see ov6630 datasheet.
85762306a36Sopenharmony_ci		   0x4f / 0x8a -> (30 fps -> 25 fps), 0x00 -> no adjustment */
85862306a36Sopenharmony_ci		__u8 i2c[] = {0xa0, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10};
85962306a36Sopenharmony_ci		switch (sd->plfreq->val) {
86062306a36Sopenharmony_ci		default:
86162306a36Sopenharmony_ci/*		case 0:			 * no filter*/
86262306a36Sopenharmony_ci/*		case 2:			 * 60 hz */
86362306a36Sopenharmony_ci			i2c[3] = 0;
86462306a36Sopenharmony_ci			break;
86562306a36Sopenharmony_ci		case 1:			/* 50 hz */
86662306a36Sopenharmony_ci			i2c[3] = (sd->sensor == SENSOR_OV6650)
86762306a36Sopenharmony_ci					? 0x4f : 0x8a;
86862306a36Sopenharmony_ci			break;
86962306a36Sopenharmony_ci		}
87062306a36Sopenharmony_ci		i2c[1] = sensor_data[sd->sensor].sensor_addr;
87162306a36Sopenharmony_ci		i2c_w(gspca_dev, i2c);
87262306a36Sopenharmony_ci	}
87362306a36Sopenharmony_ci}
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_cistatic void do_autogain(struct gspca_dev *gspca_dev)
87662306a36Sopenharmony_ci{
87762306a36Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
87862306a36Sopenharmony_ci	int deadzone, desired_avg_lum, avg_lum;
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	avg_lum = atomic_read(&sd->avg_lum);
88162306a36Sopenharmony_ci	if (avg_lum == -1)
88262306a36Sopenharmony_ci		return;
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	if (sd->autogain_ignore_frames > 0) {
88562306a36Sopenharmony_ci		sd->autogain_ignore_frames--;
88662306a36Sopenharmony_ci		return;
88762306a36Sopenharmony_ci	}
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	/* SIF / VGA sensors have a different autoexposure area and thus
89062306a36Sopenharmony_ci	   different avg_lum values for the same picture brightness */
89162306a36Sopenharmony_ci	if (sensor_data[sd->sensor].flags & F_SIF) {
89262306a36Sopenharmony_ci		deadzone = 500;
89362306a36Sopenharmony_ci		/* SIF sensors tend to overexpose, so keep this small */
89462306a36Sopenharmony_ci		desired_avg_lum = 5000;
89562306a36Sopenharmony_ci	} else {
89662306a36Sopenharmony_ci		deadzone = 1500;
89762306a36Sopenharmony_ci		desired_avg_lum = 13000;
89862306a36Sopenharmony_ci	}
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	if (sd->brightness)
90162306a36Sopenharmony_ci		desired_avg_lum = sd->brightness->val * desired_avg_lum / 127;
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	if (gspca_dev->exposure->maximum < 500) {
90462306a36Sopenharmony_ci		if (gspca_coarse_grained_expo_autogain(gspca_dev, avg_lum,
90562306a36Sopenharmony_ci				desired_avg_lum, deadzone))
90662306a36Sopenharmony_ci			sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
90762306a36Sopenharmony_ci	} else {
90862306a36Sopenharmony_ci		int gain_knee = (s32)gspca_dev->gain->maximum * 9 / 10;
90962306a36Sopenharmony_ci		if (gspca_expo_autogain(gspca_dev, avg_lum, desired_avg_lum,
91062306a36Sopenharmony_ci				deadzone, gain_knee, sd->exposure_knee))
91162306a36Sopenharmony_ci			sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
91262306a36Sopenharmony_ci	}
91362306a36Sopenharmony_ci}
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci/* this function is called at probe time */
91662306a36Sopenharmony_cistatic int sd_config(struct gspca_dev *gspca_dev,
91762306a36Sopenharmony_ci			const struct usb_device_id *id)
91862306a36Sopenharmony_ci{
91962306a36Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
92062306a36Sopenharmony_ci	struct cam *cam;
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	reg_r(gspca_dev, 0x00);
92362306a36Sopenharmony_ci	if (gspca_dev->usb_buf[0] != 0x10)
92462306a36Sopenharmony_ci		return -ENODEV;
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	/* copy the webcam info from the device id */
92762306a36Sopenharmony_ci	sd->sensor = id->driver_info >> 8;
92862306a36Sopenharmony_ci	sd->bridge = id->driver_info & 0xff;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	cam = &gspca_dev->cam;
93162306a36Sopenharmony_ci	if (!(sensor_data[sd->sensor].flags & F_SIF)) {
93262306a36Sopenharmony_ci		cam->cam_mode = vga_mode;
93362306a36Sopenharmony_ci		cam->nmodes = ARRAY_SIZE(vga_mode);
93462306a36Sopenharmony_ci	} else {
93562306a36Sopenharmony_ci		cam->cam_mode = sif_mode;
93662306a36Sopenharmony_ci		cam->nmodes = ARRAY_SIZE(sif_mode);
93762306a36Sopenharmony_ci	}
93862306a36Sopenharmony_ci	cam->npkt = 36;			/* 36 packets per ISOC message */
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci	return 0;
94162306a36Sopenharmony_ci}
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci/* this function is called at probe and resume time */
94462306a36Sopenharmony_cistatic int sd_init(struct gspca_dev *gspca_dev)
94562306a36Sopenharmony_ci{
94662306a36Sopenharmony_ci	const __u8 stop = 0x09; /* Disable stream turn of LED */
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	reg_w(gspca_dev, 0x01, &stop, 1);
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	return gspca_dev->usb_err;
95162306a36Sopenharmony_ci}
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_cistatic int sd_s_ctrl(struct v4l2_ctrl *ctrl)
95462306a36Sopenharmony_ci{
95562306a36Sopenharmony_ci	struct gspca_dev *gspca_dev =
95662306a36Sopenharmony_ci		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
95762306a36Sopenharmony_ci	struct sd *sd = (struct sd *)gspca_dev;
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	gspca_dev->usb_err = 0;
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	if (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val) {
96262306a36Sopenharmony_ci		/* when switching to autogain set defaults to make sure
96362306a36Sopenharmony_ci		   we are on a valid point of the autogain gain /
96462306a36Sopenharmony_ci		   exposure knee graph, and give this change time to
96562306a36Sopenharmony_ci		   take effect before doing autogain. */
96662306a36Sopenharmony_ci		gspca_dev->gain->val = gspca_dev->gain->default_value;
96762306a36Sopenharmony_ci		gspca_dev->exposure->val = gspca_dev->exposure->default_value;
96862306a36Sopenharmony_ci		sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
96962306a36Sopenharmony_ci	}
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	if (!gspca_dev->streaming)
97262306a36Sopenharmony_ci		return 0;
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	switch (ctrl->id) {
97562306a36Sopenharmony_ci	case V4L2_CID_BRIGHTNESS:
97662306a36Sopenharmony_ci		setbrightness(gspca_dev);
97762306a36Sopenharmony_ci		break;
97862306a36Sopenharmony_ci	case V4L2_CID_AUTOGAIN:
97962306a36Sopenharmony_ci		if (gspca_dev->exposure->is_new || (ctrl->is_new && ctrl->val))
98062306a36Sopenharmony_ci			setexposure(gspca_dev);
98162306a36Sopenharmony_ci		if (gspca_dev->gain->is_new || (ctrl->is_new && ctrl->val))
98262306a36Sopenharmony_ci			setgain(gspca_dev);
98362306a36Sopenharmony_ci		break;
98462306a36Sopenharmony_ci	case V4L2_CID_POWER_LINE_FREQUENCY:
98562306a36Sopenharmony_ci		setfreq(gspca_dev);
98662306a36Sopenharmony_ci		break;
98762306a36Sopenharmony_ci	default:
98862306a36Sopenharmony_ci		return -EINVAL;
98962306a36Sopenharmony_ci	}
99062306a36Sopenharmony_ci	return gspca_dev->usb_err;
99162306a36Sopenharmony_ci}
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_cistatic const struct v4l2_ctrl_ops sd_ctrl_ops = {
99462306a36Sopenharmony_ci	.s_ctrl = sd_s_ctrl,
99562306a36Sopenharmony_ci};
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci/* this function is called at probe time */
99862306a36Sopenharmony_cistatic int sd_init_controls(struct gspca_dev *gspca_dev)
99962306a36Sopenharmony_ci{
100062306a36Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
100162306a36Sopenharmony_ci	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	gspca_dev->vdev.ctrl_handler = hdl;
100462306a36Sopenharmony_ci	v4l2_ctrl_handler_init(hdl, 5);
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	if (sd->sensor == SENSOR_OV6650 || sd->sensor == SENSOR_OV7630 ||
100762306a36Sopenharmony_ci	    sd->sensor == SENSOR_PAS106 || sd->sensor == SENSOR_PAS202)
100862306a36Sopenharmony_ci		sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
100962306a36Sopenharmony_ci					V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	/* Gain range is sensor dependent */
101262306a36Sopenharmony_ci	switch (sd->sensor) {
101362306a36Sopenharmony_ci	case SENSOR_OV6650:
101462306a36Sopenharmony_ci	case SENSOR_PAS106:
101562306a36Sopenharmony_ci	case SENSOR_PAS202:
101662306a36Sopenharmony_ci		gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
101762306a36Sopenharmony_ci					V4L2_CID_GAIN, 0, 31, 1, 15);
101862306a36Sopenharmony_ci		break;
101962306a36Sopenharmony_ci	case SENSOR_OV7630:
102062306a36Sopenharmony_ci		gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
102162306a36Sopenharmony_ci					V4L2_CID_GAIN, 0, 47, 1, 31);
102262306a36Sopenharmony_ci		break;
102362306a36Sopenharmony_ci	case SENSOR_HV7131D:
102462306a36Sopenharmony_ci		gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
102562306a36Sopenharmony_ci					V4L2_CID_GAIN, 0, 63, 1, 31);
102662306a36Sopenharmony_ci		break;
102762306a36Sopenharmony_ci	case SENSOR_TAS5110C:
102862306a36Sopenharmony_ci	case SENSOR_TAS5110D:
102962306a36Sopenharmony_ci	case SENSOR_TAS5130CXX:
103062306a36Sopenharmony_ci		gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
103162306a36Sopenharmony_ci					V4L2_CID_GAIN, 0, 255, 1, 127);
103262306a36Sopenharmony_ci		break;
103362306a36Sopenharmony_ci	default:
103462306a36Sopenharmony_ci		if (sd->bridge == BRIDGE_103) {
103562306a36Sopenharmony_ci			gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
103662306a36Sopenharmony_ci						V4L2_CID_GAIN, 0, 127, 1, 63);
103762306a36Sopenharmony_ci		} else {
103862306a36Sopenharmony_ci			gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
103962306a36Sopenharmony_ci						V4L2_CID_GAIN, 0, 15, 1, 7);
104062306a36Sopenharmony_ci		}
104162306a36Sopenharmony_ci	}
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	/* Exposure range is sensor dependent, and not all have exposure */
104462306a36Sopenharmony_ci	switch (sd->sensor) {
104562306a36Sopenharmony_ci	case SENSOR_HV7131D:
104662306a36Sopenharmony_ci		gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
104762306a36Sopenharmony_ci					V4L2_CID_EXPOSURE, 0, 8191, 1, 482);
104862306a36Sopenharmony_ci		sd->exposure_knee = 964;
104962306a36Sopenharmony_ci		break;
105062306a36Sopenharmony_ci	case SENSOR_OV6650:
105162306a36Sopenharmony_ci	case SENSOR_OV7630:
105262306a36Sopenharmony_ci	case SENSOR_PAS106:
105362306a36Sopenharmony_ci	case SENSOR_PAS202:
105462306a36Sopenharmony_ci		gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
105562306a36Sopenharmony_ci					V4L2_CID_EXPOSURE, 0, 1023, 1, 66);
105662306a36Sopenharmony_ci		sd->exposure_knee = 200;
105762306a36Sopenharmony_ci		break;
105862306a36Sopenharmony_ci	case SENSOR_TAS5110C:
105962306a36Sopenharmony_ci	case SENSOR_TAS5110D:
106062306a36Sopenharmony_ci		gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
106162306a36Sopenharmony_ci					V4L2_CID_EXPOSURE, 2, 15, 1, 2);
106262306a36Sopenharmony_ci		break;
106362306a36Sopenharmony_ci	}
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	if (gspca_dev->exposure) {
106662306a36Sopenharmony_ci		gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
106762306a36Sopenharmony_ci						V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
106862306a36Sopenharmony_ci	}
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	if (sd->sensor == SENSOR_OV6650 || sd->sensor == SENSOR_OV7630)
107162306a36Sopenharmony_ci		sd->plfreq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops,
107262306a36Sopenharmony_ci			V4L2_CID_POWER_LINE_FREQUENCY,
107362306a36Sopenharmony_ci			V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0,
107462306a36Sopenharmony_ci			V4L2_CID_POWER_LINE_FREQUENCY_DISABLED);
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	if (hdl->error) {
107762306a36Sopenharmony_ci		pr_err("Could not initialize controls\n");
107862306a36Sopenharmony_ci		return hdl->error;
107962306a36Sopenharmony_ci	}
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	if (gspca_dev->autogain)
108262306a36Sopenharmony_ci		v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, false);
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	return 0;
108562306a36Sopenharmony_ci}
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci/* -- start the camera -- */
108862306a36Sopenharmony_cistatic int sd_start(struct gspca_dev *gspca_dev)
108962306a36Sopenharmony_ci{
109062306a36Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
109162306a36Sopenharmony_ci	struct cam *cam = &gspca_dev->cam;
109262306a36Sopenharmony_ci	int i, mode;
109362306a36Sopenharmony_ci	__u8 regs[0x31];
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	mode = cam->cam_mode[gspca_dev->curr_mode].priv & 0x07;
109662306a36Sopenharmony_ci	/* Copy registers 0x01 - 0x19 from the template */
109762306a36Sopenharmony_ci	memcpy(&regs[0x01], sensor_data[sd->sensor].bridge_init, 0x19);
109862306a36Sopenharmony_ci	/* Set the mode */
109962306a36Sopenharmony_ci	regs[0x18] |= mode << 4;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	/* Set bridge gain to 1.0 */
110262306a36Sopenharmony_ci	if (sd->bridge == BRIDGE_103) {
110362306a36Sopenharmony_ci		regs[0x05] = 0x20; /* Red */
110462306a36Sopenharmony_ci		regs[0x06] = 0x20; /* Green */
110562306a36Sopenharmony_ci		regs[0x07] = 0x20; /* Blue */
110662306a36Sopenharmony_ci	} else {
110762306a36Sopenharmony_ci		regs[0x10] = 0x00; /* Red and blue */
110862306a36Sopenharmony_ci		regs[0x11] = 0x00; /* Green */
110962306a36Sopenharmony_ci	}
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	/* Setup pixel numbers and auto exposure window */
111262306a36Sopenharmony_ci	if (sensor_data[sd->sensor].flags & F_SIF) {
111362306a36Sopenharmony_ci		regs[0x1a] = 0x14; /* HO_SIZE 640, makes no sense */
111462306a36Sopenharmony_ci		regs[0x1b] = 0x0a; /* VO_SIZE 320, makes no sense */
111562306a36Sopenharmony_ci		regs[0x1c] = 0x02; /* AE H-start 64 */
111662306a36Sopenharmony_ci		regs[0x1d] = 0x02; /* AE V-start 64 */
111762306a36Sopenharmony_ci		regs[0x1e] = 0x09; /* AE H-end 288 */
111862306a36Sopenharmony_ci		regs[0x1f] = 0x07; /* AE V-end 224 */
111962306a36Sopenharmony_ci	} else {
112062306a36Sopenharmony_ci		regs[0x1a] = 0x1d; /* HO_SIZE 960, makes no sense */
112162306a36Sopenharmony_ci		regs[0x1b] = 0x10; /* VO_SIZE 512, makes no sense */
112262306a36Sopenharmony_ci		regs[0x1c] = 0x05; /* AE H-start 160 */
112362306a36Sopenharmony_ci		regs[0x1d] = 0x03; /* AE V-start 96 */
112462306a36Sopenharmony_ci		regs[0x1e] = 0x0f; /* AE H-end 480 */
112562306a36Sopenharmony_ci		regs[0x1f] = 0x0c; /* AE V-end 384 */
112662306a36Sopenharmony_ci	}
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	/* Setup the gamma table (only used with the sn9c103 bridge) */
112962306a36Sopenharmony_ci	for (i = 0; i < 16; i++)
113062306a36Sopenharmony_ci		regs[0x20 + i] = i * 16;
113162306a36Sopenharmony_ci	regs[0x20 + i] = 255;
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	/* Special cases where some regs depend on mode or bridge */
113462306a36Sopenharmony_ci	switch (sd->sensor) {
113562306a36Sopenharmony_ci	case SENSOR_TAS5130CXX:
113662306a36Sopenharmony_ci		/* FIXME / TESTME
113762306a36Sopenharmony_ci		   probably not mode specific at all most likely the upper
113862306a36Sopenharmony_ci		   nibble of 0x19 is exposure (clock divider) just as with
113962306a36Sopenharmony_ci		   the tas5110, we need someone to test this. */
114062306a36Sopenharmony_ci		regs[0x19] = mode ? 0x23 : 0x43;
114162306a36Sopenharmony_ci		break;
114262306a36Sopenharmony_ci	case SENSOR_OV7630:
114362306a36Sopenharmony_ci		/* FIXME / TESTME for some reason with the 101/102 bridge the
114462306a36Sopenharmony_ci		   clock is set to 12 Mhz (reg1 == 0x04), rather then 24.
114562306a36Sopenharmony_ci		   Also the hstart needs to go from 1 to 2 when using a 103,
114662306a36Sopenharmony_ci		   which is likely related. This does not seem right. */
114762306a36Sopenharmony_ci		if (sd->bridge == BRIDGE_103) {
114862306a36Sopenharmony_ci			regs[0x01] = 0x44; /* Select 24 Mhz clock */
114962306a36Sopenharmony_ci			regs[0x12] = 0x02; /* Set hstart to 2 */
115062306a36Sopenharmony_ci		}
115162306a36Sopenharmony_ci		break;
115262306a36Sopenharmony_ci	case SENSOR_PAS202:
115362306a36Sopenharmony_ci		/* For some unknown reason we need to increase hstart by 1 on
115462306a36Sopenharmony_ci		   the sn9c103, otherwise we get wrong colors (bayer shift). */
115562306a36Sopenharmony_ci		if (sd->bridge == BRIDGE_103)
115662306a36Sopenharmony_ci			regs[0x12] += 1;
115762306a36Sopenharmony_ci		break;
115862306a36Sopenharmony_ci	}
115962306a36Sopenharmony_ci	/* Disable compression when the raw bayer format has been selected */
116062306a36Sopenharmony_ci	if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW)
116162306a36Sopenharmony_ci		regs[0x18] &= ~0x80;
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	/* Vga mode emulation on SIF sensor? */
116462306a36Sopenharmony_ci	if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_REDUCED_SIF) {
116562306a36Sopenharmony_ci		regs[0x12] += 16;	/* hstart adjust */
116662306a36Sopenharmony_ci		regs[0x13] += 24;	/* vstart adjust */
116762306a36Sopenharmony_ci		regs[0x15]  = 320 / 16; /* hsize */
116862306a36Sopenharmony_ci		regs[0x16]  = 240 / 16; /* vsize */
116962306a36Sopenharmony_ci	}
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	/* reg 0x01 bit 2 video transfert on */
117262306a36Sopenharmony_ci	reg_w(gspca_dev, 0x01, &regs[0x01], 1);
117362306a36Sopenharmony_ci	/* reg 0x17 SensorClk enable inv Clk 0x60 */
117462306a36Sopenharmony_ci	reg_w(gspca_dev, 0x17, &regs[0x17], 1);
117562306a36Sopenharmony_ci	/* Set the registers from the template */
117662306a36Sopenharmony_ci	reg_w(gspca_dev, 0x01, &regs[0x01],
117762306a36Sopenharmony_ci	      (sd->bridge == BRIDGE_103) ? 0x30 : 0x1f);
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	/* Init the sensor */
118062306a36Sopenharmony_ci	i2c_w_vector(gspca_dev, sensor_data[sd->sensor].sensor_init,
118162306a36Sopenharmony_ci			sensor_data[sd->sensor].sensor_init_size);
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	/* Mode / bridge specific sensor setup */
118462306a36Sopenharmony_ci	switch (sd->sensor) {
118562306a36Sopenharmony_ci	case SENSOR_PAS202: {
118662306a36Sopenharmony_ci		const __u8 i2cpclockdiv[] =
118762306a36Sopenharmony_ci			{0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10};
118862306a36Sopenharmony_ci		/* clockdiv from 4 to 3 (7.5 -> 10 fps) when in low res mode */
118962306a36Sopenharmony_ci		if (mode)
119062306a36Sopenharmony_ci			i2c_w(gspca_dev, i2cpclockdiv);
119162306a36Sopenharmony_ci		break;
119262306a36Sopenharmony_ci	    }
119362306a36Sopenharmony_ci	case SENSOR_OV7630:
119462306a36Sopenharmony_ci		/* FIXME / TESTME We should be able to handle this identical
119562306a36Sopenharmony_ci		   for the 101/102 and the 103 case */
119662306a36Sopenharmony_ci		if (sd->bridge == BRIDGE_103) {
119762306a36Sopenharmony_ci			const __u8 i2c[] = { 0xa0, 0x21, 0x13,
119862306a36Sopenharmony_ci					     0x80, 0x00, 0x00, 0x00, 0x10 };
119962306a36Sopenharmony_ci			i2c_w(gspca_dev, i2c);
120062306a36Sopenharmony_ci		}
120162306a36Sopenharmony_ci		break;
120262306a36Sopenharmony_ci	}
120362306a36Sopenharmony_ci	/* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */
120462306a36Sopenharmony_ci	reg_w(gspca_dev, 0x15, &regs[0x15], 2);
120562306a36Sopenharmony_ci	/* compression register */
120662306a36Sopenharmony_ci	reg_w(gspca_dev, 0x18, &regs[0x18], 1);
120762306a36Sopenharmony_ci	/* H_start */
120862306a36Sopenharmony_ci	reg_w(gspca_dev, 0x12, &regs[0x12], 1);
120962306a36Sopenharmony_ci	/* V_START */
121062306a36Sopenharmony_ci	reg_w(gspca_dev, 0x13, &regs[0x13], 1);
121162306a36Sopenharmony_ci	/* reset 0x17 SensorClk enable inv Clk 0x60 */
121262306a36Sopenharmony_ci				/*fixme: ov7630 [17]=68 8f (+20 if 102)*/
121362306a36Sopenharmony_ci	reg_w(gspca_dev, 0x17, &regs[0x17], 1);
121462306a36Sopenharmony_ci	/*MCKSIZE ->3 */	/*fixme: not ov7630*/
121562306a36Sopenharmony_ci	reg_w(gspca_dev, 0x19, &regs[0x19], 1);
121662306a36Sopenharmony_ci	/* AE_STRX AE_STRY AE_ENDX AE_ENDY */
121762306a36Sopenharmony_ci	reg_w(gspca_dev, 0x1c, &regs[0x1c], 4);
121862306a36Sopenharmony_ci	/* Enable video transfert */
121962306a36Sopenharmony_ci	reg_w(gspca_dev, 0x01, &regs[0x01], 1);
122062306a36Sopenharmony_ci	/* Compression */
122162306a36Sopenharmony_ci	reg_w(gspca_dev, 0x18, &regs[0x18], 2);
122262306a36Sopenharmony_ci	msleep(20);
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	sd->reg11 = -1;
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	setgain(gspca_dev);
122762306a36Sopenharmony_ci	setbrightness(gspca_dev);
122862306a36Sopenharmony_ci	setexposure(gspca_dev);
122962306a36Sopenharmony_ci	setfreq(gspca_dev);
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	sd->frames_to_drop = 0;
123262306a36Sopenharmony_ci	sd->autogain_ignore_frames = 0;
123362306a36Sopenharmony_ci	gspca_dev->exp_too_high_cnt = 0;
123462306a36Sopenharmony_ci	gspca_dev->exp_too_low_cnt = 0;
123562306a36Sopenharmony_ci	atomic_set(&sd->avg_lum, -1);
123662306a36Sopenharmony_ci	return gspca_dev->usb_err;
123762306a36Sopenharmony_ci}
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_cistatic void sd_stopN(struct gspca_dev *gspca_dev)
124062306a36Sopenharmony_ci{
124162306a36Sopenharmony_ci	sd_init(gspca_dev);
124262306a36Sopenharmony_ci}
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_cistatic u8* find_sof(struct gspca_dev *gspca_dev, u8 *data, int len)
124562306a36Sopenharmony_ci{
124662306a36Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
124762306a36Sopenharmony_ci	int i, header_size = (sd->bridge == BRIDGE_103) ? 18 : 12;
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	/* frames start with:
125062306a36Sopenharmony_ci	 *	ff ff 00 c4 c4 96	synchro
125162306a36Sopenharmony_ci	 *	00		(unknown)
125262306a36Sopenharmony_ci	 *	xx		(frame sequence / size / compression)
125362306a36Sopenharmony_ci	 *	(xx)		(idem - extra byte for sn9c103)
125462306a36Sopenharmony_ci	 *	ll mm		brightness sum inside auto exposure
125562306a36Sopenharmony_ci	 *	ll mm		brightness sum outside auto exposure
125662306a36Sopenharmony_ci	 *	(xx xx xx xx xx)	audio values for snc103
125762306a36Sopenharmony_ci	 */
125862306a36Sopenharmony_ci	for (i = 0; i < len; i++) {
125962306a36Sopenharmony_ci		switch (sd->header_read) {
126062306a36Sopenharmony_ci		case 0:
126162306a36Sopenharmony_ci			if (data[i] == 0xff)
126262306a36Sopenharmony_ci				sd->header_read++;
126362306a36Sopenharmony_ci			break;
126462306a36Sopenharmony_ci		case 1:
126562306a36Sopenharmony_ci			if (data[i] == 0xff)
126662306a36Sopenharmony_ci				sd->header_read++;
126762306a36Sopenharmony_ci			else
126862306a36Sopenharmony_ci				sd->header_read = 0;
126962306a36Sopenharmony_ci			break;
127062306a36Sopenharmony_ci		case 2:
127162306a36Sopenharmony_ci			if (data[i] == 0x00)
127262306a36Sopenharmony_ci				sd->header_read++;
127362306a36Sopenharmony_ci			else if (data[i] != 0xff)
127462306a36Sopenharmony_ci				sd->header_read = 0;
127562306a36Sopenharmony_ci			break;
127662306a36Sopenharmony_ci		case 3:
127762306a36Sopenharmony_ci			if (data[i] == 0xc4)
127862306a36Sopenharmony_ci				sd->header_read++;
127962306a36Sopenharmony_ci			else if (data[i] == 0xff)
128062306a36Sopenharmony_ci				sd->header_read = 1;
128162306a36Sopenharmony_ci			else
128262306a36Sopenharmony_ci				sd->header_read = 0;
128362306a36Sopenharmony_ci			break;
128462306a36Sopenharmony_ci		case 4:
128562306a36Sopenharmony_ci			if (data[i] == 0xc4)
128662306a36Sopenharmony_ci				sd->header_read++;
128762306a36Sopenharmony_ci			else if (data[i] == 0xff)
128862306a36Sopenharmony_ci				sd->header_read = 1;
128962306a36Sopenharmony_ci			else
129062306a36Sopenharmony_ci				sd->header_read = 0;
129162306a36Sopenharmony_ci			break;
129262306a36Sopenharmony_ci		case 5:
129362306a36Sopenharmony_ci			if (data[i] == 0x96)
129462306a36Sopenharmony_ci				sd->header_read++;
129562306a36Sopenharmony_ci			else if (data[i] == 0xff)
129662306a36Sopenharmony_ci				sd->header_read = 1;
129762306a36Sopenharmony_ci			else
129862306a36Sopenharmony_ci				sd->header_read = 0;
129962306a36Sopenharmony_ci			break;
130062306a36Sopenharmony_ci		default:
130162306a36Sopenharmony_ci			sd->header[sd->header_read - 6] = data[i];
130262306a36Sopenharmony_ci			sd->header_read++;
130362306a36Sopenharmony_ci			if (sd->header_read == header_size) {
130462306a36Sopenharmony_ci				sd->header_read = 0;
130562306a36Sopenharmony_ci				return data + i + 1;
130662306a36Sopenharmony_ci			}
130762306a36Sopenharmony_ci		}
130862306a36Sopenharmony_ci	}
130962306a36Sopenharmony_ci	return NULL;
131062306a36Sopenharmony_ci}
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_cistatic void sd_pkt_scan(struct gspca_dev *gspca_dev,
131362306a36Sopenharmony_ci			u8 *data,			/* isoc packet */
131462306a36Sopenharmony_ci			int len)			/* iso packet length */
131562306a36Sopenharmony_ci{
131662306a36Sopenharmony_ci	int fr_h_sz = 0, lum_offset = 0, len_after_sof = 0;
131762306a36Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
131862306a36Sopenharmony_ci	struct cam *cam = &gspca_dev->cam;
131962306a36Sopenharmony_ci	u8 *sof;
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	sof = find_sof(gspca_dev, data, len);
132262306a36Sopenharmony_ci	if (sof) {
132362306a36Sopenharmony_ci		if (sd->bridge == BRIDGE_103) {
132462306a36Sopenharmony_ci			fr_h_sz = 18;
132562306a36Sopenharmony_ci			lum_offset = 3;
132662306a36Sopenharmony_ci		} else {
132762306a36Sopenharmony_ci			fr_h_sz = 12;
132862306a36Sopenharmony_ci			lum_offset = 2;
132962306a36Sopenharmony_ci		}
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci		len_after_sof = len - (sof - data);
133262306a36Sopenharmony_ci		len = (sof - data) - fr_h_sz;
133362306a36Sopenharmony_ci		if (len < 0)
133462306a36Sopenharmony_ci			len = 0;
133562306a36Sopenharmony_ci	}
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) {
133862306a36Sopenharmony_ci		/* In raw mode we sometimes get some garbage after the frame
133962306a36Sopenharmony_ci		   ignore this */
134062306a36Sopenharmony_ci		int used;
134162306a36Sopenharmony_ci		int size = cam->cam_mode[gspca_dev->curr_mode].sizeimage;
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci		used = gspca_dev->image_len;
134462306a36Sopenharmony_ci		if (used + len > size)
134562306a36Sopenharmony_ci			len = size - used;
134662306a36Sopenharmony_ci	}
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	if (sof) {
135162306a36Sopenharmony_ci		int  lum = sd->header[lum_offset] +
135262306a36Sopenharmony_ci			  (sd->header[lum_offset + 1] << 8);
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci		/* When exposure changes midway a frame we
135562306a36Sopenharmony_ci		   get a lum of 0 in this case drop 2 frames
135662306a36Sopenharmony_ci		   as the frames directly after an exposure
135762306a36Sopenharmony_ci		   change have an unstable image. Sometimes lum
135862306a36Sopenharmony_ci		   *really* is 0 (cam used in low light with
135962306a36Sopenharmony_ci		   low exposure setting), so do not drop frames
136062306a36Sopenharmony_ci		   if the previous lum was 0 too. */
136162306a36Sopenharmony_ci		if (lum == 0 && sd->prev_avg_lum != 0) {
136262306a36Sopenharmony_ci			lum = -1;
136362306a36Sopenharmony_ci			sd->frames_to_drop = 2;
136462306a36Sopenharmony_ci			sd->prev_avg_lum = 0;
136562306a36Sopenharmony_ci		} else
136662306a36Sopenharmony_ci			sd->prev_avg_lum = lum;
136762306a36Sopenharmony_ci		atomic_set(&sd->avg_lum, lum);
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci		if (sd->frames_to_drop)
137062306a36Sopenharmony_ci			sd->frames_to_drop--;
137162306a36Sopenharmony_ci		else
137262306a36Sopenharmony_ci			gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci		gspca_frame_add(gspca_dev, FIRST_PACKET, sof, len_after_sof);
137562306a36Sopenharmony_ci	}
137662306a36Sopenharmony_ci}
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_INPUT)
137962306a36Sopenharmony_cistatic int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
138062306a36Sopenharmony_ci			u8 *data,		/* interrupt packet data */
138162306a36Sopenharmony_ci			int len)		/* interrupt packet length */
138262306a36Sopenharmony_ci{
138362306a36Sopenharmony_ci	int ret = -EINVAL;
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	if (len == 1 && data[0] == 1) {
138662306a36Sopenharmony_ci		input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
138762306a36Sopenharmony_ci		input_sync(gspca_dev->input_dev);
138862306a36Sopenharmony_ci		input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
138962306a36Sopenharmony_ci		input_sync(gspca_dev->input_dev);
139062306a36Sopenharmony_ci		ret = 0;
139162306a36Sopenharmony_ci	}
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	return ret;
139462306a36Sopenharmony_ci}
139562306a36Sopenharmony_ci#endif
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci/* sub-driver description */
139862306a36Sopenharmony_cistatic const struct sd_desc sd_desc = {
139962306a36Sopenharmony_ci	.name = MODULE_NAME,
140062306a36Sopenharmony_ci	.config = sd_config,
140162306a36Sopenharmony_ci	.init = sd_init,
140262306a36Sopenharmony_ci	.init_controls = sd_init_controls,
140362306a36Sopenharmony_ci	.start = sd_start,
140462306a36Sopenharmony_ci	.stopN = sd_stopN,
140562306a36Sopenharmony_ci	.pkt_scan = sd_pkt_scan,
140662306a36Sopenharmony_ci	.dq_callback = do_autogain,
140762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_INPUT)
140862306a36Sopenharmony_ci	.int_pkt_scan = sd_int_pkt_scan,
140962306a36Sopenharmony_ci#endif
141062306a36Sopenharmony_ci};
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci/* -- module initialisation -- */
141362306a36Sopenharmony_ci#define SB(sensor, bridge) \
141462306a36Sopenharmony_ci	.driver_info = (SENSOR_ ## sensor << 8) | BRIDGE_ ## bridge
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_cistatic const struct usb_device_id device_table[] = {
141862306a36Sopenharmony_ci	{USB_DEVICE(0x0c45, 0x6001), SB(TAS5110C, 102)}, /* TAS5110C1B */
141962306a36Sopenharmony_ci	{USB_DEVICE(0x0c45, 0x6005), SB(TAS5110C, 101)}, /* TAS5110C1B */
142062306a36Sopenharmony_ci	{USB_DEVICE(0x0c45, 0x6007), SB(TAS5110D, 101)}, /* TAS5110D */
142162306a36Sopenharmony_ci	{USB_DEVICE(0x0c45, 0x6009), SB(PAS106, 101)},
142262306a36Sopenharmony_ci	{USB_DEVICE(0x0c45, 0x600d), SB(PAS106, 101)},
142362306a36Sopenharmony_ci	{USB_DEVICE(0x0c45, 0x6011), SB(OV6650, 101)},
142462306a36Sopenharmony_ci	{USB_DEVICE(0x0c45, 0x6019), SB(OV7630, 101)},
142562306a36Sopenharmony_ci	{USB_DEVICE(0x0c45, 0x6024), SB(TAS5130CXX, 102)},
142662306a36Sopenharmony_ci	{USB_DEVICE(0x0c45, 0x6025), SB(TAS5130CXX, 102)},
142762306a36Sopenharmony_ci	{USB_DEVICE(0x0c45, 0x6027), SB(OV7630, 101)}, /* Genius Eye 310 */
142862306a36Sopenharmony_ci	{USB_DEVICE(0x0c45, 0x6028), SB(PAS202, 102)},
142962306a36Sopenharmony_ci	{USB_DEVICE(0x0c45, 0x6029), SB(PAS106, 102)},
143062306a36Sopenharmony_ci	{USB_DEVICE(0x0c45, 0x602a), SB(HV7131D, 102)},
143162306a36Sopenharmony_ci	/* {USB_DEVICE(0x0c45, 0x602b), SB(MI0343, 102)}, */
143262306a36Sopenharmony_ci	{USB_DEVICE(0x0c45, 0x602c), SB(OV7630, 102)},
143362306a36Sopenharmony_ci	{USB_DEVICE(0x0c45, 0x602d), SB(HV7131R, 102)},
143462306a36Sopenharmony_ci	{USB_DEVICE(0x0c45, 0x602e), SB(OV7630, 102)},
143562306a36Sopenharmony_ci	/* {USB_DEVICE(0x0c45, 0x6030), SB(MI03XX, 102)}, */ /* MI0343 MI0360 MI0330 */
143662306a36Sopenharmony_ci	/* {USB_DEVICE(0x0c45, 0x6082), SB(MI03XX, 103)}, */ /* MI0343 MI0360 */
143762306a36Sopenharmony_ci	{USB_DEVICE(0x0c45, 0x6083), SB(HV7131D, 103)},
143862306a36Sopenharmony_ci	{USB_DEVICE(0x0c45, 0x608c), SB(HV7131R, 103)},
143962306a36Sopenharmony_ci	/* {USB_DEVICE(0x0c45, 0x608e), SB(CISVF10, 103)}, */
144062306a36Sopenharmony_ci	{USB_DEVICE(0x0c45, 0x608f), SB(OV7630, 103)},
144162306a36Sopenharmony_ci	{USB_DEVICE(0x0c45, 0x60a8), SB(PAS106, 103)},
144262306a36Sopenharmony_ci	{USB_DEVICE(0x0c45, 0x60aa), SB(TAS5130CXX, 103)},
144362306a36Sopenharmony_ci	{USB_DEVICE(0x0c45, 0x60af), SB(PAS202, 103)},
144462306a36Sopenharmony_ci	{USB_DEVICE(0x0c45, 0x60b0), SB(OV7630, 103)},
144562306a36Sopenharmony_ci	{}
144662306a36Sopenharmony_ci};
144762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, device_table);
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci/* -- device connect -- */
145062306a36Sopenharmony_cistatic int sd_probe(struct usb_interface *intf,
145162306a36Sopenharmony_ci			const struct usb_device_id *id)
145262306a36Sopenharmony_ci{
145362306a36Sopenharmony_ci	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
145462306a36Sopenharmony_ci				THIS_MODULE);
145562306a36Sopenharmony_ci}
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_cistatic struct usb_driver sd_driver = {
145862306a36Sopenharmony_ci	.name = MODULE_NAME,
145962306a36Sopenharmony_ci	.id_table = device_table,
146062306a36Sopenharmony_ci	.probe = sd_probe,
146162306a36Sopenharmony_ci	.disconnect = gspca_disconnect,
146262306a36Sopenharmony_ci#ifdef CONFIG_PM
146362306a36Sopenharmony_ci	.suspend = gspca_suspend,
146462306a36Sopenharmony_ci	.resume = gspca_resume,
146562306a36Sopenharmony_ci	.reset_resume = gspca_resume,
146662306a36Sopenharmony_ci#endif
146762306a36Sopenharmony_ci};
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_cimodule_usb_driver(sd_driver);
1470