sn9c102_mi0343.c revision c680dd603857d7218b84751e9f6f0654bbfbefa2
1/***************************************************************************
2 * Plug-in for MI-0343 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 int mi0343_init(struct sn9c102_device* cam)
26{
27	struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
28	int err = 0;
29
30	err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11},
31				       {0x0a, 0x14}, {0x40, 0x01},
32				       {0x20, 0x17}, {0x07, 0x18},
33				       {0xa0, 0x19});
34
35	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
36					 0x00, 0x01, 0, 0);
37	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
38					 0x00, 0x00, 0, 0);
39	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03,
40					 0x01, 0xe1, 0, 0);
41	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04,
42					 0x02, 0x81, 0, 0);
43	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05,
44					 0x00, 0x17, 0, 0);
45	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06,
46					 0x00, 0x11, 0, 0);
47	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x62,
48					 0x04, 0x9a, 0, 0);
49
50	return err;
51}
52
53
54static int mi0343_get_ctrl(struct sn9c102_device* cam,
55			   struct v4l2_control* ctrl)
56{
57	struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
58	u8 data[5+1];
59
60	switch (ctrl->id) {
61	case V4L2_CID_EXPOSURE:
62		if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x09,
63					     2+1, data) < 0)
64			return -EIO;
65		ctrl->value = data[2];
66		return 0;
67	case V4L2_CID_GAIN:
68		if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x35,
69					     2+1, data) < 0)
70			return -EIO;
71		break;
72	case V4L2_CID_HFLIP:
73		if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20,
74					     2+1, data) < 0)
75			return -EIO;
76		ctrl->value = data[3] & 0x20 ? 1 : 0;
77		return 0;
78	case V4L2_CID_VFLIP:
79		if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20,
80					     2+1, data) < 0)
81			return -EIO;
82		ctrl->value = data[3] & 0x80 ? 1 : 0;
83		return 0;
84	case V4L2_CID_RED_BALANCE:
85		if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2d,
86					     2+1, data) < 0)
87			return -EIO;
88		break;
89	case V4L2_CID_BLUE_BALANCE:
90		if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2c,
91					     2+1, data) < 0)
92			return -EIO;
93		break;
94	case SN9C102_V4L2_CID_GREEN_BALANCE:
95		if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2e,
96					     2+1, data) < 0)
97			return -EIO;
98		break;
99	default:
100		return -EINVAL;
101	}
102
103	switch (ctrl->id) {
104	case V4L2_CID_GAIN:
105	case V4L2_CID_RED_BALANCE:
106	case V4L2_CID_BLUE_BALANCE:
107	case SN9C102_V4L2_CID_GREEN_BALANCE:
108		ctrl->value = data[3] | (data[2] << 8);
109		if (ctrl->value >= 0x10 && ctrl->value <= 0x3f)
110			ctrl->value -= 0x10;
111		else if (ctrl->value >= 0x60 && ctrl->value <= 0x7f)
112			ctrl->value -= 0x60;
113		else if (ctrl->value >= 0xe0 && ctrl->value <= 0xff)
114			ctrl->value -= 0xe0;
115	}
116
117	return 0;
118}
119
120
121static int mi0343_set_ctrl(struct sn9c102_device* cam,
122			   const struct v4l2_control* ctrl)
123{
124	struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
125	u16 reg = 0;
126	int err = 0;
127
128	switch (ctrl->id) {
129	case V4L2_CID_GAIN:
130	case V4L2_CID_RED_BALANCE:
131	case V4L2_CID_BLUE_BALANCE:
132	case SN9C102_V4L2_CID_GREEN_BALANCE:
133		if (ctrl->value <= (0x3f-0x10))
134			reg = 0x10 + ctrl->value;
135		else if (ctrl->value <= ((0x3f-0x10) + (0x7f-0x60)))
136			reg = 0x60 + (ctrl->value - (0x3f-0x10));
137		else
138			reg = 0xe0 + (ctrl->value - (0x3f-0x10) - (0x7f-0x60));
139		break;
140	}
141
142	switch (ctrl->id) {
143	case V4L2_CID_EXPOSURE:
144		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
145						 0x09, ctrl->value, 0x00,
146						 0, 0);
147		break;
148	case V4L2_CID_GAIN:
149		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
150						 0x35, reg >> 8, reg & 0xff,
151						 0, 0);
152		break;
153	case V4L2_CID_HFLIP:
154		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
155						 0x20, ctrl->value ? 0x40:0x00,
156						 ctrl->value ? 0x20:0x00,
157						 0, 0);
158		break;
159	case V4L2_CID_VFLIP:
160		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
161						 0x20, ctrl->value ? 0x80:0x00,
162						 ctrl->value ? 0x80:0x00,
163						 0, 0);
164		break;
165	case V4L2_CID_RED_BALANCE:
166		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
167						 0x2d, reg >> 8, reg & 0xff,
168						 0, 0);
169		break;
170	case V4L2_CID_BLUE_BALANCE:
171		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
172						 0x2c, reg >> 8, reg & 0xff,
173						 0, 0);
174		break;
175	case SN9C102_V4L2_CID_GREEN_BALANCE:
176		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
177						 0x2b, reg >> 8, reg & 0xff,
178						 0, 0);
179		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
180						 0x2e, reg >> 8, reg & 0xff,
181						 0, 0);
182		break;
183	default:
184		return -EINVAL;
185	}
186
187	return err ? -EIO : 0;
188}
189
190
191static int mi0343_set_crop(struct sn9c102_device* cam,
192			    const struct v4l2_rect* rect)
193{
194	struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
195	int err = 0;
196	u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0,
197	   v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2;
198
199	err += sn9c102_write_reg(cam, h_start, 0x12);
200	err += sn9c102_write_reg(cam, v_start, 0x13);
201
202	return err;
203}
204
205
206static int mi0343_set_pix_format(struct sn9c102_device* cam,
207				 const struct v4l2_pix_format* pix)
208{
209	struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
210	int err = 0;
211
212	if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) {
213		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
214						 0x0a, 0x00, 0x03, 0, 0);
215		err += sn9c102_write_reg(cam, 0x20, 0x19);
216	} else {
217		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
218						 0x0a, 0x00, 0x05, 0, 0);
219		err += sn9c102_write_reg(cam, 0xa0, 0x19);
220	}
221
222	return err;
223}
224
225
226static struct sn9c102_sensor mi0343 = {
227	.name = "MI-0343",
228	.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
229	.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
230	.frequency = SN9C102_I2C_100KHZ,
231	.interface = SN9C102_I2C_2WIRES,
232	.i2c_slave_id = 0x5d,
233	.init = &mi0343_init,
234	.qctrl = {
235		{
236			.id = V4L2_CID_EXPOSURE,
237			.type = V4L2_CTRL_TYPE_INTEGER,
238			.name = "exposure",
239			.minimum = 0x00,
240			.maximum = 0x0f,
241			.step = 0x01,
242			.default_value = 0x06,
243			.flags = 0,
244		},
245		{
246			.id = V4L2_CID_GAIN,
247			.type = V4L2_CTRL_TYPE_INTEGER,
248			.name = "global gain",
249			.minimum = 0x00,
250			.maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),/*0x6d*/
251			.step = 0x01,
252			.default_value = 0x00,
253			.flags = 0,
254		},
255		{
256			.id = V4L2_CID_HFLIP,
257			.type = V4L2_CTRL_TYPE_BOOLEAN,
258			.name = "horizontal mirror",
259			.minimum = 0,
260			.maximum = 1,
261			.step = 1,
262			.default_value = 0,
263			.flags = 0,
264		},
265		{
266			.id = V4L2_CID_VFLIP,
267			.type = V4L2_CTRL_TYPE_BOOLEAN,
268			.name = "vertical mirror",
269			.minimum = 0,
270			.maximum = 1,
271			.step = 1,
272			.default_value = 0,
273			.flags = 0,
274		},
275		{
276			.id = V4L2_CID_RED_BALANCE,
277			.type = V4L2_CTRL_TYPE_INTEGER,
278			.name = "red balance",
279			.minimum = 0x00,
280			.maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),
281			.step = 0x01,
282			.default_value = 0x00,
283			.flags = 0,
284		},
285		{
286			.id = V4L2_CID_BLUE_BALANCE,
287			.type = V4L2_CTRL_TYPE_INTEGER,
288			.name = "blue balance",
289			.minimum = 0x00,
290			.maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),
291			.step = 0x01,
292			.default_value = 0x00,
293			.flags = 0,
294		},
295		{
296			.id = SN9C102_V4L2_CID_GREEN_BALANCE,
297			.type = V4L2_CTRL_TYPE_INTEGER,
298			.name = "green balance",
299			.minimum = 0x00,
300			.maximum = ((0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0)),
301			.step = 0x01,
302			.default_value = 0x00,
303			.flags = 0,
304		},
305	},
306	.get_ctrl = &mi0343_get_ctrl,
307	.set_ctrl = &mi0343_set_ctrl,
308	.cropcap = {
309		.bounds = {
310			.left = 0,
311			.top = 0,
312			.width = 640,
313			.height = 480,
314		},
315		.defrect = {
316			.left = 0,
317			.top = 0,
318			.width = 640,
319			.height = 480,
320		},
321	},
322	.set_crop = &mi0343_set_crop,
323	.pix_format = {
324		.width = 640,
325		.height = 480,
326		.pixelformat = V4L2_PIX_FMT_SBGGR8,
327		.priv = 8,
328	},
329	.set_pix_format = &mi0343_set_pix_format
330};
331
332
333int sn9c102_probe_mi0343(struct sn9c102_device* cam)
334{
335	u8 data[5+1];
336	int err = 0;
337
338	err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01},
339				       {0x28, 0x17});
340
341	if (err)
342		return -EIO;
343
344	if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, 0x00,
345				     2, data) < 0)
346		return -EIO;
347
348	if (data[4] != 0x32 || data[3] != 0xe3)
349		return -ENODEV;
350
351	sn9c102_attach_sensor(cam, &mi0343);
352
353	return 0;
354}
355