Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
sn9c102_hv7131r.c
Go to the documentation of this file.
1 /***************************************************************************
2  * Plug-in for HV7131R image sensor connected to the SN9C1xx PC Camera *
3  * Controllers *
4  * *
5  * Copyright (C) 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 hv7131r_init(struct sn9c102_device* cam)
27 {
28  int err = 0;
29 
30  switch (sn9c102_get_bridge(cam)) {
31  case BRIDGE_SN9C103:
32  err = sn9c102_write_const_regs(cam, {0x00, 0x03}, {0x1a, 0x04},
33  {0x20, 0x05}, {0x20, 0x06},
34  {0x03, 0x10}, {0x00, 0x14},
35  {0x60, 0x17}, {0x0a, 0x18},
36  {0xf0, 0x19}, {0x1d, 0x1a},
37  {0x10, 0x1b}, {0x02, 0x1c},
38  {0x03, 0x1d}, {0x0f, 0x1e},
39  {0x0c, 0x1f}, {0x00, 0x20},
40  {0x10, 0x21}, {0x20, 0x22},
41  {0x30, 0x23}, {0x40, 0x24},
42  {0x50, 0x25}, {0x60, 0x26},
43  {0x70, 0x27}, {0x80, 0x28},
44  {0x90, 0x29}, {0xa0, 0x2a},
45  {0xb0, 0x2b}, {0xc0, 0x2c},
46  {0xd0, 0x2d}, {0xe0, 0x2e},
47  {0xf0, 0x2f}, {0xff, 0x30});
48  break;
49  case BRIDGE_SN9C105:
50  case BRIDGE_SN9C120:
51  err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02},
52  {0x00, 0x03}, {0x1a, 0x04},
53  {0x44, 0x05}, {0x3e, 0x06},
54  {0x1a, 0x07}, {0x03, 0x10},
55  {0x08, 0x14}, {0xa3, 0x17},
56  {0x4b, 0x18}, {0x00, 0x19},
57  {0x1d, 0x1a}, {0x10, 0x1b},
58  {0x02, 0x1c}, {0x03, 0x1d},
59  {0x0f, 0x1e}, {0x0c, 0x1f},
60  {0x00, 0x20}, {0x29, 0x21},
61  {0x40, 0x22}, {0x54, 0x23},
62  {0x66, 0x24}, {0x76, 0x25},
63  {0x85, 0x26}, {0x94, 0x27},
64  {0xa1, 0x28}, {0xae, 0x29},
65  {0xbb, 0x2a}, {0xc7, 0x2b},
66  {0xd3, 0x2c}, {0xde, 0x2d},
67  {0xea, 0x2e}, {0xf4, 0x2f},
68  {0xff, 0x30}, {0x00, 0x3F},
69  {0xC7, 0x40}, {0x01, 0x41},
70  {0x44, 0x42}, {0x00, 0x43},
71  {0x44, 0x44}, {0x00, 0x45},
72  {0x44, 0x46}, {0x00, 0x47},
73  {0xC7, 0x48}, {0x01, 0x49},
74  {0xC7, 0x4A}, {0x01, 0x4B},
75  {0xC7, 0x4C}, {0x01, 0x4D},
76  {0x44, 0x4E}, {0x00, 0x4F},
77  {0x44, 0x50}, {0x00, 0x51},
78  {0x44, 0x52}, {0x00, 0x53},
79  {0xC7, 0x54}, {0x01, 0x55},
80  {0xC7, 0x56}, {0x01, 0x57},
81  {0xC7, 0x58}, {0x01, 0x59},
82  {0x44, 0x5A}, {0x00, 0x5B},
83  {0x44, 0x5C}, {0x00, 0x5D},
84  {0x44, 0x5E}, {0x00, 0x5F},
85  {0xC7, 0x60}, {0x01, 0x61},
86  {0xC7, 0x62}, {0x01, 0x63},
87  {0xC7, 0x64}, {0x01, 0x65},
88  {0x44, 0x66}, {0x00, 0x67},
89  {0x44, 0x68}, {0x00, 0x69},
90  {0x44, 0x6A}, {0x00, 0x6B},
91  {0xC7, 0x6C}, {0x01, 0x6D},
92  {0xC7, 0x6E}, {0x01, 0x6F},
93  {0xC7, 0x70}, {0x01, 0x71},
94  {0x44, 0x72}, {0x00, 0x73},
95  {0x44, 0x74}, {0x00, 0x75},
96  {0x44, 0x76}, {0x00, 0x77},
97  {0xC7, 0x78}, {0x01, 0x79},
98  {0xC7, 0x7A}, {0x01, 0x7B},
99  {0xC7, 0x7C}, {0x01, 0x7D},
100  {0x44, 0x7E}, {0x00, 0x7F},
101  {0x14, 0x84}, {0x00, 0x85},
102  {0x27, 0x86}, {0x00, 0x87},
103  {0x07, 0x88}, {0x00, 0x89},
104  {0xEC, 0x8A}, {0x0f, 0x8B},
105  {0xD8, 0x8C}, {0x0f, 0x8D},
106  {0x3D, 0x8E}, {0x00, 0x8F},
107  {0x3D, 0x90}, {0x00, 0x91},
108  {0xCD, 0x92}, {0x0f, 0x93},
109  {0xf7, 0x94}, {0x0f, 0x95},
110  {0x0C, 0x96}, {0x00, 0x97},
111  {0x00, 0x98}, {0x66, 0x99},
112  {0x05, 0x9A}, {0x00, 0x9B},
113  {0x04, 0x9C}, {0x00, 0x9D},
114  {0x08, 0x9E}, {0x00, 0x9F},
115  {0x2D, 0xC0}, {0x2D, 0xC1},
116  {0x3A, 0xC2}, {0x05, 0xC3},
117  {0x04, 0xC4}, {0x3F, 0xC5},
118  {0x00, 0xC6}, {0x00, 0xC7},
119  {0x50, 0xC8}, {0x3C, 0xC9},
120  {0x28, 0xCA}, {0xD8, 0xCB},
121  {0x14, 0xCC}, {0xEC, 0xCD},
122  {0x32, 0xCE}, {0xDD, 0xCF},
123  {0x32, 0xD0}, {0xDD, 0xD1},
124  {0x6A, 0xD2}, {0x50, 0xD3},
125  {0x00, 0xD4}, {0x00, 0xD5},
126  {0x00, 0xD6});
127  break;
128  default:
129  break;
130  }
131 
132  err += sn9c102_i2c_write(cam, 0x20, 0x00);
133  err += sn9c102_i2c_write(cam, 0x21, 0xd6);
134  err += sn9c102_i2c_write(cam, 0x25, 0x06);
135 
136  return err;
137 }
138 
139 
140 static int hv7131r_get_ctrl(struct sn9c102_device* cam,
141  struct v4l2_control* ctrl)
142 {
143  switch (ctrl->id) {
144  case V4L2_CID_GAIN:
145  if ((ctrl->value = sn9c102_i2c_read(cam, 0x30)) < 0)
146  return -EIO;
147  return 0;
149  if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0)
150  return -EIO;
151  ctrl->value = ctrl->value & 0x3f;
152  return 0;
154  if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0)
155  return -EIO;
156  ctrl->value = ctrl->value & 0x3f;
157  return 0;
159  if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0)
160  return -EIO;
161  ctrl->value = ctrl->value & 0x3f;
162  return 0;
164  if ((ctrl->value = sn9c102_i2c_read(cam, 0x01)) < 0)
165  return -EIO;
166  ctrl->value = (ctrl->value & 0x08) ? 1 : 0;
167  return 0;
168  default:
169  return -EINVAL;
170  }
171 }
172 
173 
174 static int hv7131r_set_ctrl(struct sn9c102_device* cam,
175  const struct v4l2_control* ctrl)
176 {
177  int err = 0;
178 
179  switch (ctrl->id) {
180  case V4L2_CID_GAIN:
181  err += sn9c102_i2c_write(cam, 0x30, ctrl->value);
182  break;
184  err += sn9c102_i2c_write(cam, 0x31, ctrl->value);
185  break;
187  err += sn9c102_i2c_write(cam, 0x33, ctrl->value);
188  break;
190  err += sn9c102_i2c_write(cam, 0x32, ctrl->value);
191  break;
193  {
194  int r = sn9c102_i2c_read(cam, 0x01);
195  if (r < 0)
196  return -EIO;
197  err += sn9c102_i2c_write(cam, 0x01,
198  (ctrl->value<<3) | (r&0xf7));
199  }
200  break;
201  default:
202  return -EINVAL;
203  }
204 
205  return err ? -EIO : 0;
206 }
207 
208 
209 static int hv7131r_set_crop(struct sn9c102_device* cam,
210  const struct v4l2_rect* rect)
211 {
212  struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
213  int err = 0;
214  u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1,
215  v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
216 
217  err += sn9c102_write_reg(cam, h_start, 0x12);
218  err += sn9c102_write_reg(cam, v_start, 0x13);
219 
220  return err;
221 }
222 
223 
224 static int hv7131r_set_pix_format(struct sn9c102_device* cam,
225  const struct v4l2_pix_format* pix)
226 {
227  int err = 0;
228 
229  switch (sn9c102_get_bridge(cam)) {
230  case BRIDGE_SN9C103:
231  if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
232  err += sn9c102_write_reg(cam, 0xa0, 0x19);
233  err += sn9c102_i2c_write(cam, 0x01, 0x04);
234  } else {
235  err += sn9c102_write_reg(cam, 0x30, 0x19);
236  err += sn9c102_i2c_write(cam, 0x01, 0x04);
237  }
238  break;
239  case BRIDGE_SN9C105:
240  case BRIDGE_SN9C120:
241  if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
242  err += sn9c102_write_reg(cam, 0xa5, 0x17);
243  err += sn9c102_i2c_write(cam, 0x01, 0x24);
244  } else {
245  err += sn9c102_write_reg(cam, 0xa3, 0x17);
246  err += sn9c102_i2c_write(cam, 0x01, 0x04);
247  }
248  break;
249  default:
250  break;
251  }
252 
253  return err;
254 }
255 
256 
257 static const struct sn9c102_sensor hv7131r = {
258  .name = "HV7131R",
259  .maintainer = "Luca Risolia <[email protected]>",
260  .supported_bridge = BRIDGE_SN9C103 | BRIDGE_SN9C105 | BRIDGE_SN9C120,
261  .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
262  .frequency = SN9C102_I2C_100KHZ,
263  .interface = SN9C102_I2C_2WIRES,
264  .i2c_slave_id = 0x11,
265  .init = &hv7131r_init,
266  .qctrl = {
267  {
268  .id = V4L2_CID_GAIN,
269  .type = V4L2_CTRL_TYPE_INTEGER,
270  .name = "global gain",
271  .minimum = 0x00,
272  .maximum = 0xff,
273  .step = 0x01,
274  .default_value = 0x40,
275  .flags = 0,
276  },
277  {
278  .id = V4L2_CID_RED_BALANCE,
279  .type = V4L2_CTRL_TYPE_INTEGER,
280  .name = "red balance",
281  .minimum = 0x00,
282  .maximum = 0x3f,
283  .step = 0x01,
284  .default_value = 0x08,
285  .flags = 0,
286  },
287  {
288  .id = V4L2_CID_BLUE_BALANCE,
289  .type = V4L2_CTRL_TYPE_INTEGER,
290  .name = "blue balance",
291  .minimum = 0x00,
292  .maximum = 0x3f,
293  .step = 0x01,
294  .default_value = 0x1a,
295  .flags = 0,
296  },
297  {
299  .type = V4L2_CTRL_TYPE_INTEGER,
300  .name = "green balance",
301  .minimum = 0x00,
302  .maximum = 0x3f,
303  .step = 0x01,
304  .default_value = 0x2f,
305  .flags = 0,
306  },
307  {
308  .id = V4L2_CID_BLACK_LEVEL,
309  .type = V4L2_CTRL_TYPE_BOOLEAN,
310  .name = "auto black level compensation",
311  .minimum = 0x00,
312  .maximum = 0x01,
313  .step = 0x01,
314  .default_value = 0x00,
315  .flags = 0,
316  },
317  },
318  .get_ctrl = &hv7131r_get_ctrl,
319  .set_ctrl = &hv7131r_set_ctrl,
320  .cropcap = {
321  .bounds = {
322  .left = 0,
323  .top = 0,
324  .width = 640,
325  .height = 480,
326  },
327  .defrect = {
328  .left = 0,
329  .top = 0,
330  .width = 640,
331  .height = 480,
332  },
333  },
334  .set_crop = &hv7131r_set_crop,
335  .pix_format = {
336  .width = 640,
337  .height = 480,
338  .pixelformat = V4L2_PIX_FMT_SBGGR8,
339  .priv = 8,
340  },
341  .set_pix_format = &hv7131r_set_pix_format
342 };
343 
344 
346 {
347  int devid, err;
348 
349  err = sn9c102_write_const_regs(cam, {0x09, 0x01}, {0x44, 0x02},
350  {0x34, 0x01}, {0x20, 0x17},
351  {0x34, 0x01}, {0x46, 0x01});
352 
353  devid = sn9c102_i2c_try_read(cam, &hv7131r, 0x00);
354  if (err || devid < 0)
355  return -EIO;
356 
357  if (devid != 0x02)
358  return -ENODEV;
359 
360  sn9c102_attach_sensor(cam, &hv7131r);
361 
362  return 0;
363 }