1/*
2 * Support for the sensor part which is integrated (I think) into the
3 * st6422 stv06xx alike bridge, as its integrated there are no i2c writes
4 * but instead direct bridge writes.
5 *
6 * Copyright (c) 2009 Hans de Goede <hdegoede@redhat.com>
7 *
8 * Strongly based on qc-usb-messenger, which is:
9 * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher
10 *		      Mark Cave-Ayland, Carlo E Prelz, Dick Streefland
11 * Copyright (c) 2002, 2003 Tuukka Toivonen
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 *
27 */
28
29#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
30
31#include "stv06xx_st6422.h"
32
33/* controls */
34enum e_ctrl {
35	BRIGHTNESS,
36	CONTRAST,
37	GAIN,
38	EXPOSURE,
39	NCTRLS		/* number of controls */
40};
41
42/* sensor settings */
43struct st6422_settings {
44	struct gspca_ctrl ctrls[NCTRLS];
45};
46
47static struct v4l2_pix_format st6422_mode[] = {
48	/* Note we actually get 124 lines of data, of which we skip the 4st
49	   4 as they are garbage */
50	{
51		162,
52		120,
53		V4L2_PIX_FMT_SGRBG8,
54		V4L2_FIELD_NONE,
55		.sizeimage = 162 * 120,
56		.bytesperline = 162,
57		.colorspace = V4L2_COLORSPACE_SRGB,
58		.priv = 1
59	},
60	/* Note we actually get 248 lines of data, of which we skip the 4st
61	   4 as they are garbage, and we tell the app it only gets the
62	   first 240 of the 244 lines it actually gets, so that it ignores
63	   the last 4. */
64	{
65		324,
66		240,
67		V4L2_PIX_FMT_SGRBG8,
68		V4L2_FIELD_NONE,
69		.sizeimage = 324 * 244,
70		.bytesperline = 324,
71		.colorspace = V4L2_COLORSPACE_SRGB,
72		.priv = 0
73	},
74};
75
76/* V4L2 controls supported by the driver */
77static void st6422_set_brightness(struct gspca_dev *gspca_dev);
78static void st6422_set_contrast(struct gspca_dev *gspca_dev);
79static void st6422_set_gain(struct gspca_dev *gspca_dev);
80static void st6422_set_exposure(struct gspca_dev *gspca_dev);
81
82static const struct ctrl st6422_ctrl[NCTRLS] = {
83[BRIGHTNESS] = {
84		{
85			.id		= V4L2_CID_BRIGHTNESS,
86			.type		= V4L2_CTRL_TYPE_INTEGER,
87			.name		= "Brightness",
88			.minimum	= 0,
89			.maximum	= 31,
90			.step		= 1,
91			.default_value  = 3
92		},
93		.set_control = st6422_set_brightness
94	},
95[CONTRAST] = {
96		{
97			.id		= V4L2_CID_CONTRAST,
98			.type		= V4L2_CTRL_TYPE_INTEGER,
99			.name		= "Contrast",
100			.minimum	= 0,
101			.maximum	= 15,
102			.step		= 1,
103			.default_value  = 11
104		},
105		.set_control = st6422_set_contrast
106	},
107[GAIN] = {
108		{
109			.id		= V4L2_CID_GAIN,
110			.type		= V4L2_CTRL_TYPE_INTEGER,
111			.name		= "Gain",
112			.minimum	= 0,
113			.maximum	= 255,
114			.step		= 1,
115			.default_value  = 64
116		},
117		.set_control = st6422_set_gain
118	},
119[EXPOSURE] = {
120		{
121			.id		= V4L2_CID_EXPOSURE,
122			.type		= V4L2_CTRL_TYPE_INTEGER,
123			.name		= "Exposure",
124			.minimum	= 0,
125#define EXPOSURE_MAX 1023
126			.maximum	= EXPOSURE_MAX,
127			.step		= 1,
128			.default_value  = 256
129		},
130		.set_control = st6422_set_exposure
131	},
132};
133
134static int st6422_probe(struct sd *sd)
135{
136	struct st6422_settings *sensor_settings;
137
138	if (sd->bridge != BRIDGE_ST6422)
139		return -ENODEV;
140
141	pr_info("st6422 sensor detected\n");
142
143	sensor_settings = kmalloc(sizeof *sensor_settings, GFP_KERNEL);
144	if (!sensor_settings)
145		return -ENOMEM;
146
147	sd->gspca_dev.cam.cam_mode = st6422_mode;
148	sd->gspca_dev.cam.nmodes = ARRAY_SIZE(st6422_mode);
149	sd->gspca_dev.cam.ctrls = sensor_settings->ctrls;
150	sd->desc.ctrls = st6422_ctrl;
151	sd->desc.nctrls = ARRAY_SIZE(st6422_ctrl);
152	sd->sensor_priv = sensor_settings;
153
154	return 0;
155}
156
157static int st6422_init(struct sd *sd)
158{
159	int err = 0, i;
160
161	const u16 st6422_bridge_init[][2] = {
162		{ STV_ISO_ENABLE, 0x00 }, /* disable capture */
163		{ 0x1436, 0x00 },
164		{ 0x1432, 0x03 },	/* 0x00-0x1F brightness */
165		{ 0x143a, 0xf9 },	/* 0x00-0x0F contrast */
166		{ 0x0509, 0x38 },	/* R */
167		{ 0x050a, 0x38 },	/* G */
168		{ 0x050b, 0x38 },	/* B */
169		{ 0x050c, 0x2a },
170		{ 0x050d, 0x01 },
171
172
173		{ 0x1431, 0x00 },	/* 0x00-0x07 ??? */
174		{ 0x1433, 0x34 },	/* 160x120, 0x00-0x01 night filter */
175		{ 0x1438, 0x18 },	/* 640x480 */
176/* 18 bayes */
177/* 10 compressed? */
178
179		{ 0x1439, 0x00 },
180/* anti-noise?  0xa2 gives a perfect image */
181
182		{ 0x143b, 0x05 },
183		{ 0x143c, 0x00 },	/* 0x00-0x01 - ??? */
184
185
186/* shutter time 0x0000-0x03FF */
187/* low value  give good picures on moving objects (but requires much light) */
188/* high value gives good picures in darkness (but tends to be overexposed) */
189		{ 0x143e, 0x01 },
190		{ 0x143d, 0x00 },
191
192		{ 0x1442, 0xe2 },
193/* write: 1x1x xxxx */
194/* read:  1x1x xxxx */
195/*        bit 5 == button pressed and hold if 0 */
196/* write 0xe2,0xea */
197
198/* 0x144a */
199/* 0x00 init */
200/* bit 7 == button has been pressed, but not handled */
201
202/* interrupt */
203/* if(urb->iso_frame_desc[i].status == 0x80) { */
204/* if(urb->iso_frame_desc[i].status == 0x88) { */
205
206		{ 0x1500, 0xd0 },
207		{ 0x1500, 0xd0 },
208		{ 0x1500, 0x50 },	/* 0x00 - 0xFF  0x80 == compr ? */
209
210		{ 0x1501, 0xaf },
211/* high val-> light area gets darker */
212/* low val -> light area gets lighter */
213		{ 0x1502, 0xc2 },
214/* high val-> light area gets darker */
215/* low val -> light area gets lighter */
216		{ 0x1503, 0x45 },
217/* high val-> light area gets darker */
218/* low val -> light area gets lighter */
219		{ 0x1505, 0x02 },
220/* 2  : 324x248  80352 bytes */
221/* 7  : 248x162  40176 bytes */
222/* c+f: 162*124  20088 bytes */
223
224		{ 0x150e, 0x8e },
225		{ 0x150f, 0x37 },
226		{ 0x15c0, 0x00 },
227		{ 0x15c3, 0x08 },	/* 0x04/0x14 ... test pictures ??? */
228
229
230		{ 0x143f, 0x01 },	/* commit settings */
231
232	};
233
234	for (i = 0; i < ARRAY_SIZE(st6422_bridge_init) && !err; i++) {
235		err = stv06xx_write_bridge(sd, st6422_bridge_init[i][0],
236					       st6422_bridge_init[i][1]);
237	}
238
239	return err;
240}
241
242static void st6422_disconnect(struct sd *sd)
243{
244	sd->sensor = NULL;
245	kfree(sd->sensor_priv);
246}
247
248static int setbrightness(struct sd *sd)
249{
250	struct st6422_settings *sensor_settings = sd->sensor_priv;
251
252	/* val goes from 0 -> 31 */
253	return stv06xx_write_bridge(sd, 0x1432,
254			sensor_settings->ctrls[BRIGHTNESS].val);
255}
256
257static int setcontrast(struct sd *sd)
258{
259	struct st6422_settings *sensor_settings = sd->sensor_priv;
260
261	/* Val goes from 0 -> 15 */
262	return stv06xx_write_bridge(sd, 0x143a,
263			sensor_settings->ctrls[CONTRAST].val | 0xf0);
264}
265
266static int setgain(struct sd *sd)
267{
268	struct st6422_settings *sensor_settings = sd->sensor_priv;
269	u8 gain;
270	int err;
271
272	gain = sensor_settings->ctrls[GAIN].val;
273
274	/* Set red, green, blue, gain */
275	err = stv06xx_write_bridge(sd, 0x0509, gain);
276	if (err < 0)
277		return err;
278
279	err = stv06xx_write_bridge(sd, 0x050a, gain);
280	if (err < 0)
281		return err;
282
283	err = stv06xx_write_bridge(sd, 0x050b, gain);
284	if (err < 0)
285		return err;
286
287	/* 2 mystery writes */
288	err = stv06xx_write_bridge(sd, 0x050c, 0x2a);
289	if (err < 0)
290		return err;
291
292	return stv06xx_write_bridge(sd, 0x050d, 0x01);
293}
294
295static int setexposure(struct sd *sd)
296{
297	struct st6422_settings *sensor_settings = sd->sensor_priv;
298	u16 expo;
299	int err;
300
301	expo = sensor_settings->ctrls[EXPOSURE].val;
302	err = stv06xx_write_bridge(sd, 0x143d, expo & 0xff);
303	if (err < 0)
304		return err;
305
306	return stv06xx_write_bridge(sd, 0x143e, expo >> 8);
307}
308
309static int st6422_start(struct sd *sd)
310{
311	int err;
312	struct cam *cam = &sd->gspca_dev.cam;
313
314	if (cam->cam_mode[sd->gspca_dev.curr_mode].priv)
315		err = stv06xx_write_bridge(sd, 0x1505, 0x0f);
316	else
317		err = stv06xx_write_bridge(sd, 0x1505, 0x02);
318	if (err < 0)
319		return err;
320
321	err = setbrightness(sd);
322	if (err < 0)
323		return err;
324
325	err = setcontrast(sd);
326	if (err < 0)
327		return err;
328
329	err = setexposure(sd);
330	if (err < 0)
331		return err;
332
333	err = setgain(sd);
334	if (err < 0)
335		return err;
336
337	/* commit settings */
338	err = stv06xx_write_bridge(sd, 0x143f, 0x01);
339	return (err < 0) ? err : 0;
340}
341
342static int st6422_stop(struct sd *sd)
343{
344	PDEBUG(D_STREAM, "Halting stream");
345
346	return 0;
347}
348
349static void st6422_set_brightness(struct gspca_dev *gspca_dev)
350{
351	int err;
352	struct sd *sd = (struct sd *) gspca_dev;
353
354	err = setbrightness(sd);
355
356	/* commit settings */
357	if (err >= 0)
358		err = stv06xx_write_bridge(sd, 0x143f, 0x01);
359
360	gspca_dev->usb_err = err;
361}
362
363static void st6422_set_contrast(struct gspca_dev *gspca_dev)
364{
365	int err;
366	struct sd *sd = (struct sd *) gspca_dev;
367
368	err = setcontrast(sd);
369
370	/* commit settings */
371	if (err >= 0)
372		err = stv06xx_write_bridge(sd, 0x143f, 0x01);
373
374	gspca_dev->usb_err = err;
375}
376
377static void st6422_set_gain(struct gspca_dev *gspca_dev)
378{
379	int err;
380	struct sd *sd = (struct sd *) gspca_dev;
381
382	err = setgain(sd);
383
384	/* commit settings */
385	if (err >= 0)
386		err = stv06xx_write_bridge(sd, 0x143f, 0x01);
387
388	gspca_dev->usb_err = err;
389}
390
391static void st6422_set_exposure(struct gspca_dev *gspca_dev)
392{
393	int err;
394	struct sd *sd = (struct sd *) gspca_dev;
395
396	err = setexposure(sd);
397
398	/* commit settings */
399	if (err >= 0)
400		err = stv06xx_write_bridge(sd, 0x143f, 0x01);
401
402	gspca_dev->usb_err = err;
403}
404