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