1/*
2 * Driver for the ov7660 sensor
3 *
4 * Copyright (C) 2009 Erik Andr��n
5 * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
6 * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
7 *
8 * Portions of code to USB interface and ALi driver software,
9 * Copyright (c) 2006 Willem Duinker
10 * v4l2 interface modeled after the V4L2 driver
11 * for SN9C10x PC Camera Controllers
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License as
15 * published by the Free Software Foundation, version 2.
16 *
17 */
18
19#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
20
21#include "m5602_ov7660.h"
22
23static int ov7660_s_ctrl(struct v4l2_ctrl *ctrl);
24static void ov7660_dump_registers(struct sd *sd);
25
26static struct v4l2_pix_format ov7660_modes[] = {
27	{
28		640,
29		480,
30		V4L2_PIX_FMT_SBGGR8,
31		V4L2_FIELD_NONE,
32		.sizeimage =
33			640 * 480,
34		.bytesperline = 640,
35		.colorspace = V4L2_COLORSPACE_SRGB,
36		.priv = 0
37	}
38};
39
40static const struct v4l2_ctrl_ops ov7660_ctrl_ops = {
41	.s_ctrl = ov7660_s_ctrl,
42};
43
44int ov7660_probe(struct sd *sd)
45{
46	int err = 0, i;
47	u8 prod_id = 0, ver_id = 0;
48
49	if (force_sensor) {
50		if (force_sensor == OV7660_SENSOR) {
51			pr_info("Forcing an %s sensor\n", ov7660.name);
52			goto sensor_found;
53		}
54		/* If we want to force another sensor,
55		don't try to probe this one */
56		return -ENODEV;
57	}
58
59	/* Do the preinit */
60	for (i = 0; i < ARRAY_SIZE(preinit_ov7660) && !err; i++) {
61		u8 data[2];
62
63		if (preinit_ov7660[i][0] == BRIDGE) {
64			err = m5602_write_bridge(sd,
65				preinit_ov7660[i][1],
66				preinit_ov7660[i][2]);
67		} else {
68			data[0] = preinit_ov7660[i][2];
69			err = m5602_write_sensor(sd,
70				preinit_ov7660[i][1], data, 1);
71		}
72	}
73	if (err < 0)
74		return err;
75
76	if (m5602_read_sensor(sd, OV7660_PID, &prod_id, 1))
77		return -ENODEV;
78
79	if (m5602_read_sensor(sd, OV7660_VER, &ver_id, 1))
80		return -ENODEV;
81
82	pr_info("Sensor reported 0x%x%x\n", prod_id, ver_id);
83
84	if ((prod_id == 0x76) && (ver_id == 0x60)) {
85		pr_info("Detected a ov7660 sensor\n");
86		goto sensor_found;
87	}
88	return -ENODEV;
89
90sensor_found:
91	sd->gspca_dev.cam.cam_mode = ov7660_modes;
92	sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov7660_modes);
93
94	return 0;
95}
96
97int ov7660_init(struct sd *sd)
98{
99	int i, err;
100
101	/* Init the sensor */
102	for (i = 0; i < ARRAY_SIZE(init_ov7660); i++) {
103		u8 data[2];
104
105		if (init_ov7660[i][0] == BRIDGE) {
106			err = m5602_write_bridge(sd,
107				init_ov7660[i][1],
108				init_ov7660[i][2]);
109		} else {
110			data[0] = init_ov7660[i][2];
111			err = m5602_write_sensor(sd,
112				init_ov7660[i][1], data, 1);
113		}
114		if (err < 0)
115			return err;
116	}
117
118	if (dump_sensor)
119		ov7660_dump_registers(sd);
120
121	return 0;
122}
123
124int ov7660_init_controls(struct sd *sd)
125{
126	struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
127
128	sd->gspca_dev.vdev.ctrl_handler = hdl;
129	v4l2_ctrl_handler_init(hdl, 6);
130
131	v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE,
132			  0, 1, 1, 1);
133	v4l2_ctrl_new_std_menu(hdl, &ov7660_ctrl_ops,
134			  V4L2_CID_EXPOSURE_AUTO, 1, 0, V4L2_EXPOSURE_AUTO);
135
136	sd->autogain = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops,
137					 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
138	sd->gain = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_GAIN, 0,
139				     255, 1, OV7660_DEFAULT_GAIN);
140
141	sd->hflip = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_HFLIP,
142				      0, 1, 1, 0);
143	sd->vflip = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_VFLIP,
144				      0, 1, 1, 0);
145
146	if (hdl->error) {
147		pr_err("Could not initialize controls\n");
148		return hdl->error;
149	}
150
151	v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, false);
152	v4l2_ctrl_cluster(2, &sd->hflip);
153
154	return 0;
155}
156
157int ov7660_start(struct sd *sd)
158{
159	return 0;
160}
161
162int ov7660_stop(struct sd *sd)
163{
164	return 0;
165}
166
167void ov7660_disconnect(struct sd *sd)
168{
169	ov7660_stop(sd);
170
171	sd->sensor = NULL;
172}
173
174static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val)
175{
176	int err;
177	u8 i2c_data = val;
178	struct sd *sd = (struct sd *) gspca_dev;
179
180	PDEBUG(D_CONF, "Setting gain to %d", val);
181
182	err = m5602_write_sensor(sd, OV7660_GAIN, &i2c_data, 1);
183	return err;
184}
185
186static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev,
187					 __s32 val)
188{
189	int err;
190	u8 i2c_data;
191	struct sd *sd = (struct sd *) gspca_dev;
192
193	PDEBUG(D_CONF, "Set auto white balance to %d", val);
194
195	err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
196	if (err < 0)
197		return err;
198
199	i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1));
200	err = m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
201
202	return err;
203}
204
205static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
206{
207	int err;
208	u8 i2c_data;
209	struct sd *sd = (struct sd *) gspca_dev;
210
211	PDEBUG(D_CONF, "Set auto gain control to %d", val);
212
213	err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
214	if (err < 0)
215		return err;
216
217	i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2));
218
219	return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
220}
221
222static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev,
223				    __s32 val)
224{
225	int err;
226	u8 i2c_data;
227	struct sd *sd = (struct sd *) gspca_dev;
228
229	PDEBUG(D_CONF, "Set auto exposure control to %d", val);
230
231	err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
232	if (err < 0)
233		return err;
234
235	val = (val == V4L2_EXPOSURE_AUTO);
236	i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0));
237
238	return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
239}
240
241static int ov7660_set_hvflip(struct gspca_dev *gspca_dev)
242{
243	int err;
244	u8 i2c_data;
245	struct sd *sd = (struct sd *) gspca_dev;
246
247	PDEBUG(D_CONF, "Set hvflip to %d, %d", sd->hflip->val, sd->vflip->val);
248
249	i2c_data = (sd->hflip->val << 5) | (sd->vflip->val << 4);
250
251	err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1);
252
253	return err;
254}
255
256static int ov7660_s_ctrl(struct v4l2_ctrl *ctrl)
257{
258	struct gspca_dev *gspca_dev =
259		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
260	struct sd *sd = (struct sd *) gspca_dev;
261	int err;
262
263	if (!gspca_dev->streaming)
264		return 0;
265
266	switch (ctrl->id) {
267	case V4L2_CID_AUTO_WHITE_BALANCE:
268		err = ov7660_set_auto_white_balance(gspca_dev, ctrl->val);
269		break;
270	case V4L2_CID_EXPOSURE_AUTO:
271		err = ov7660_set_auto_exposure(gspca_dev, ctrl->val);
272		break;
273	case V4L2_CID_AUTOGAIN:
274		err = ov7660_set_auto_gain(gspca_dev, ctrl->val);
275		if (err || ctrl->val)
276			return err;
277		err = ov7660_set_gain(gspca_dev, sd->gain->val);
278		break;
279	case V4L2_CID_HFLIP:
280		err = ov7660_set_hvflip(gspca_dev);
281		break;
282	default:
283		return -EINVAL;
284	}
285
286	return err;
287}
288
289static void ov7660_dump_registers(struct sd *sd)
290{
291	int address;
292	pr_info("Dumping the ov7660 register state\n");
293	for (address = 0; address < 0xa9; address++) {
294		u8 value;
295		m5602_read_sensor(sd, address, &value, 1);
296		pr_info("register 0x%x contains 0x%x\n", address, value);
297	}
298
299	pr_info("ov7660 register state dump complete\n");
300
301	pr_info("Probing for which registers that are read/write\n");
302	for (address = 0; address < 0xff; address++) {
303		u8 old_value, ctrl_value;
304		u8 test_value[2] = {0xff, 0xff};
305
306		m5602_read_sensor(sd, address, &old_value, 1);
307		m5602_write_sensor(sd, address, test_value, 1);
308		m5602_read_sensor(sd, address, &ctrl_value, 1);
309
310		if (ctrl_value == test_value[0])
311			pr_info("register 0x%x is writeable\n", address);
312		else
313			pr_info("register 0x%x is read only\n", address);
314
315		/* Restore original value */
316		m5602_write_sensor(sd, address, &old_value, 1);
317	}
318}
319