sn9c102_hv7131d.c revision f327ebbd004fb2f08291ca4c6637f5f27319683c
1/***************************************************************************
2 * Plug-in for HV7131D image sensor connected to the SN9C1xx PC Camera     *
3 * Controllers                                                             *
4 *                                                                         *
5 * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
6 *                                                                         *
7 * This program is free software; you can redistribute it and/or modify    *
8 * it under the terms of the GNU General Public License as published by    *
9 * the Free Software Foundation; either version 2 of the License, or       *
10 * (at your option) any later version.                                     *
11 *                                                                         *
12 * This program is distributed in the hope that it will be useful,         *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
15 * GNU General Public License for more details.                            *
16 *                                                                         *
17 * You should have received a copy of the GNU General Public License       *
18 * along with this program; if not, write to the Free Software             *
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
20 ***************************************************************************/
21
22#include "sn9c102_sensor.h"
23
24
25static struct sn9c102_sensor hv7131d;
26
27
28static int hv7131d_init(struct sn9c102_device* cam)
29{
30	int err = 0;
31
32	err += sn9c102_write_reg(cam, 0x00, 0x10);
33	err += sn9c102_write_reg(cam, 0x00, 0x11);
34	err += sn9c102_write_reg(cam, 0x00, 0x14);
35	err += sn9c102_write_reg(cam, 0x60, 0x17);
36	err += sn9c102_write_reg(cam, 0x0e, 0x18);
37	err += sn9c102_write_reg(cam, 0xf2, 0x19);
38
39	err += sn9c102_i2c_write(cam, 0x01, 0x04);
40	err += sn9c102_i2c_write(cam, 0x02, 0x00);
41	err += sn9c102_i2c_write(cam, 0x28, 0x00);
42
43	return err;
44}
45
46
47static int hv7131d_get_ctrl(struct sn9c102_device* cam,
48			    struct v4l2_control* ctrl)
49{
50	switch (ctrl->id) {
51	case V4L2_CID_EXPOSURE:
52		{
53			int r1 = sn9c102_i2c_read(cam, 0x26),
54			    r2 = sn9c102_i2c_read(cam, 0x27);
55			if (r1 < 0 || r2 < 0)
56				return -EIO;
57			ctrl->value = (r1 << 8) | (r2 & 0xff);
58		}
59		return 0;
60	case V4L2_CID_RED_BALANCE:
61		if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0)
62			return -EIO;
63		ctrl->value = 0x3f - (ctrl->value & 0x3f);
64		return 0;
65	case V4L2_CID_BLUE_BALANCE:
66		if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0)
67			return -EIO;
68		ctrl->value = 0x3f - (ctrl->value & 0x3f);
69		return 0;
70	case SN9C102_V4L2_CID_GREEN_BALANCE:
71		if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0)
72			return -EIO;
73		ctrl->value = 0x3f - (ctrl->value & 0x3f);
74		return 0;
75	case SN9C102_V4L2_CID_RESET_LEVEL:
76		if ((ctrl->value = sn9c102_i2c_read(cam, 0x30)) < 0)
77			return -EIO;
78		ctrl->value &= 0x3f;
79		return 0;
80	case SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE:
81		if ((ctrl->value = sn9c102_i2c_read(cam, 0x34)) < 0)
82			return -EIO;
83		ctrl->value &= 0x07;
84		return 0;
85	default:
86		return -EINVAL;
87	}
88}
89
90
91static int hv7131d_set_ctrl(struct sn9c102_device* cam,
92			    const struct v4l2_control* ctrl)
93{
94	int err = 0;
95
96	switch (ctrl->id) {
97	case V4L2_CID_EXPOSURE:
98		err += sn9c102_i2c_write(cam, 0x26, ctrl->value >> 8);
99		err += sn9c102_i2c_write(cam, 0x27, ctrl->value & 0xff);
100		break;
101	case V4L2_CID_RED_BALANCE:
102		err += sn9c102_i2c_write(cam, 0x31, 0x3f - ctrl->value);
103		break;
104	case V4L2_CID_BLUE_BALANCE:
105		err += sn9c102_i2c_write(cam, 0x33, 0x3f - ctrl->value);
106		break;
107	case SN9C102_V4L2_CID_GREEN_BALANCE:
108		err += sn9c102_i2c_write(cam, 0x32, 0x3f - ctrl->value);
109		break;
110	case SN9C102_V4L2_CID_RESET_LEVEL:
111		err += sn9c102_i2c_write(cam, 0x30, ctrl->value);
112		break;
113	case SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE:
114		err += sn9c102_i2c_write(cam, 0x34, ctrl->value);
115		break;
116	default:
117		return -EINVAL;
118	}
119
120	return err ? -EIO : 0;
121}
122
123
124static int hv7131d_set_crop(struct sn9c102_device* cam,
125			    const struct v4l2_rect* rect)
126{
127	struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
128	int err = 0;
129	u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 2,
130	   v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2;
131
132	err += sn9c102_write_reg(cam, h_start, 0x12);
133	err += sn9c102_write_reg(cam, v_start, 0x13);
134
135	return err;
136}
137
138
139static int hv7131d_set_pix_format(struct sn9c102_device* cam,
140				  const struct v4l2_pix_format* pix)
141{
142	int err = 0;
143
144	if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
145		err += sn9c102_write_reg(cam, 0x42, 0x19);
146	else
147		err += sn9c102_write_reg(cam, 0xf2, 0x19);
148
149	return err;
150}
151
152
153static struct sn9c102_sensor hv7131d = {
154	.name = "HV7131D",
155	.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
156	.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
157	.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
158	.frequency = SN9C102_I2C_100KHZ,
159	.interface = SN9C102_I2C_2WIRES,
160	.i2c_slave_id = 0x11,
161	.init = &hv7131d_init,
162	.qctrl = {
163		{
164			.id = V4L2_CID_EXPOSURE,
165			.type = V4L2_CTRL_TYPE_INTEGER,
166			.name = "exposure",
167			.minimum = 0x0250,
168			.maximum = 0xffff,
169			.step = 0x0001,
170			.default_value = 0x0250,
171			.flags = 0,
172		},
173		{
174			.id = V4L2_CID_RED_BALANCE,
175			.type = V4L2_CTRL_TYPE_INTEGER,
176			.name = "red balance",
177			.minimum = 0x00,
178			.maximum = 0x3f,
179			.step = 0x01,
180			.default_value = 0x00,
181			.flags = 0,
182		},
183		{
184			.id = V4L2_CID_BLUE_BALANCE,
185			.type = V4L2_CTRL_TYPE_INTEGER,
186			.name = "blue balance",
187			.minimum = 0x00,
188			.maximum = 0x3f,
189			.step = 0x01,
190			.default_value = 0x20,
191			.flags = 0,
192		},
193		{
194			.id = SN9C102_V4L2_CID_GREEN_BALANCE,
195			.type = V4L2_CTRL_TYPE_INTEGER,
196			.name = "green balance",
197			.minimum = 0x00,
198			.maximum = 0x3f,
199			.step = 0x01,
200			.default_value = 0x1e,
201			.flags = 0,
202		},
203		{
204			.id = SN9C102_V4L2_CID_RESET_LEVEL,
205			.type = V4L2_CTRL_TYPE_INTEGER,
206			.name = "reset level",
207			.minimum = 0x19,
208			.maximum = 0x3f,
209			.step = 0x01,
210			.default_value = 0x30,
211			.flags = 0,
212		},
213		{
214			.id = SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE,
215			.type = V4L2_CTRL_TYPE_INTEGER,
216			.name = "pixel bias voltage",
217			.minimum = 0x00,
218			.maximum = 0x07,
219			.step = 0x01,
220			.default_value = 0x02,
221			.flags = 0,
222		},
223	},
224	.get_ctrl = &hv7131d_get_ctrl,
225	.set_ctrl = &hv7131d_set_ctrl,
226	.cropcap = {
227		.bounds = {
228			.left = 0,
229			.top = 0,
230			.width = 640,
231			.height = 480,
232		},
233		.defrect = {
234			.left = 0,
235			.top = 0,
236			.width = 640,
237			.height = 480,
238		},
239	},
240	.set_crop = &hv7131d_set_crop,
241	.pix_format = {
242		.width = 640,
243		.height = 480,
244		.pixelformat = V4L2_PIX_FMT_SBGGR8,
245		.priv = 8,
246	},
247	.set_pix_format = &hv7131d_set_pix_format
248};
249
250
251int sn9c102_probe_hv7131d(struct sn9c102_device* cam)
252{
253	int r0 = 0, r1 = 0, err = 0;
254
255	err += sn9c102_write_reg(cam, 0x01, 0x01);
256	err += sn9c102_write_reg(cam, 0x00, 0x01);
257	err += sn9c102_write_reg(cam, 0x28, 0x17);
258	if (err)
259		return -EIO;
260
261	r0 = sn9c102_i2c_try_read(cam, &hv7131d, 0x00);
262	r1 = sn9c102_i2c_try_read(cam, &hv7131d, 0x01);
263	if (r0 < 0 || r1 < 0)
264		return -EIO;
265
266	if (r0 != 0x00 && r1 != 0x04)
267		return -ENODEV;
268
269	sn9c102_attach_sensor(cam, &hv7131d);
270
271	return 0;
272}
273