xref: /linux/drivers/media/usb/gspca/t613.c (revision 58e16d792a6a8c6b750f637a4649967fcac853dc)
1*fd9871f7SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
26a7eba24SJean-Francois Moine /*
3cd8955b8SJean-François Moine  * T613 subdriver
4cd8955b8SJean-François Moine  *
5cd8955b8SJean-François Moine  * Copyright (C) 2010 Jean-Francois Moine (http://moinejf.free.fr)
66a7eba24SJean-Francois Moine  *
710b0e96eSJean-Francois Moine  *Notes: * t613  + tas5130A
810b0e96eSJean-Francois Moine  *	* Focus to light do not balance well as in win.
910b0e96eSJean-Francois Moine  *	  Quality in win is not good, but its kinda better.
1010b0e96eSJean-Francois Moine  *	 * Fix some "extraneous bytes", most of apps will show the image anyway
1110b0e96eSJean-Francois Moine  *	 * Gamma table, is there, but its really doing something?
1210b0e96eSJean-Francois Moine  *	 * 7~8 Fps, its ok, max on win its 10.
1310b0e96eSJean-Francois Moine  *			Costantino Leandro
146a7eba24SJean-Francois Moine  */
156a7eba24SJean-Francois Moine 
161b19e429SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
171b19e429SJoe Perches 
186a7eba24SJean-Francois Moine #define MODULE_NAME "t613"
1910b0e96eSJean-Francois Moine 
20ee186fd9SHans de Goede #include <linux/input.h>
21be2a9faeSJean-François Moine #include <linux/slab.h>
226a7eba24SJean-Francois Moine #include "gspca.h"
236a7eba24SJean-Francois Moine 
246a7eba24SJean-Francois Moine MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>");
256a7eba24SJean-Francois Moine MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver");
266a7eba24SJean-Francois Moine MODULE_LICENSE("GPL");
276a7eba24SJean-Francois Moine 
286a7eba24SJean-Francois Moine struct sd {
296a7eba24SJean-Francois Moine 	struct gspca_dev gspca_dev;	/* !! must be the first item */
309bf81642SHans Verkuil 	struct v4l2_ctrl *freq;
319bf81642SHans Verkuil 	struct { /* awb / color gains control cluster */
329bf81642SHans Verkuil 		struct v4l2_ctrl *awb;
339bf81642SHans Verkuil 		struct v4l2_ctrl *gain;
349bf81642SHans Verkuil 		struct v4l2_ctrl *red_balance;
359bf81642SHans Verkuil 		struct v4l2_ctrl *blue_balance;
369bf81642SHans Verkuil 	};
37fadc7993SJean-Francois Moine 
3882e25491SJean-Francois Moine 	u8 sensor;
39ee186fd9SHans de Goede 	u8 button_pressed;
4011ce884aSJean-François Moine };
4111ce884aSJean-François Moine enum sensors {
42cd8955b8SJean-François Moine 	SENSOR_OM6802,
43cd8955b8SJean-François Moine 	SENSOR_OTHER,
44cd8955b8SJean-François Moine 	SENSOR_TAS5130A,
45cd8955b8SJean-François Moine 	SENSOR_LT168G,		/* must verify if this is the actual model */
466a7eba24SJean-Francois Moine };
476a7eba24SJean-Francois Moine 
48cc611b8aSJean-Francois Moine static const struct v4l2_pix_format vga_mode_t16[] = {
49c2446b3eSJean-Francois Moine 	{160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
50c2446b3eSJean-Francois Moine 		.bytesperline = 160,
515d05294aSJean-Francois Moine 		.sizeimage = 160 * 120 * 4 / 8 + 590,
52c2446b3eSJean-Francois Moine 		.colorspace = V4L2_COLORSPACE_JPEG,
53c2446b3eSJean-Francois Moine 		.priv = 4},
541ea172d2SHans de Goede #if 0 /* HDG: broken with my test cam, so lets disable it */
55c2446b3eSJean-Francois Moine 	{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
56c2446b3eSJean-Francois Moine 		.bytesperline = 176,
57c2446b3eSJean-Francois Moine 		.sizeimage = 176 * 144 * 3 / 8 + 590,
58c2446b3eSJean-Francois Moine 		.colorspace = V4L2_COLORSPACE_JPEG,
59c2446b3eSJean-Francois Moine 		.priv = 3},
601ea172d2SHans de Goede #endif
61c2446b3eSJean-Francois Moine 	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
62c2446b3eSJean-Francois Moine 		.bytesperline = 320,
63c2446b3eSJean-Francois Moine 		.sizeimage = 320 * 240 * 3 / 8 + 590,
64c2446b3eSJean-Francois Moine 		.colorspace = V4L2_COLORSPACE_JPEG,
65c2446b3eSJean-Francois Moine 		.priv = 2},
661ea172d2SHans de Goede #if 0 /* HDG: broken with my test cam, so lets disable it */
67c2446b3eSJean-Francois Moine 	{352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
68c2446b3eSJean-Francois Moine 		.bytesperline = 352,
69c2446b3eSJean-Francois Moine 		.sizeimage = 352 * 288 * 3 / 8 + 590,
70c2446b3eSJean-Francois Moine 		.colorspace = V4L2_COLORSPACE_JPEG,
71c2446b3eSJean-Francois Moine 		.priv = 1},
721ea172d2SHans de Goede #endif
73c2446b3eSJean-Francois Moine 	{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
74c2446b3eSJean-Francois Moine 		.bytesperline = 640,
75c2446b3eSJean-Francois Moine 		.sizeimage = 640 * 480 * 3 / 8 + 590,
76c2446b3eSJean-Francois Moine 		.colorspace = V4L2_COLORSPACE_JPEG,
77c2446b3eSJean-Francois Moine 		.priv = 0},
786a7eba24SJean-Francois Moine };
796a7eba24SJean-Francois Moine 
80ad62fb08SLeandro Costantino /* sensor specific data */
81ad62fb08SLeandro Costantino struct additional_sensor_data {
8278a6d74eSJean-Francois Moine 	const u8 n3[6];
8378a6d74eSJean-Francois Moine 	const u8 *n4, n4sz;
8478a6d74eSJean-Francois Moine 	const u8 reg80, reg8e;
8578a6d74eSJean-Francois Moine 	const u8 nset8[6];
8682e25491SJean-Francois Moine 	const u8 data1[10];
8782e25491SJean-Francois Moine 	const u8 data2[9];
8882e25491SJean-Francois Moine 	const u8 data3[9];
8982e25491SJean-Francois Moine 	const u8 data5[6];
9082e25491SJean-Francois Moine 	const u8 stream[4];
91ad62fb08SLeandro Costantino };
92ad62fb08SLeandro Costantino 
9378a6d74eSJean-Francois Moine static const u8 n4_om6802[] = {
9478a6d74eSJean-Francois Moine 	0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,
9578a6d74eSJean-Francois Moine 	0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,
9678a6d74eSJean-Francois Moine 	0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,
9778a6d74eSJean-Francois Moine 	0xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8,
9878a6d74eSJean-Francois Moine 	0xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48,
9978a6d74eSJean-Francois Moine 	0xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0,
10078a6d74eSJean-Francois Moine 	0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
10178a6d74eSJean-Francois Moine 	0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
10278a6d74eSJean-Francois Moine 	0xac, 0x84, 0xad, 0x86, 0xaf, 0x46
10378a6d74eSJean-Francois Moine };
10478a6d74eSJean-Francois Moine static const u8 n4_other[] = {
10578a6d74eSJean-Francois Moine 	0x66, 0x00, 0x7f, 0x00, 0x80, 0xac, 0x81, 0x69,
10678a6d74eSJean-Francois Moine 	0x84, 0x40, 0x85, 0x70, 0x86, 0x20, 0x8a, 0x68,
10778a6d74eSJean-Francois Moine 	0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xff, 0x8e, 0xb8,
10878a6d74eSJean-Francois Moine 	0x8f, 0x28, 0xa2, 0x60, 0xa5, 0x40, 0xa8, 0xa8,
10978a6d74eSJean-Francois Moine 	0xac, 0x84, 0xad, 0x84, 0xae, 0x24, 0xaf, 0x56,
11078a6d74eSJean-Francois Moine 	0xb0, 0x68, 0xb1, 0x00, 0xb2, 0x88, 0xbb, 0xc5,
11178a6d74eSJean-Francois Moine 	0xbc, 0x4a, 0xbe, 0x36, 0xc2, 0x88, 0xc5, 0xc0,
11278a6d74eSJean-Francois Moine 	0xc6, 0xda, 0xe9, 0x26, 0xeb, 0x00
11378a6d74eSJean-Francois Moine };
11478a6d74eSJean-Francois Moine static const u8 n4_tas5130a[] = {
11578a6d74eSJean-Francois Moine 	0x80, 0x3c, 0x81, 0x68, 0x83, 0xa0, 0x84, 0x20,
11678a6d74eSJean-Francois Moine 	0x8a, 0x68, 0x8b, 0x58, 0x8c, 0x88, 0x8e, 0xb4,
11778a6d74eSJean-Francois Moine 	0x8f, 0x24, 0xa1, 0xb1, 0xa2, 0x30, 0xa5, 0x10,
11878a6d74eSJean-Francois Moine 	0xa6, 0x4a, 0xae, 0x03, 0xb1, 0x44, 0xb2, 0x08,
11978a6d74eSJean-Francois Moine 	0xb7, 0x06, 0xb9, 0xe7, 0xbb, 0xc4, 0xbc, 0x4a,
12078a6d74eSJean-Francois Moine 	0xbe, 0x36, 0xbf, 0xff, 0xc2, 0x88, 0xc5, 0xc8,
12178a6d74eSJean-Francois Moine 	0xc6, 0xda
12278a6d74eSJean-Francois Moine };
12300e8006dSNicolau Werneck static const u8 n4_lt168g[] = {
12400e8006dSNicolau Werneck 	0x66, 0x01, 0x7f, 0x00, 0x80, 0x7c, 0x81, 0x28,
12500e8006dSNicolau Werneck 	0x83, 0x44, 0x84, 0x20, 0x86, 0x20, 0x8a, 0x70,
12600e8006dSNicolau Werneck 	0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xa0, 0x8e, 0xb3,
12700e8006dSNicolau Werneck 	0x8f, 0x24, 0xa1, 0xb0, 0xa2, 0x38, 0xa5, 0x20,
12800e8006dSNicolau Werneck 	0xa6, 0x4a, 0xa8, 0xe8, 0xaf, 0x38, 0xb0, 0x68,
12900e8006dSNicolau Werneck 	0xb1, 0x44, 0xb2, 0x88, 0xbb, 0x86, 0xbd, 0x40,
13000e8006dSNicolau Werneck 	0xbe, 0x26, 0xc1, 0x05, 0xc2, 0x88, 0xc5, 0xc0,
13100e8006dSNicolau Werneck 	0xda, 0x8e, 0xdb, 0xca, 0xdc, 0xa8, 0xdd, 0x8c,
13200e8006dSNicolau Werneck 	0xde, 0x44, 0xdf, 0x0c, 0xe9, 0x80
13300e8006dSNicolau Werneck };
13478a6d74eSJean-Francois Moine 
135e23b2907STobias Klauser static const struct additional_sensor_data sensor_data[] = {
136cd8955b8SJean-François Moine [SENSOR_OM6802] = {
13778a6d74eSJean-Francois Moine 	.n3 =
13878a6d74eSJean-Francois Moine 		{0x61, 0x68, 0x65, 0x0a, 0x60, 0x04},
13978a6d74eSJean-Francois Moine 	.n4 = n4_om6802,
14078a6d74eSJean-Francois Moine 	.n4sz = sizeof n4_om6802,
14178a6d74eSJean-Francois Moine 	.reg80 = 0x3c,
14278a6d74eSJean-Francois Moine 	.reg8e = 0x33,
14378a6d74eSJean-Francois Moine 	.nset8 = {0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00},
1442d56f3bbSJean-Francois Moine 	.data1 =
1452d56f3bbSJean-Francois Moine 		{0xc2, 0x28, 0x0f, 0x22, 0xcd, 0x27, 0x2c, 0x06,
1462d56f3bbSJean-Francois Moine 		 0xb3, 0xfc},
1472d56f3bbSJean-Francois Moine 	.data2 =
1482d56f3bbSJean-Francois Moine 		{0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
1492d56f3bbSJean-Francois Moine 		 0xff},
15078a6d74eSJean-Francois Moine 	.data3 =
15178a6d74eSJean-Francois Moine 		{0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
15278a6d74eSJean-Francois Moine 		 0xff},
1532d56f3bbSJean-Francois Moine 	.data5 =	/* this could be removed later */
1542d56f3bbSJean-Francois Moine 		{0x0c, 0x03, 0xab, 0x13, 0x81, 0x23},
1552d56f3bbSJean-Francois Moine 	.stream =
1562d56f3bbSJean-Francois Moine 		{0x0b, 0x04, 0x0a, 0x78},
1572d56f3bbSJean-Francois Moine     },
158cd8955b8SJean-François Moine [SENSOR_OTHER] = {
15978a6d74eSJean-Francois Moine 	.n3 =
16078a6d74eSJean-Francois Moine 		{0x61, 0xc2, 0x65, 0x88, 0x60, 0x00},
16178a6d74eSJean-Francois Moine 	.n4 = n4_other,
16278a6d74eSJean-Francois Moine 	.n4sz = sizeof n4_other,
16378a6d74eSJean-Francois Moine 	.reg80 = 0xac,
16478a6d74eSJean-Francois Moine 	.reg8e = 0xb8,
16578a6d74eSJean-Francois Moine 	.nset8 = {0xa8, 0xa8, 0xc6, 0xda, 0xc0, 0x00},
1662d56f3bbSJean-Francois Moine 	.data1 =
1672d56f3bbSJean-Francois Moine 		{0xc1, 0x48, 0x04, 0x1b, 0xca, 0x2e, 0x33, 0x3a,
1682d56f3bbSJean-Francois Moine 		 0xe8, 0xfc},
1692d56f3bbSJean-Francois Moine 	.data2 =
1702d56f3bbSJean-Francois Moine 		{0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
1712d56f3bbSJean-Francois Moine 		 0xd9},
17278a6d74eSJean-Francois Moine 	.data3 =
17378a6d74eSJean-Francois Moine 		{0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
17478a6d74eSJean-Francois Moine 		 0xd9},
1752d56f3bbSJean-Francois Moine 	.data5 =
1762d56f3bbSJean-Francois Moine 		{0x0c, 0x03, 0xab, 0x29, 0x81, 0x69},
1772d56f3bbSJean-Francois Moine 	.stream =
1782d56f3bbSJean-Francois Moine 		{0x0b, 0x04, 0x0a, 0x00},
1792d56f3bbSJean-Francois Moine     },
180cd8955b8SJean-François Moine [SENSOR_TAS5130A] = {
18178a6d74eSJean-Francois Moine 	.n3 =
18278a6d74eSJean-Francois Moine 		{0x61, 0xc2, 0x65, 0x0d, 0x60, 0x08},
18378a6d74eSJean-Francois Moine 	.n4 = n4_tas5130a,
18478a6d74eSJean-Francois Moine 	.n4sz = sizeof n4_tas5130a,
18578a6d74eSJean-Francois Moine 	.reg80 = 0x3c,
18678a6d74eSJean-Francois Moine 	.reg8e = 0xb4,
18778a6d74eSJean-Francois Moine 	.nset8 = {0xa8, 0xf0, 0xc6, 0xda, 0xc0, 0x00},
188ad62fb08SLeandro Costantino 	.data1 =
18982e25491SJean-Francois Moine 		{0xbb, 0x28, 0x10, 0x10, 0xbb, 0x28, 0x1e, 0x27,
19082e25491SJean-Francois Moine 		 0xc8, 0xfc},
191ad62fb08SLeandro Costantino 	.data2 =
19282e25491SJean-Francois Moine 		{0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
19382e25491SJean-Francois Moine 		 0xe0},
19478a6d74eSJean-Francois Moine 	.data3 =
19578a6d74eSJean-Francois Moine 		{0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
19678a6d74eSJean-Francois Moine 		 0xe0},
197ad62fb08SLeandro Costantino 	.data5 =
198ad62fb08SLeandro Costantino 		{0x0c, 0x03, 0xab, 0x10, 0x81, 0x20},
199ad62fb08SLeandro Costantino 	.stream =
200ad62fb08SLeandro Costantino 		{0x0b, 0x04, 0x0a, 0x40},
201ad62fb08SLeandro Costantino     },
202cd8955b8SJean-François Moine [SENSOR_LT168G] = {
20300e8006dSNicolau Werneck 	.n3 = {0x61, 0xc2, 0x65, 0x68, 0x60, 0x00},
20400e8006dSNicolau Werneck 	.n4 = n4_lt168g,
20500e8006dSNicolau Werneck 	.n4sz = sizeof n4_lt168g,
20600e8006dSNicolau Werneck 	.reg80 = 0x7c,
20700e8006dSNicolau Werneck 	.reg8e = 0xb3,
20800e8006dSNicolau Werneck 	.nset8 = {0xa8, 0xf0, 0xc6, 0xba, 0xc0, 0x00},
20900e8006dSNicolau Werneck 	.data1 = {0xc0, 0x38, 0x08, 0x10, 0xc0, 0x30, 0x10, 0x40,
21000e8006dSNicolau Werneck 		 0xb0, 0xf4},
21100e8006dSNicolau Werneck 	.data2 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
21200e8006dSNicolau Werneck 		 0xff},
21300e8006dSNicolau Werneck 	.data3 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
21400e8006dSNicolau Werneck 		 0xff},
21500e8006dSNicolau Werneck 	.data5 = {0x0c, 0x03, 0xab, 0x4b, 0x81, 0x2b},
21600e8006dSNicolau Werneck 	.stream = {0x0b, 0x04, 0x0a, 0x28},
21700e8006dSNicolau Werneck     },
218ad62fb08SLeandro Costantino };
219ad62fb08SLeandro Costantino 
2206a7eba24SJean-Francois Moine #define MAX_EFFECTS 7
22182e25491SJean-Francois Moine static const u8 effects_table[MAX_EFFECTS][6] = {
2226a7eba24SJean-Francois Moine 	{0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00},	/* Normal */
2236a7eba24SJean-Francois Moine 	{0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04},	/* Repujar */
2246a7eba24SJean-Francois Moine 	{0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x20},	/* Monochrome */
2256a7eba24SJean-Francois Moine 	{0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x80},	/* Sepia */
2266a7eba24SJean-Francois Moine 	{0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x02},	/* Croquis */
2276a7eba24SJean-Francois Moine 	{0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x10},	/* Sun Effect */
2286a7eba24SJean-Francois Moine 	{0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40},	/* Negative */
2296a7eba24SJean-Francois Moine };
2306a7eba24SJean-Francois Moine 
2319bf81642SHans Verkuil #define GAMMA_MAX (15)
2329bf81642SHans Verkuil static const u8 gamma_table[GAMMA_MAX+1][17] = {
23379960d39SJean-François Moine /* gamma table from cam1690.ini */
23479960d39SJean-François Moine 	{0x00, 0x00, 0x01, 0x04, 0x08, 0x0e, 0x16, 0x21,	/* 0 */
23579960d39SJean-François Moine 	 0x2e, 0x3d, 0x50, 0x65, 0x7d, 0x99, 0xb8, 0xdb,
23682e25491SJean-Francois Moine 	 0xff},
23779960d39SJean-François Moine 	{0x00, 0x01, 0x03, 0x08, 0x0e, 0x16, 0x21, 0x2d,	/* 1 */
23879960d39SJean-François Moine 	 0x3c, 0x4d, 0x60, 0x75, 0x8d, 0xa6, 0xc2, 0xe1,
23982e25491SJean-Francois Moine 	 0xff},
24079960d39SJean-François Moine 	{0x00, 0x01, 0x05, 0x0b, 0x12, 0x1c, 0x28, 0x35,	/* 2 */
24179960d39SJean-François Moine 	 0x45, 0x56, 0x69, 0x7e, 0x95, 0xad, 0xc7, 0xe3,
24282e25491SJean-Francois Moine 	 0xff},
24379960d39SJean-François Moine 	{0x00, 0x02, 0x07, 0x0f, 0x18, 0x24, 0x30, 0x3f,	/* 3 */
24479960d39SJean-François Moine 	 0x4f, 0x61, 0x73, 0x88, 0x9d, 0xb4, 0xcd, 0xe6,
24582e25491SJean-Francois Moine 	 0xff},
2461d00d6c1SJean-François Moine 	{0x00, 0x04, 0x0b, 0x15, 0x20, 0x2d, 0x3b, 0x4a,	/* 4 */
24779960d39SJean-François Moine 	 0x5b, 0x6c, 0x7f, 0x92, 0xa7, 0xbc, 0xd2, 0xe9,
24882e25491SJean-Francois Moine 	 0xff},
24979960d39SJean-François Moine 	{0x00, 0x07, 0x11, 0x15, 0x20, 0x2d, 0x48, 0x58,	/* 5 */
25079960d39SJean-François Moine 	 0x68, 0x79, 0x8b, 0x9d, 0xb0, 0xc4, 0xd7, 0xec,
25182e25491SJean-Francois Moine 	 0xff},
25279960d39SJean-François Moine 	{0x00, 0x0c, 0x1a, 0x29, 0x38, 0x47, 0x57, 0x67,	/* 6 */
25382e25491SJean-Francois Moine 	 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
25482e25491SJean-Francois Moine 	 0xff},
25579960d39SJean-François Moine 	{0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,	/* 7 */
25682e25491SJean-Francois Moine 	 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
25782e25491SJean-Francois Moine 	 0xff},
25879960d39SJean-François Moine 	{0x00, 0x15, 0x27, 0x38, 0x49, 0x59, 0x69, 0x79,	/* 8 */
25979960d39SJean-François Moine 	 0x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe2, 0xf0,
26082e25491SJean-Francois Moine 	 0xff},
26179960d39SJean-François Moine 	{0x00, 0x1c, 0x30, 0x43, 0x54, 0x65, 0x75, 0x84,	/* 9 */
26279960d39SJean-François Moine 	 0x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd8, 0xe5, 0xf2,
26382e25491SJean-Francois Moine 	 0xff},
26479960d39SJean-François Moine 	{0x00, 0x24, 0x3b, 0x4f, 0x60, 0x70, 0x80, 0x8e,	/* 10 */
26579960d39SJean-François Moine 	 0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xdc, 0xe8, 0xf3,
26682e25491SJean-Francois Moine 	 0xff},
26779960d39SJean-François Moine 	{0x00, 0x2a, 0x3c, 0x5d, 0x6e, 0x7e, 0x8d, 0x9b,	/* 11 */
26882e25491SJean-Francois Moine 	 0xa8, 0xb4, 0xc0, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
26982e25491SJean-Francois Moine 	 0xff},
27082e25491SJean-Francois Moine 	{0x00, 0x3f, 0x5a, 0x6e, 0x7f, 0x8e, 0x9c, 0xa8,	/* 12 */
27182e25491SJean-Francois Moine 	 0xb4, 0xbf, 0xc9, 0xd3, 0xdc, 0xe5, 0xee, 0xf6,
27282e25491SJean-Francois Moine 	 0xff},
27382e25491SJean-Francois Moine 	{0x00, 0x54, 0x6f, 0x83, 0x93, 0xa0, 0xad, 0xb7,	/* 13 */
27482e25491SJean-Francois Moine 	 0xc2, 0xcb, 0xd4, 0xdc, 0xe4, 0xeb, 0xf2, 0xf9,
27582e25491SJean-Francois Moine 	 0xff},
27682e25491SJean-Francois Moine 	{0x00, 0x6e, 0x88, 0x9a, 0xa8, 0xb3, 0xbd, 0xc6,	/* 14 */
27782e25491SJean-Francois Moine 	 0xcf, 0xd6, 0xdd, 0xe3, 0xe9, 0xef, 0xf4, 0xfa,
27882e25491SJean-Francois Moine 	 0xff},
27982e25491SJean-Francois Moine 	{0x00, 0x93, 0xa8, 0xb7, 0xc1, 0xca, 0xd2, 0xd8,	/* 15 */
28082e25491SJean-Francois Moine 	 0xde, 0xe3, 0xe8, 0xed, 0xf1, 0xf5, 0xf8, 0xfc,
28182e25491SJean-Francois Moine 	 0xff}
2826a7eba24SJean-Francois Moine };
2836a7eba24SJean-Francois Moine 
28482e25491SJean-Francois Moine static const u8 tas5130a_sensor_init[][8] = {
2856a7eba24SJean-Francois Moine 	{0x62, 0x08, 0x63, 0x70, 0x64, 0x1d, 0x60, 0x09},
2866a7eba24SJean-Francois Moine 	{0x62, 0x20, 0x63, 0x01, 0x64, 0x02, 0x60, 0x09},
2876a7eba24SJean-Francois Moine 	{0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
2886a7eba24SJean-Francois Moine };
2896a7eba24SJean-Francois Moine 
29082e25491SJean-Francois Moine static u8 sensor_reset[] = {0x61, 0x68, 0x62, 0xff, 0x60, 0x07};
291392ee5a5SJean-Francois Moine 
292739570bbSJean-Francois Moine /* read 1 byte */
29382e25491SJean-Francois Moine static u8 reg_r(struct gspca_dev *gspca_dev,
29482e25491SJean-Francois Moine 		   u16 index)
2956a7eba24SJean-Francois Moine {
296739570bbSJean-Francois Moine 	usb_control_msg(gspca_dev->dev,
297739570bbSJean-Francois Moine 			usb_rcvctrlpipe(gspca_dev->dev, 0),
2986a7eba24SJean-Francois Moine 			0,		/* request */
2996a7eba24SJean-Francois Moine 			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
3006a7eba24SJean-Francois Moine 			0,		/* value */
301739570bbSJean-Francois Moine 			index,
302739570bbSJean-Francois Moine 			gspca_dev->usb_buf, 1, 500);
303739570bbSJean-Francois Moine 	return gspca_dev->usb_buf[0];
3046a7eba24SJean-Francois Moine }
3056a7eba24SJean-Francois Moine 
306739570bbSJean-Francois Moine static void reg_w(struct gspca_dev *gspca_dev,
30782e25491SJean-Francois Moine 		  u16 index)
3086a7eba24SJean-Francois Moine {
309739570bbSJean-Francois Moine 	usb_control_msg(gspca_dev->dev,
310739570bbSJean-Francois Moine 			usb_sndctrlpipe(gspca_dev->dev, 0),
311a5ae2062SJean-Francois Moine 			0,
3120bc99b5cSJean-Francois Moine 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
313fadc7993SJean-Francois Moine 			0, index,
314a5ae2062SJean-Francois Moine 			NULL, 0, 500);
315bf7f0b98SJean-Francois Moine }
316fadc7993SJean-Francois Moine 
317f89be036SJean-Francois Moine static void reg_w_buf(struct gspca_dev *gspca_dev,
31882e25491SJean-Francois Moine 		  const u8 *buffer, u16 len)
319fadc7993SJean-Francois Moine {
3208295d99eSJean-Francois Moine 	if (len <= USB_BUF_SZ) {
321739570bbSJean-Francois Moine 		memcpy(gspca_dev->usb_buf, buffer, len);
322739570bbSJean-Francois Moine 		usb_control_msg(gspca_dev->dev,
323739570bbSJean-Francois Moine 				usb_sndctrlpipe(gspca_dev->dev, 0),
324a5ae2062SJean-Francois Moine 				0,
3250bc99b5cSJean-Francois Moine 			   USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
326fadc7993SJean-Francois Moine 				0x01, 0,
327739570bbSJean-Francois Moine 				gspca_dev->usb_buf, len, 500);
328a5ae2062SJean-Francois Moine 	} else {
32982e25491SJean-Francois Moine 		u8 *tmpbuf;
330a5ae2062SJean-Francois Moine 
331feda79bfSJulia Lawall 		tmpbuf = kmemdup(buffer, len, GFP_KERNEL);
33224f222e7SJean-François Moine 		if (!tmpbuf) {
3331b19e429SJoe Perches 			pr_err("Out of memory\n");
33424f222e7SJean-François Moine 			return;
33524f222e7SJean-François Moine 		}
336739570bbSJean-Francois Moine 		usb_control_msg(gspca_dev->dev,
337739570bbSJean-Francois Moine 				usb_sndctrlpipe(gspca_dev->dev, 0),
338a5ae2062SJean-Francois Moine 				0,
3390bc99b5cSJean-Francois Moine 			   USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
340fadc7993SJean-Francois Moine 				0x01, 0,
341a5ae2062SJean-Francois Moine 				tmpbuf, len, 500);
342a5ae2062SJean-Francois Moine 		kfree(tmpbuf);
343a5ae2062SJean-Francois Moine 	}
3446a7eba24SJean-Francois Moine }
3456a7eba24SJean-Francois Moine 
34682e25491SJean-Francois Moine /* write values to consecutive registers */
34782e25491SJean-Francois Moine static void reg_w_ixbuf(struct gspca_dev *gspca_dev,
34882e25491SJean-Francois Moine 			u8 reg,
34982e25491SJean-Francois Moine 			const u8 *buffer, u16 len)
35082e25491SJean-Francois Moine {
35182e25491SJean-Francois Moine 	int i;
35282e25491SJean-Francois Moine 	u8 *p, *tmpbuf;
35382e25491SJean-Francois Moine 
35424f222e7SJean-François Moine 	if (len * 2 <= USB_BUF_SZ) {
35582e25491SJean-Francois Moine 		p = tmpbuf = gspca_dev->usb_buf;
35624f222e7SJean-François Moine 	} else {
3576da2ec56SKees Cook 		p = tmpbuf = kmalloc_array(len, 2, GFP_KERNEL);
35824f222e7SJean-François Moine 		if (!tmpbuf) {
3591b19e429SJoe Perches 			pr_err("Out of memory\n");
36024f222e7SJean-François Moine 			return;
36124f222e7SJean-François Moine 		}
36224f222e7SJean-François Moine 	}
36382e25491SJean-Francois Moine 	i = len;
36482e25491SJean-Francois Moine 	while (--i >= 0) {
36582e25491SJean-Francois Moine 		*p++ = reg++;
36682e25491SJean-Francois Moine 		*p++ = *buffer++;
36782e25491SJean-Francois Moine 	}
36882e25491SJean-Francois Moine 	usb_control_msg(gspca_dev->dev,
36982e25491SJean-Francois Moine 			usb_sndctrlpipe(gspca_dev->dev, 0),
37082e25491SJean-Francois Moine 			0,
37182e25491SJean-Francois Moine 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
37282e25491SJean-Francois Moine 			0x01, 0,
37382e25491SJean-Francois Moine 			tmpbuf, len * 2, 500);
37482e25491SJean-Francois Moine 	if (len * 2 > USB_BUF_SZ)
37582e25491SJean-Francois Moine 		kfree(tmpbuf);
37682e25491SJean-Francois Moine }
37782e25491SJean-Francois Moine 
378236088d2SJean-Francois Moine static void om6802_sensor_init(struct gspca_dev *gspca_dev)
379fadc7993SJean-Francois Moine {
380fadc7993SJean-Francois Moine 	int i;
38182e25491SJean-Francois Moine 	const u8 *p;
38282e25491SJean-Francois Moine 	u8 byte;
38382e25491SJean-Francois Moine 	u8 val[6] = {0x62, 0, 0x64, 0, 0x60, 0x05};
38482e25491SJean-Francois Moine 	static const u8 sensor_init[] = {
385fadc7993SJean-Francois Moine 		0xdf, 0x6d,
386fadc7993SJean-Francois Moine 		0xdd, 0x18,
387fadc7993SJean-Francois Moine 		0x5a, 0xe0,
388fadc7993SJean-Francois Moine 		0x5c, 0x07,
389fadc7993SJean-Francois Moine 		0x5d, 0xb0,
390fadc7993SJean-Francois Moine 		0x5e, 0x1e,
391fadc7993SJean-Francois Moine 		0x60, 0x71,
392fadc7993SJean-Francois Moine 		0xef, 0x00,
393fadc7993SJean-Francois Moine 		0xe9, 0x00,
394fadc7993SJean-Francois Moine 		0xea, 0x00,
395fadc7993SJean-Francois Moine 		0x90, 0x24,
396fadc7993SJean-Francois Moine 		0x91, 0xb2,
397fadc7993SJean-Francois Moine 		0x82, 0x32,
398fadc7993SJean-Francois Moine 		0xfd, 0x41,
399fadc7993SJean-Francois Moine 		0x00			/* table end */
400fadc7993SJean-Francois Moine 	};
401fadc7993SJean-Francois Moine 
402392ee5a5SJean-Francois Moine 	reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
403e30bdc66SJean-Francois Moine 	msleep(100);
404392ee5a5SJean-Francois Moine 	i = 4;
40597a53a0fSRoel Kluin 	while (--i > 0) {
406392ee5a5SJean-Francois Moine 		byte = reg_r(gspca_dev, 0x0060);
407392ee5a5SJean-Francois Moine 		if (!(byte & 0x01))
408392ee5a5SJean-Francois Moine 			break;
409392ee5a5SJean-Francois Moine 		msleep(100);
410392ee5a5SJean-Francois Moine 	}
411392ee5a5SJean-Francois Moine 	byte = reg_r(gspca_dev, 0x0063);
412392ee5a5SJean-Francois Moine 	if (byte != 0x17) {
4131b19e429SJoe Perches 		pr_err("Bad sensor reset %02x\n", byte);
414392ee5a5SJean-Francois Moine 		/* continue? */
415392ee5a5SJean-Francois Moine 	}
416392ee5a5SJean-Francois Moine 
417fadc7993SJean-Francois Moine 	p = sensor_init;
418fadc7993SJean-Francois Moine 	while (*p != 0) {
419fadc7993SJean-Francois Moine 		val[1] = *p++;
420fadc7993SJean-Francois Moine 		val[3] = *p++;
421fadc7993SJean-Francois Moine 		if (*p == 0)
422fadc7993SJean-Francois Moine 			reg_w(gspca_dev, 0x3c80);
423f89be036SJean-Francois Moine 		reg_w_buf(gspca_dev, val, sizeof val);
424fadc7993SJean-Francois Moine 		i = 4;
425fadc7993SJean-Francois Moine 		while (--i >= 0) {
426fadc7993SJean-Francois Moine 			msleep(15);
427fadc7993SJean-Francois Moine 			byte = reg_r(gspca_dev, 0x60);
428fadc7993SJean-Francois Moine 			if (!(byte & 0x01))
429fadc7993SJean-Francois Moine 				break;
430fadc7993SJean-Francois Moine 		}
431fadc7993SJean-Francois Moine 	}
432392ee5a5SJean-Francois Moine 	msleep(15);
433fadc7993SJean-Francois Moine 	reg_w(gspca_dev, 0x3c80);
434fadc7993SJean-Francois Moine }
435fadc7993SJean-Francois Moine 
4366a7eba24SJean-Francois Moine /* this function is called at probe time */
4376a7eba24SJean-Francois Moine static int sd_config(struct gspca_dev *gspca_dev,
4386a7eba24SJean-Francois Moine 		     const struct usb_device_id *id)
4396a7eba24SJean-Francois Moine {
4409bf81642SHans Verkuil 	struct cam *cam  = &gspca_dev->cam;
4416a7eba24SJean-Francois Moine 
4426a7eba24SJean-Francois Moine 	cam->cam_mode = vga_mode_t16;
4436a7eba24SJean-Francois Moine 	cam->nmodes = ARRAY_SIZE(vga_mode_t16);
4446a7eba24SJean-Francois Moine 
4456a7eba24SJean-Francois Moine 	return 0;
4466a7eba24SJean-Francois Moine }
4476a7eba24SJean-Francois Moine 
4489bf81642SHans Verkuil static void setbrightness(struct gspca_dev *gspca_dev, s32 brightness)
44935480b6bSJean-Francois Moine {
45082e25491SJean-Francois Moine 	u8 set6[4] = { 0x8f, 0x24, 0xc3, 0x00 };
45135480b6bSJean-Francois Moine 
45235480b6bSJean-Francois Moine 	if (brightness < 7) {
45335480b6bSJean-Francois Moine 		set6[1] = 0x26;
45435480b6bSJean-Francois Moine 		set6[3] = 0x70 - brightness * 0x10;
45535480b6bSJean-Francois Moine 	} else {
45635480b6bSJean-Francois Moine 		set6[3] = 0x00 + ((brightness - 7) * 0x10);
45735480b6bSJean-Francois Moine 	}
45835480b6bSJean-Francois Moine 
45935480b6bSJean-Francois Moine 	reg_w_buf(gspca_dev, set6, sizeof set6);
46035480b6bSJean-Francois Moine }
46135480b6bSJean-Francois Moine 
4629bf81642SHans Verkuil static void setcontrast(struct gspca_dev *gspca_dev, s32 contrast)
46335480b6bSJean-Francois Moine {
46482e25491SJean-Francois Moine 	u16 reg_to_write;
46535480b6bSJean-Francois Moine 
46635480b6bSJean-Francois Moine 	if (contrast < 7)
46735480b6bSJean-Francois Moine 		reg_to_write = 0x8ea9 - contrast * 0x200;
46835480b6bSJean-Francois Moine 	else
46935480b6bSJean-Francois Moine 		reg_to_write = 0x00a9 + (contrast - 7) * 0x200;
47035480b6bSJean-Francois Moine 
47135480b6bSJean-Francois Moine 	reg_w(gspca_dev, reg_to_write);
47235480b6bSJean-Francois Moine }
47335480b6bSJean-Francois Moine 
4749bf81642SHans Verkuil static void setcolors(struct gspca_dev *gspca_dev, s32 val)
47535480b6bSJean-Francois Moine {
47682e25491SJean-Francois Moine 	u16 reg_to_write;
47735480b6bSJean-Francois Moine 
4789bf81642SHans Verkuil 	reg_to_write = 0x80bb + val * 0x100;	/* was 0xc0 */
47935480b6bSJean-Francois Moine 	reg_w(gspca_dev, reg_to_write);
48035480b6bSJean-Francois Moine }
48135480b6bSJean-Francois Moine 
4829bf81642SHans Verkuil static void setgamma(struct gspca_dev *gspca_dev, s32 val)
483fadc7993SJean-Francois Moine {
48437d5efb0SJoe Perches 	gspca_dbg(gspca_dev, D_CONF, "Gamma: %d\n", val);
48582e25491SJean-Francois Moine 	reg_w_ixbuf(gspca_dev, 0x90,
4869bf81642SHans Verkuil 		gamma_table[val], sizeof gamma_table[0]);
487fadc7993SJean-Francois Moine }
488fadc7993SJean-Francois Moine 
4899bf81642SHans Verkuil static void setawb_n_RGB(struct gspca_dev *gspca_dev)
490e9b15653SJean-François Moine {
491be1da9eeSCostantino Leandro 	struct sd *sd = (struct sd *) gspca_dev;
4929bf81642SHans Verkuil 	u8 all_gain_reg[8] = {
4939bf81642SHans Verkuil 		0x87, 0x00, 0x88, 0x00, 0x89, 0x00, 0x80, 0x00 };
4949bf81642SHans Verkuil 	s32 red_gain, blue_gain, green_gain;
495e9b15653SJean-François Moine 
4969bf81642SHans Verkuil 	green_gain = sd->gain->val;
4979bf81642SHans Verkuil 
4989bf81642SHans Verkuil 	red_gain = green_gain + sd->red_balance->val;
4999bf81642SHans Verkuil 	if (red_gain > 0x40)
5009bf81642SHans Verkuil 		red_gain = 0x40;
5019bf81642SHans Verkuil 	else if (red_gain < 0x10)
5029bf81642SHans Verkuil 		red_gain = 0x10;
5039bf81642SHans Verkuil 
5049bf81642SHans Verkuil 	blue_gain = green_gain + sd->blue_balance->val;
5059bf81642SHans Verkuil 	if (blue_gain > 0x40)
5069bf81642SHans Verkuil 		blue_gain = 0x40;
5079bf81642SHans Verkuil 	else if (blue_gain < 0x10)
5089bf81642SHans Verkuil 		blue_gain = 0x10;
5099bf81642SHans Verkuil 
5109bf81642SHans Verkuil 	all_gain_reg[1] = red_gain;
5119bf81642SHans Verkuil 	all_gain_reg[3] = blue_gain;
5129bf81642SHans Verkuil 	all_gain_reg[5] = green_gain;
5139bf81642SHans Verkuil 	all_gain_reg[7] = sensor_data[sd->sensor].reg80;
5149bf81642SHans Verkuil 	if (!sd->awb->val)
5159bf81642SHans Verkuil 		all_gain_reg[7] &= ~0x04; /* AWB off */
5169bf81642SHans Verkuil 
517e9b15653SJean-François Moine 	reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg);
518be1da9eeSCostantino Leandro }
519be1da9eeSCostantino Leandro 
5209bf81642SHans Verkuil static void setsharpness(struct gspca_dev *gspca_dev, s32 val)
52135480b6bSJean-Francois Moine {
52282e25491SJean-Francois Moine 	u16 reg_to_write;
52335480b6bSJean-Francois Moine 
5249bf81642SHans Verkuil 	reg_to_write = 0x0aa6 + 0x1000 * val;
52535480b6bSJean-Francois Moine 
52635480b6bSJean-Francois Moine 	reg_w(gspca_dev, reg_to_write);
52735480b6bSJean-Francois Moine }
52835480b6bSJean-Francois Moine 
5299bf81642SHans Verkuil static void setfreq(struct gspca_dev *gspca_dev, s32 val)
53078b98cb9SJean-François Moine {
53178b98cb9SJean-François Moine 	struct sd *sd = (struct sd *) gspca_dev;
53278b98cb9SJean-François Moine 	u8 reg66;
53378b98cb9SJean-François Moine 	u8 freq[4] = { 0x66, 0x00, 0xa8, 0xe8 };
53478b98cb9SJean-François Moine 
53578b98cb9SJean-François Moine 	switch (sd->sensor) {
53678b98cb9SJean-François Moine 	case SENSOR_LT168G:
5379bf81642SHans Verkuil 		if (val != 0)
53878b98cb9SJean-François Moine 			freq[3] = 0xa8;
53978b98cb9SJean-François Moine 		reg66 = 0x41;
54078b98cb9SJean-François Moine 		break;
54178b98cb9SJean-François Moine 	case SENSOR_OM6802:
54278b98cb9SJean-François Moine 		reg66 = 0xca;
54378b98cb9SJean-François Moine 		break;
54478b98cb9SJean-François Moine 	default:
54578b98cb9SJean-François Moine 		reg66 = 0x40;
54678b98cb9SJean-François Moine 		break;
54778b98cb9SJean-François Moine 	}
5489bf81642SHans Verkuil 	switch (val) {
54978b98cb9SJean-François Moine 	case 0:				/* no flicker */
55078b98cb9SJean-François Moine 		freq[3] = 0xf0;
55178b98cb9SJean-François Moine 		break;
55278b98cb9SJean-François Moine 	case 2:				/* 60Hz */
55378b98cb9SJean-François Moine 		reg66 &= ~0x40;
55478b98cb9SJean-François Moine 		break;
55578b98cb9SJean-François Moine 	}
55678b98cb9SJean-François Moine 	freq[1] = reg66;
55778b98cb9SJean-François Moine 
55878b98cb9SJean-François Moine 	reg_w_buf(gspca_dev, freq, sizeof freq);
55978b98cb9SJean-François Moine }
56078b98cb9SJean-François Moine 
561fadc7993SJean-Francois Moine /* this function is called at probe and resume time */
562fadc7993SJean-Francois Moine static int sd_init(struct gspca_dev *gspca_dev)
5636a7eba24SJean-Francois Moine {
564176180c2SMasahiro Yamada 	/* some of this registers are not really needed, because
565176180c2SMasahiro Yamada 	 * they are overridden by setbrigthness, setcontrast, etc.,
566176180c2SMasahiro Yamada 	 * but won't hurt anyway, and can help someone with similar webcam
5676a7eba24SJean-Francois Moine 	 * to see the initial parameters.*/
568fadc7993SJean-Francois Moine 	struct sd *sd = (struct sd *) gspca_dev;
56978a6d74eSJean-Francois Moine 	const struct additional_sensor_data *sensor;
570fadc7993SJean-Francois Moine 	int i;
5712d56f3bbSJean-Francois Moine 	u16 sensor_id;
572d9ddd3b0SHans Verkuil 	u8 test_byte = 0;
5736a7eba24SJean-Francois Moine 
57482e25491SJean-Francois Moine 	static const u8 read_indexs[] =
575249fe889SJean-Francois Moine 		{ 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
57682e25491SJean-Francois Moine 		  0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00 };
57782e25491SJean-Francois Moine 	static const u8 n1[] =
5786a7eba24SJean-Francois Moine 			{0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
57982e25491SJean-Francois Moine 	static const u8 n2[] =
5806a7eba24SJean-Francois Moine 			{0x08, 0x00};
5816a7eba24SJean-Francois Moine 
5822d56f3bbSJean-Francois Moine 	sensor_id = (reg_r(gspca_dev, 0x06) << 8)
5832d56f3bbSJean-Francois Moine 			| reg_r(gspca_dev, 0x07);
5843da37e42SJean-Francois Moine 	switch (sensor_id & 0xff0f) {
5852d56f3bbSJean-Francois Moine 	case 0x0801:
58637d5efb0SJoe Perches 		gspca_dbg(gspca_dev, D_PROBE, "sensor tas5130a\n");
587236088d2SJean-Francois Moine 		sd->sensor = SENSOR_TAS5130A;
5882d56f3bbSJean-Francois Moine 		break;
58900e8006dSNicolau Werneck 	case 0x0802:
59037d5efb0SJoe Perches 		gspca_dbg(gspca_dev, D_PROBE, "sensor lt168g\n");
59100e8006dSNicolau Werneck 		sd->sensor = SENSOR_LT168G;
59200e8006dSNicolau Werneck 		break;
5932d56f3bbSJean-Francois Moine 	case 0x0803:
59437d5efb0SJoe Perches 		gspca_dbg(gspca_dev, D_PROBE, "sensor 'other'\n");
5952d56f3bbSJean-Francois Moine 		sd->sensor = SENSOR_OTHER;
5962d56f3bbSJean-Francois Moine 		break;
5972d56f3bbSJean-Francois Moine 	case 0x0807:
59837d5efb0SJoe Perches 		gspca_dbg(gspca_dev, D_PROBE, "sensor om6802\n");
5992d56f3bbSJean-Francois Moine 		sd->sensor = SENSOR_OM6802;
6002d56f3bbSJean-Francois Moine 		break;
6012d56f3bbSJean-Francois Moine 	default:
6021b19e429SJoe Perches 		pr_err("unknown sensor %04x\n", sensor_id);
603409b11ddSJean-Francois Moine 		return -EINVAL;
604fadc7993SJean-Francois Moine 	}
6056a7eba24SJean-Francois Moine 
606dd72cb3eSJean-Francois Moine 	if (sd->sensor == SENSOR_OM6802) {
607f89be036SJean-Francois Moine 		reg_w_buf(gspca_dev, n1, sizeof n1);
608fadc7993SJean-Francois Moine 		i = 5;
609fadc7993SJean-Francois Moine 		while (--i >= 0) {
610392ee5a5SJean-Francois Moine 			reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
611fadc7993SJean-Francois Moine 			test_byte = reg_r(gspca_dev, 0x0063);
612fadc7993SJean-Francois Moine 			msleep(100);
613fadc7993SJean-Francois Moine 			if (test_byte == 0x17)
614fadc7993SJean-Francois Moine 				break;		/* OK */
615fadc7993SJean-Francois Moine 		}
616fadc7993SJean-Francois Moine 		if (i < 0) {
6171b19e429SJoe Perches 			pr_err("Bad sensor reset %02x\n", test_byte);
61878a6d74eSJean-Francois Moine 			return -EIO;
619fadc7993SJean-Francois Moine 		}
620f89be036SJean-Francois Moine 		reg_w_buf(gspca_dev, n2, sizeof n2);
6212d56f3bbSJean-Francois Moine 	}
622fadc7993SJean-Francois Moine 
623fadc7993SJean-Francois Moine 	i = 0;
6246a7eba24SJean-Francois Moine 	while (read_indexs[i] != 0x00) {
625fadc7993SJean-Francois Moine 		test_byte = reg_r(gspca_dev, read_indexs[i]);
62637d5efb0SJoe Perches 		gspca_dbg(gspca_dev, D_STREAM, "Reg 0x%02x = 0x%02x\n",
62737d5efb0SJoe Perches 			  read_indexs[i], test_byte);
6286a7eba24SJean-Francois Moine 		i++;
6296a7eba24SJean-Francois Moine 	}
6306a7eba24SJean-Francois Moine 
63178a6d74eSJean-Francois Moine 	sensor = &sensor_data[sd->sensor];
63278a6d74eSJean-Francois Moine 	reg_w_buf(gspca_dev, sensor->n3, sizeof sensor->n3);
63378a6d74eSJean-Francois Moine 	reg_w_buf(gspca_dev, sensor->n4, sensor->n4sz);
634ad62fb08SLeandro Costantino 
63500e8006dSNicolau Werneck 	if (sd->sensor == SENSOR_LT168G) {
63600e8006dSNicolau Werneck 		test_byte = reg_r(gspca_dev, 0x80);
63737d5efb0SJoe Perches 		gspca_dbg(gspca_dev, D_STREAM, "Reg 0x%02x = 0x%02x\n", 0x80,
63800e8006dSNicolau Werneck 			  test_byte);
63900e8006dSNicolau Werneck 		reg_w(gspca_dev, 0x6c80);
64000e8006dSNicolau Werneck 	}
64100e8006dSNicolau Werneck 
64278a6d74eSJean-Francois Moine 	reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);
64378a6d74eSJean-Francois Moine 	reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);
64478a6d74eSJean-Francois Moine 	reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);
645ad62fb08SLeandro Costantino 
64678a6d74eSJean-Francois Moine 	reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80);
64778a6d74eSJean-Francois Moine 	reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80);
64878a6d74eSJean-Francois Moine 	reg_w(gspca_dev, (sensor->reg8e << 8) + 0x8e);
6499bf81642SHans Verkuil 	reg_w(gspca_dev, (0x20 << 8) + 0x87);
6509bf81642SHans Verkuil 	reg_w(gspca_dev, (0x20 << 8) + 0x88);
6519bf81642SHans Verkuil 	reg_w(gspca_dev, (0x20 << 8) + 0x89);
6526a7eba24SJean-Francois Moine 
65378a6d74eSJean-Francois Moine 	reg_w_buf(gspca_dev, sensor->data5, sizeof sensor->data5);
65478a6d74eSJean-Francois Moine 	reg_w_buf(gspca_dev, sensor->nset8, sizeof sensor->nset8);
65578a6d74eSJean-Francois Moine 	reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
656ad62fb08SLeandro Costantino 
65700e8006dSNicolau Werneck 	if (sd->sensor == SENSOR_LT168G) {
65800e8006dSNicolau Werneck 		test_byte = reg_r(gspca_dev, 0x80);
65937d5efb0SJoe Perches 		gspca_dbg(gspca_dev, D_STREAM, "Reg 0x%02x = 0x%02x\n", 0x80,
66000e8006dSNicolau Werneck 			  test_byte);
66100e8006dSNicolau Werneck 		reg_w(gspca_dev, 0x6c80);
66200e8006dSNicolau Werneck 	}
66300e8006dSNicolau Werneck 
66478a6d74eSJean-Francois Moine 	reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);
66578a6d74eSJean-Francois Moine 	reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);
66678a6d74eSJean-Francois Moine 	reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);
6676a7eba24SJean-Francois Moine 
6686a7eba24SJean-Francois Moine 	return 0;
6696a7eba24SJean-Francois Moine }
6706a7eba24SJean-Francois Moine 
6719bf81642SHans Verkuil static void setmirror(struct gspca_dev *gspca_dev, s32 val)
6726a7eba24SJean-Francois Moine {
673cd8955b8SJean-François Moine 	u8 hflipcmd[8] =
6746a7eba24SJean-Francois Moine 		{0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09};
6756a7eba24SJean-Francois Moine 
6769bf81642SHans Verkuil 	if (val)
677cd8955b8SJean-François Moine 		hflipcmd[3] = 0x01;
6786a7eba24SJean-Francois Moine 
679cd8955b8SJean-François Moine 	reg_w_buf(gspca_dev, hflipcmd, sizeof hflipcmd);
6806a7eba24SJean-Francois Moine }
6816a7eba24SJean-Francois Moine 
6829bf81642SHans Verkuil static void seteffect(struct gspca_dev *gspca_dev, s32 val)
6836a7eba24SJean-Francois Moine {
6849bf81642SHans Verkuil 	int idx = 0;
6856a7eba24SJean-Francois Moine 
6869bf81642SHans Verkuil 	switch (val) {
6879bf81642SHans Verkuil 	case V4L2_COLORFX_NONE:
6889bf81642SHans Verkuil 		break;
6899bf81642SHans Verkuil 	case V4L2_COLORFX_BW:
6909bf81642SHans Verkuil 		idx = 2;
6919bf81642SHans Verkuil 		break;
6929bf81642SHans Verkuil 	case V4L2_COLORFX_SEPIA:
6939bf81642SHans Verkuil 		idx = 3;
6949bf81642SHans Verkuil 		break;
6959bf81642SHans Verkuil 	case V4L2_COLORFX_SKETCH:
6969bf81642SHans Verkuil 		idx = 4;
6979bf81642SHans Verkuil 		break;
6989bf81642SHans Verkuil 	case V4L2_COLORFX_NEGATIVE:
6999bf81642SHans Verkuil 		idx = 6;
7009bf81642SHans Verkuil 		break;
7019bf81642SHans Verkuil 	default:
7029bf81642SHans Verkuil 		break;
7036a7eba24SJean-Francois Moine 	}
7046a7eba24SJean-Francois Moine 
7059bf81642SHans Verkuil 	reg_w_buf(gspca_dev, effects_table[idx],
7069bf81642SHans Verkuil 				sizeof effects_table[0]);
7079bf81642SHans Verkuil 
7089bf81642SHans Verkuil 	if (val == V4L2_COLORFX_SKETCH)
709fadc7993SJean-Francois Moine 		reg_w(gspca_dev, 0x4aa6);
7106a7eba24SJean-Francois Moine 	else
711fadc7993SJean-Francois Moine 		reg_w(gspca_dev, 0xfaa6);
7126a7eba24SJean-Francois Moine }
7136a7eba24SJean-Francois Moine 
714ad62fb08SLeandro Costantino /* Is this really needed?
715ad62fb08SLeandro Costantino  * i added some module parameters for test with some users */
716ad62fb08SLeandro Costantino static void poll_sensor(struct gspca_dev *gspca_dev)
717ad62fb08SLeandro Costantino {
71882e25491SJean-Francois Moine 	static const u8 poll1[] =
719ad62fb08SLeandro Costantino 		{0x67, 0x05, 0x68, 0x81, 0x69, 0x80, 0x6a, 0x82,
720ad62fb08SLeandro Costantino 		 0x6b, 0x68, 0x6c, 0x69, 0x72, 0xd9, 0x73, 0x34,
721ad62fb08SLeandro Costantino 		 0x74, 0x32, 0x75, 0x92, 0x76, 0x00, 0x09, 0x01,
722ad62fb08SLeandro Costantino 		 0x60, 0x14};
72382e25491SJean-Francois Moine 	static const u8 poll2[] =
724ad62fb08SLeandro Costantino 		{0x67, 0x02, 0x68, 0x71, 0x69, 0x72, 0x72, 0xa9,
725ad62fb08SLeandro Costantino 		 0x73, 0x02, 0x73, 0x02, 0x60, 0x14};
72698388241SJean-François Moine 	static const u8 noise03[] =	/* (some differences / ms-drv) */
727ad62fb08SLeandro Costantino 		{0xa6, 0x0a, 0xea, 0xcf, 0xbe, 0x26, 0xb1, 0x5f,
728ad62fb08SLeandro Costantino 		 0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c,
729ad62fb08SLeandro Costantino 		 0xc2, 0x80, 0xc3, 0x10};
730ad62fb08SLeandro Costantino 
73137d5efb0SJoe Perches 	gspca_dbg(gspca_dev, D_STREAM, "[Sensor requires polling]\n");
732ad62fb08SLeandro Costantino 	reg_w_buf(gspca_dev, poll1, sizeof poll1);
733ad62fb08SLeandro Costantino 	reg_w_buf(gspca_dev, poll2, sizeof poll2);
73498388241SJean-François Moine 	reg_w_buf(gspca_dev, noise03, sizeof noise03);
735ad62fb08SLeandro Costantino }
736ad62fb08SLeandro Costantino 
737fadc7993SJean-Francois Moine static int sd_start(struct gspca_dev *gspca_dev)
738fadc7993SJean-Francois Moine {
739fadc7993SJean-Francois Moine 	struct sd *sd = (struct sd *) gspca_dev;
74078a6d74eSJean-Francois Moine 	const struct additional_sensor_data *sensor;
741fadc7993SJean-Francois Moine 	int i, mode;
74282e25491SJean-Francois Moine 	u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
74382e25491SJean-Francois Moine 	static const u8 t3[] =
74482e25491SJean-Francois Moine 		{ 0x07, 0x00, 0x88, 0x02, 0x06, 0x00, 0xe7, 0x01 };
745fadc7993SJean-Francois Moine 
74678a6d74eSJean-Francois Moine 	mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
747fadc7993SJean-Francois Moine 	switch (mode) {
74882e25491SJean-Francois Moine 	case 0:		/* 640x480 (0x00) */
74982e25491SJean-Francois Moine 		break;
750fadc7993SJean-Francois Moine 	case 1:		/* 352x288 */
751fadc7993SJean-Francois Moine 		t2[1] = 0x40;
752fadc7993SJean-Francois Moine 		break;
753fadc7993SJean-Francois Moine 	case 2:		/* 320x240 */
754fadc7993SJean-Francois Moine 		t2[1] = 0x10;
755fadc7993SJean-Francois Moine 		break;
756fadc7993SJean-Francois Moine 	case 3:		/* 176x144 */
757fadc7993SJean-Francois Moine 		t2[1] = 0x50;
758fadc7993SJean-Francois Moine 		break;
75982e25491SJean-Francois Moine 	default:
76082e25491SJean-Francois Moine /*	case 4:		 * 160x120 */
761fadc7993SJean-Francois Moine 		t2[1] = 0x20;
762fadc7993SJean-Francois Moine 		break;
763fadc7993SJean-Francois Moine 	}
764fadc7993SJean-Francois Moine 
7652d56f3bbSJean-Francois Moine 	switch (sd->sensor) {
7662d56f3bbSJean-Francois Moine 	case SENSOR_OM6802:
7672d56f3bbSJean-Francois Moine 		om6802_sensor_init(gspca_dev);
7682d56f3bbSJean-Francois Moine 		break;
769cd8955b8SJean-François Moine 	case SENSOR_TAS5130A:
770fadc7993SJean-Francois Moine 		i = 0;
77178a6d74eSJean-Francois Moine 		for (;;) {
772f89be036SJean-Francois Moine 			reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
773fadc7993SJean-Francois Moine 					 sizeof tas5130a_sensor_init[0]);
77478a6d74eSJean-Francois Moine 			if (i >= ARRAY_SIZE(tas5130a_sensor_init) - 1)
77578a6d74eSJean-Francois Moine 				break;
776fadc7993SJean-Francois Moine 			i++;
777fadc7993SJean-Francois Moine 		}
778fadc7993SJean-Francois Moine 		reg_w(gspca_dev, 0x3c80);
779fadc7993SJean-Francois Moine 		/* just in case and to keep sync with logs (for mine) */
78078a6d74eSJean-Francois Moine 		reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
781fadc7993SJean-Francois Moine 				 sizeof tas5130a_sensor_init[0]);
782fadc7993SJean-Francois Moine 		reg_w(gspca_dev, 0x3c80);
7832d56f3bbSJean-Francois Moine 		break;
784fadc7993SJean-Francois Moine 	}
78578a6d74eSJean-Francois Moine 	sensor = &sensor_data[sd->sensor];
7869bf81642SHans Verkuil 	setfreq(gspca_dev, v4l2_ctrl_g_ctrl(sd->freq));
787fadc7993SJean-Francois Moine 	reg_r(gspca_dev, 0x0012);
788ad62fb08SLeandro Costantino 	reg_w_buf(gspca_dev, t2, sizeof t2);
78982e25491SJean-Francois Moine 	reg_w_ixbuf(gspca_dev, 0xb3, t3, sizeof t3);
790fadc7993SJean-Francois Moine 	reg_w(gspca_dev, 0x0013);
791ad62fb08SLeandro Costantino 	msleep(15);
79278a6d74eSJean-Francois Moine 	reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
79378a6d74eSJean-Francois Moine 	reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
79478a6d74eSJean-Francois Moine 
79578a6d74eSJean-Francois Moine 	if (sd->sensor == SENSOR_OM6802)
796ad62fb08SLeandro Costantino 		poll_sensor(gspca_dev);
797ad62fb08SLeandro Costantino 
798fadc7993SJean-Francois Moine 	return 0;
799fadc7993SJean-Francois Moine }
800fadc7993SJean-Francois Moine 
801eb229b22SJean-Francois Moine static void sd_stopN(struct gspca_dev *gspca_dev)
802eb229b22SJean-Francois Moine {
803eb229b22SJean-Francois Moine 	struct sd *sd = (struct sd *) gspca_dev;
804eb229b22SJean-Francois Moine 
805eb229b22SJean-Francois Moine 	reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
806eb229b22SJean-Francois Moine 			sizeof sensor_data[sd->sensor].stream);
807eb229b22SJean-Francois Moine 	reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
808eb229b22SJean-Francois Moine 			sizeof sensor_data[sd->sensor].stream);
80978a6d74eSJean-Francois Moine 	if (sd->sensor == SENSOR_OM6802) {
810eb229b22SJean-Francois Moine 		msleep(20);
811eb229b22SJean-Francois Moine 		reg_w(gspca_dev, 0x0309);
812eb229b22SJean-Francois Moine 	}
813f8d26879SPeter Senna Tschudin #if IS_ENABLED(CONFIG_INPUT)
814ee186fd9SHans de Goede 	/* If the last button state is pressed, release it now! */
815ee186fd9SHans de Goede 	if (sd->button_pressed) {
816ee186fd9SHans de Goede 		input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
817ee186fd9SHans de Goede 		input_sync(gspca_dev->input_dev);
818ee186fd9SHans de Goede 		sd->button_pressed = 0;
819ee186fd9SHans de Goede 	}
820ee186fd9SHans de Goede #endif
8212d56f3bbSJean-Francois Moine }
822eb229b22SJean-Francois Moine 
823fadc7993SJean-Francois Moine static void sd_pkt_scan(struct gspca_dev *gspca_dev,
82482e25491SJean-Francois Moine 			u8 *data,			/* isoc packet */
825fadc7993SJean-Francois Moine 			int len)			/* iso packet length */
826fadc7993SJean-Francois Moine {
827d7e92e15SArnd Bergmann 	struct sd *sd __maybe_unused = (struct sd *) gspca_dev;
828ebb78c5aSJean-François Moine 	int pkt_type;
829fadc7993SJean-Francois Moine 
830fadc7993SJean-Francois Moine 	if (data[0] == 0x5a) {
831f8d26879SPeter Senna Tschudin #if IS_ENABLED(CONFIG_INPUT)
832ee186fd9SHans de Goede 		if (len > 20) {
833ee186fd9SHans de Goede 			u8 state = (data[20] & 0x80) ? 1 : 0;
834ee186fd9SHans de Goede 			if (sd->button_pressed != state) {
835ee186fd9SHans de Goede 				input_report_key(gspca_dev->input_dev,
836ee186fd9SHans de Goede 						 KEY_CAMERA, state);
837ee186fd9SHans de Goede 				input_sync(gspca_dev->input_dev);
838ee186fd9SHans de Goede 				sd->button_pressed = state;
839ee186fd9SHans de Goede 			}
840ee186fd9SHans de Goede 		}
841ee186fd9SHans de Goede #endif
842fadc7993SJean-Francois Moine 		/* Control Packet, after this came the header again,
843fadc7993SJean-Francois Moine 		 * but extra bytes came in the packet before this,
844fadc7993SJean-Francois Moine 		 * sometimes an EOF arrives, sometimes not... */
845fadc7993SJean-Francois Moine 		return;
846fadc7993SJean-Francois Moine 	}
847fadc7993SJean-Francois Moine 	data += 2;
848fadc7993SJean-Francois Moine 	len -= 2;
849ebb78c5aSJean-François Moine 	if (data[0] == 0xff && data[1] == 0xd8)
850ebb78c5aSJean-François Moine 		pkt_type = FIRST_PACKET;
851ebb78c5aSJean-François Moine 	else if (data[len - 2] == 0xff && data[len - 1] == 0xd9)
852ebb78c5aSJean-François Moine 		pkt_type = LAST_PACKET;
853ebb78c5aSJean-François Moine 	else
854ebb78c5aSJean-François Moine 		pkt_type = INTER_PACKET;
855ebb78c5aSJean-François Moine 	gspca_frame_add(gspca_dev, pkt_type, data, len);
8566a7eba24SJean-Francois Moine }
8576a7eba24SJean-Francois Moine 
8589bf81642SHans Verkuil static int sd_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
859be1da9eeSCostantino Leandro {
8609bf81642SHans Verkuil 	struct gspca_dev *gspca_dev =
8619bf81642SHans Verkuil 		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
862be1da9eeSCostantino Leandro 	struct sd *sd = (struct sd *)gspca_dev;
8639bf81642SHans Verkuil 	s32 red_gain, blue_gain, green_gain;
864be1da9eeSCostantino Leandro 
8659bf81642SHans Verkuil 	gspca_dev->usb_err = 0;
8669bf81642SHans Verkuil 
8679bf81642SHans Verkuil 	switch (ctrl->id) {
8689bf81642SHans Verkuil 	case V4L2_CID_AUTO_WHITE_BALANCE:
8699bf81642SHans Verkuil 		red_gain = reg_r(gspca_dev, 0x0087);
8709bf81642SHans Verkuil 		if (red_gain > 0x40)
8719bf81642SHans Verkuil 			red_gain = 0x40;
8729bf81642SHans Verkuil 		else if (red_gain < 0x10)
8739bf81642SHans Verkuil 			red_gain = 0x10;
8749bf81642SHans Verkuil 
8759bf81642SHans Verkuil 		blue_gain = reg_r(gspca_dev, 0x0088);
8769bf81642SHans Verkuil 		if (blue_gain > 0x40)
8779bf81642SHans Verkuil 			blue_gain = 0x40;
8789bf81642SHans Verkuil 		else if (blue_gain < 0x10)
8799bf81642SHans Verkuil 			blue_gain = 0x10;
8809bf81642SHans Verkuil 
8819bf81642SHans Verkuil 		green_gain = reg_r(gspca_dev, 0x0089);
8829bf81642SHans Verkuil 		if (green_gain > 0x40)
8839bf81642SHans Verkuil 			green_gain = 0x40;
8849bf81642SHans Verkuil 		else if (green_gain < 0x10)
8859bf81642SHans Verkuil 			green_gain = 0x10;
8869bf81642SHans Verkuil 
8879bf81642SHans Verkuil 		sd->gain->val = green_gain;
8889bf81642SHans Verkuil 		sd->red_balance->val = red_gain - green_gain;
8899bf81642SHans Verkuil 		sd->blue_balance->val = blue_gain - green_gain;
8909bf81642SHans Verkuil 		break;
8919bf81642SHans Verkuil 	}
892be1da9eeSCostantino Leandro 	return 0;
893be1da9eeSCostantino Leandro }
894be1da9eeSCostantino Leandro 
8959bf81642SHans Verkuil static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
896be1da9eeSCostantino Leandro {
8979bf81642SHans Verkuil 	struct gspca_dev *gspca_dev =
8989bf81642SHans Verkuil 		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
899be1da9eeSCostantino Leandro 
9009bf81642SHans Verkuil 	gspca_dev->usb_err = 0;
9019bf81642SHans Verkuil 
9029bf81642SHans Verkuil 	if (!gspca_dev->streaming)
903be1da9eeSCostantino Leandro 		return 0;
904be1da9eeSCostantino Leandro 
9059bf81642SHans Verkuil 	switch (ctrl->id) {
9069bf81642SHans Verkuil 	case V4L2_CID_BRIGHTNESS:
9079bf81642SHans Verkuil 		setbrightness(gspca_dev, ctrl->val);
9089bf81642SHans Verkuil 		break;
9099bf81642SHans Verkuil 	case V4L2_CID_CONTRAST:
9109bf81642SHans Verkuil 		setcontrast(gspca_dev, ctrl->val);
9119bf81642SHans Verkuil 		break;
9129bf81642SHans Verkuil 	case V4L2_CID_SATURATION:
9139bf81642SHans Verkuil 		setcolors(gspca_dev, ctrl->val);
9149bf81642SHans Verkuil 		break;
9159bf81642SHans Verkuil 	case V4L2_CID_GAMMA:
9169bf81642SHans Verkuil 		setgamma(gspca_dev, ctrl->val);
9179bf81642SHans Verkuil 		break;
9189bf81642SHans Verkuil 	case V4L2_CID_HFLIP:
9199bf81642SHans Verkuil 		setmirror(gspca_dev, ctrl->val);
9209bf81642SHans Verkuil 		break;
9219bf81642SHans Verkuil 	case V4L2_CID_SHARPNESS:
9229bf81642SHans Verkuil 		setsharpness(gspca_dev, ctrl->val);
9239bf81642SHans Verkuil 		break;
9246a7eba24SJean-Francois Moine 	case V4L2_CID_POWER_LINE_FREQUENCY:
9259bf81642SHans Verkuil 		setfreq(gspca_dev, ctrl->val);
9266a7eba24SJean-Francois Moine 		break;
9279bf81642SHans Verkuil 	case V4L2_CID_BACKLIGHT_COMPENSATION:
9289bf81642SHans Verkuil 		reg_w(gspca_dev, ctrl->val ? 0xf48e : 0xb48e);
9299bf81642SHans Verkuil 		break;
9309bf81642SHans Verkuil 	case V4L2_CID_AUTO_WHITE_BALANCE:
9319bf81642SHans Verkuil 		setawb_n_RGB(gspca_dev);
9329bf81642SHans Verkuil 		break;
9339bf81642SHans Verkuil 	case V4L2_CID_COLORFX:
9349bf81642SHans Verkuil 		seteffect(gspca_dev, ctrl->val);
9356a7eba24SJean-Francois Moine 		break;
9366a7eba24SJean-Francois Moine 	}
9379bf81642SHans Verkuil 	return gspca_dev->usb_err;
9389bf81642SHans Verkuil }
9399bf81642SHans Verkuil 
9409bf81642SHans Verkuil static const struct v4l2_ctrl_ops sd_ctrl_ops = {
9419bf81642SHans Verkuil 	.g_volatile_ctrl = sd_g_volatile_ctrl,
9429bf81642SHans Verkuil 	.s_ctrl = sd_s_ctrl,
9439bf81642SHans Verkuil };
9449bf81642SHans Verkuil 
9459bf81642SHans Verkuil static int sd_init_controls(struct gspca_dev *gspca_dev)
9469bf81642SHans Verkuil {
9479bf81642SHans Verkuil 	struct sd *sd = (struct sd *)gspca_dev;
9489bf81642SHans Verkuil 	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
9499bf81642SHans Verkuil 
9509bf81642SHans Verkuil 	gspca_dev->vdev.ctrl_handler = hdl;
9519bf81642SHans Verkuil 	v4l2_ctrl_handler_init(hdl, 12);
9529bf81642SHans Verkuil 	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
9539bf81642SHans Verkuil 			V4L2_CID_BRIGHTNESS, 0, 14, 1, 8);
9549bf81642SHans Verkuil 	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
9559bf81642SHans Verkuil 			V4L2_CID_CONTRAST, 0, 0x0d, 1, 7);
9569bf81642SHans Verkuil 	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
9579bf81642SHans Verkuil 			V4L2_CID_SATURATION, 0, 0xf, 1, 5);
9589bf81642SHans Verkuil 	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
9599bf81642SHans Verkuil 			V4L2_CID_GAMMA, 0, GAMMA_MAX, 1, 10);
9603e4d8f48SMauro Carvalho Chehab 	/* Activate lowlight, some apps don't bring up the
9619bf81642SHans Verkuil 	   backlight_compensation control) */
9629bf81642SHans Verkuil 	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
9639bf81642SHans Verkuil 			V4L2_CID_BACKLIGHT_COMPENSATION, 0, 1, 1, 1);
9649bf81642SHans Verkuil 	if (sd->sensor == SENSOR_TAS5130A)
9659bf81642SHans Verkuil 		v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
9669bf81642SHans Verkuil 				V4L2_CID_HFLIP, 0, 1, 1, 0);
9679bf81642SHans Verkuil 	sd->awb = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
9689bf81642SHans Verkuil 			V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
9699bf81642SHans Verkuil 	sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
9709bf81642SHans Verkuil 			V4L2_CID_GAIN, 0x10, 0x40, 1, 0x20);
9719bf81642SHans Verkuil 	sd->blue_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
9729bf81642SHans Verkuil 			V4L2_CID_BLUE_BALANCE, -0x30, 0x30, 1, 0);
9739bf81642SHans Verkuil 	sd->red_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
9749bf81642SHans Verkuil 			V4L2_CID_RED_BALANCE, -0x30, 0x30, 1, 0);
9759bf81642SHans Verkuil 	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
9769bf81642SHans Verkuil 			V4L2_CID_SHARPNESS, 0, 15, 1, 6);
9779bf81642SHans Verkuil 	v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops,
9789bf81642SHans Verkuil 			V4L2_CID_COLORFX, V4L2_COLORFX_SKETCH,
9799bf81642SHans Verkuil 			~((1 << V4L2_COLORFX_NONE) |
9809bf81642SHans Verkuil 			  (1 << V4L2_COLORFX_BW) |
9819bf81642SHans Verkuil 			  (1 << V4L2_COLORFX_SEPIA) |
9829bf81642SHans Verkuil 			  (1 << V4L2_COLORFX_SKETCH) |
9839bf81642SHans Verkuil 			  (1 << V4L2_COLORFX_NEGATIVE)),
9849bf81642SHans Verkuil 			V4L2_COLORFX_NONE);
9859bf81642SHans Verkuil 	sd->freq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops,
9869bf81642SHans Verkuil 			V4L2_CID_POWER_LINE_FREQUENCY,
9879bf81642SHans Verkuil 			V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 1,
9889bf81642SHans Verkuil 			V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
9899bf81642SHans Verkuil 
9909bf81642SHans Verkuil 	if (hdl->error) {
9919bf81642SHans Verkuil 		pr_err("Could not initialize controls\n");
9929bf81642SHans Verkuil 		return hdl->error;
9939bf81642SHans Verkuil 	}
9949bf81642SHans Verkuil 
9959bf81642SHans Verkuil 	v4l2_ctrl_auto_cluster(4, &sd->awb, 0, true);
9969bf81642SHans Verkuil 
9979bf81642SHans Verkuil 	return 0;
9986a7eba24SJean-Francois Moine }
9996a7eba24SJean-Francois Moine 
10006a7eba24SJean-Francois Moine /* sub-driver description */
1001a5ae2062SJean-Francois Moine static const struct sd_desc sd_desc = {
10026a7eba24SJean-Francois Moine 	.name = MODULE_NAME,
10036a7eba24SJean-Francois Moine 	.config = sd_config,
1004012d6b02SJean-Francois Moine 	.init = sd_init,
10059bf81642SHans Verkuil 	.init_controls = sd_init_controls,
10066a7eba24SJean-Francois Moine 	.start = sd_start,
1007eb229b22SJean-Francois Moine 	.stopN = sd_stopN,
10086a7eba24SJean-Francois Moine 	.pkt_scan = sd_pkt_scan,
1009f8d26879SPeter Senna Tschudin #if IS_ENABLED(CONFIG_INPUT)
1010ee186fd9SHans de Goede 	.other_input = 1,
1011ee186fd9SHans de Goede #endif
10126a7eba24SJean-Francois Moine };
10136a7eba24SJean-Francois Moine 
10146a7eba24SJean-Francois Moine /* -- module initialisation -- */
101595c967c1SJean-François Moine static const struct usb_device_id device_table[] = {
10169d64fdb1SJean-Francois Moine 	{USB_DEVICE(0x17a1, 0x0128)},
10176a7eba24SJean-Francois Moine 	{}
10186a7eba24SJean-Francois Moine };
10196a7eba24SJean-Francois Moine MODULE_DEVICE_TABLE(usb, device_table);
10206a7eba24SJean-Francois Moine 
10216a7eba24SJean-Francois Moine /* -- device connect -- */
10226a7eba24SJean-Francois Moine static int sd_probe(struct usb_interface *intf,
10236a7eba24SJean-Francois Moine 		    const struct usb_device_id *id)
10246a7eba24SJean-Francois Moine {
10256a7eba24SJean-Francois Moine 	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
10266a7eba24SJean-Francois Moine 			       THIS_MODULE);
10276a7eba24SJean-Francois Moine }
10286a7eba24SJean-Francois Moine 
10296a7eba24SJean-Francois Moine static struct usb_driver sd_driver = {
10306a7eba24SJean-Francois Moine 	.name = MODULE_NAME,
10316a7eba24SJean-Francois Moine 	.id_table = device_table,
10326a7eba24SJean-Francois Moine 	.probe = sd_probe,
10336a7eba24SJean-Francois Moine 	.disconnect = gspca_disconnect,
10346a709749SJean-Francois Moine #ifdef CONFIG_PM
10356a709749SJean-Francois Moine 	.suspend = gspca_suspend,
10366a709749SJean-Francois Moine 	.resume = gspca_resume,
10378bb58964SHans de Goede 	.reset_resume = gspca_resume,
10386a709749SJean-Francois Moine #endif
10396a7eba24SJean-Francois Moine };
10406a7eba24SJean-Francois Moine 
1041ecb3b2b3SGreg Kroah-Hartman module_usb_driver(sd_driver);
1042