Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
sn9c102_mi0343.c
Go to the documentation of this file.
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 <[email protected]> *
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 
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 
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;
86  if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2d, 2,
87  data) < 0)
88  return -EIO;
89  break;
91  if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2c, 2,
92  data) < 0)
93  return -EIO;
94  break;
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:
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 
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:
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;
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;
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;
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 
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 
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 <[email protected]>",
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  {
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 
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 }