Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
sn9c102_pas106b.c
Go to the documentation of this file.
1 /***************************************************************************
2  * Plug-in for PAS106B 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 <linux/delay.h>
23 #include "sn9c102_sensor.h"
24 #include "sn9c102_devtable.h"
25 
26 
27 static int pas106b_init(struct sn9c102_device* cam)
28 {
29  int err = 0;
30 
31  err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11},
32  {0x00, 0x14}, {0x20, 0x17},
33  {0x20, 0x19}, {0x09, 0x18});
34 
35  err += sn9c102_i2c_write(cam, 0x02, 0x0c);
36  err += sn9c102_i2c_write(cam, 0x05, 0x5a);
37  err += sn9c102_i2c_write(cam, 0x06, 0x88);
38  err += sn9c102_i2c_write(cam, 0x07, 0x80);
39  err += sn9c102_i2c_write(cam, 0x10, 0x06);
40  err += sn9c102_i2c_write(cam, 0x11, 0x06);
41  err += sn9c102_i2c_write(cam, 0x12, 0x00);
42  err += sn9c102_i2c_write(cam, 0x14, 0x02);
43  err += sn9c102_i2c_write(cam, 0x13, 0x01);
44 
45  msleep(400);
46 
47  return err;
48 }
49 
50 
51 static int pas106b_get_ctrl(struct sn9c102_device* cam,
52  struct v4l2_control* ctrl)
53 {
54  switch (ctrl->id) {
55  case V4L2_CID_EXPOSURE:
56  {
57  int r1 = sn9c102_i2c_read(cam, 0x03),
58  r2 = sn9c102_i2c_read(cam, 0x04);
59  if (r1 < 0 || r2 < 0)
60  return -EIO;
61  ctrl->value = (r1 << 4) | (r2 & 0x0f);
62  }
63  return 0;
65  if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
66  return -EIO;
67  ctrl->value &= 0x1f;
68  return 0;
70  if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0)
71  return -EIO;
72  ctrl->value &= 0x1f;
73  return 0;
74  case V4L2_CID_GAIN:
75  if ((ctrl->value = sn9c102_i2c_read(cam, 0x0e)) < 0)
76  return -EIO;
77  ctrl->value &= 0x1f;
78  return 0;
79  case V4L2_CID_CONTRAST:
80  if ((ctrl->value = sn9c102_i2c_read(cam, 0x0f)) < 0)
81  return -EIO;
82  ctrl->value &= 0x07;
83  return 0;
85  if ((ctrl->value = sn9c102_i2c_read(cam, 0x0a)) < 0)
86  return -EIO;
87  ctrl->value = (ctrl->value & 0x1f) << 1;
88  return 0;
90  if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0)
91  return -EIO;
92  ctrl->value &= 0xf8;
93  return 0;
94  default:
95  return -EINVAL;
96  }
97 }
98 
99 
100 static int pas106b_set_ctrl(struct sn9c102_device* cam,
101  const struct v4l2_control* ctrl)
102 {
103  int err = 0;
104 
105  switch (ctrl->id) {
106  case V4L2_CID_EXPOSURE:
107  err += sn9c102_i2c_write(cam, 0x03, ctrl->value >> 4);
108  err += sn9c102_i2c_write(cam, 0x04, ctrl->value & 0x0f);
109  break;
111  err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
112  break;
114  err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
115  break;
116  case V4L2_CID_GAIN:
117  err += sn9c102_i2c_write(cam, 0x0e, ctrl->value);
118  break;
119  case V4L2_CID_CONTRAST:
120  err += sn9c102_i2c_write(cam, 0x0f, ctrl->value);
121  break;
123  err += sn9c102_i2c_write(cam, 0x0a, ctrl->value >> 1);
124  err += sn9c102_i2c_write(cam, 0x0b, ctrl->value >> 1);
125  break;
127  err += sn9c102_i2c_write(cam, 0x08, ctrl->value << 3);
128  break;
129  default:
130  return -EINVAL;
131  }
132  err += sn9c102_i2c_write(cam, 0x13, 0x01);
133 
134  return err ? -EIO : 0;
135 }
136 
137 
138 static int pas106b_set_crop(struct sn9c102_device* cam,
139  const struct v4l2_rect* rect)
140 {
141  struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
142  int err = 0;
143  u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4,
144  v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
145 
146  err += sn9c102_write_reg(cam, h_start, 0x12);
147  err += sn9c102_write_reg(cam, v_start, 0x13);
148 
149  return err;
150 }
151 
152 
153 static int pas106b_set_pix_format(struct sn9c102_device* cam,
154  const struct v4l2_pix_format* pix)
155 {
156  int err = 0;
157 
158  if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
159  err += sn9c102_write_reg(cam, 0x2c, 0x17);
160  else
161  err += sn9c102_write_reg(cam, 0x20, 0x17);
162 
163  return err;
164 }
165 
166 
167 static const struct sn9c102_sensor pas106b = {
168  .name = "PAS106B",
169  .maintainer = "Luca Risolia <[email protected]>",
170  .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
171  .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
172  .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
173  .interface = SN9C102_I2C_2WIRES,
174  .i2c_slave_id = 0x40,
175  .init = &pas106b_init,
176  .qctrl = {
177  {
178  .id = V4L2_CID_EXPOSURE,
179  .type = V4L2_CTRL_TYPE_INTEGER,
180  .name = "exposure",
181  .minimum = 0x125,
182  .maximum = 0xfff,
183  .step = 0x001,
184  .default_value = 0x140,
185  .flags = 0,
186  },
187  {
188  .id = V4L2_CID_GAIN,
189  .type = V4L2_CTRL_TYPE_INTEGER,
190  .name = "global gain",
191  .minimum = 0x00,
192  .maximum = 0x1f,
193  .step = 0x01,
194  .default_value = 0x0d,
195  .flags = 0,
196  },
197  {
198  .id = V4L2_CID_CONTRAST,
199  .type = V4L2_CTRL_TYPE_INTEGER,
200  .name = "contrast",
201  .minimum = 0x00,
202  .maximum = 0x07,
203  .step = 0x01,
204  .default_value = 0x00, /* 0x00~0x03 have same effect */
205  .flags = 0,
206  },
207  {
208  .id = V4L2_CID_RED_BALANCE,
209  .type = V4L2_CTRL_TYPE_INTEGER,
210  .name = "red balance",
211  .minimum = 0x00,
212  .maximum = 0x1f,
213  .step = 0x01,
214  .default_value = 0x04,
215  .flags = 0,
216  },
217  {
218  .id = V4L2_CID_BLUE_BALANCE,
219  .type = V4L2_CTRL_TYPE_INTEGER,
220  .name = "blue balance",
221  .minimum = 0x00,
222  .maximum = 0x1f,
223  .step = 0x01,
224  .default_value = 0x06,
225  .flags = 0,
226  },
227  {
229  .type = V4L2_CTRL_TYPE_INTEGER,
230  .name = "green balance",
231  .minimum = 0x00,
232  .maximum = 0x3e,
233  .step = 0x02,
234  .default_value = 0x02,
235  .flags = 0,
236  },
237  {
239  .type = V4L2_CTRL_TYPE_INTEGER,
240  .name = "DAC magnitude",
241  .minimum = 0x00,
242  .maximum = 0x1f,
243  .step = 0x01,
244  .default_value = 0x01,
245  .flags = 0,
246  },
247  },
248  .get_ctrl = &pas106b_get_ctrl,
249  .set_ctrl = &pas106b_set_ctrl,
250  .cropcap = {
251  .bounds = {
252  .left = 0,
253  .top = 0,
254  .width = 352,
255  .height = 288,
256  },
257  .defrect = {
258  .left = 0,
259  .top = 0,
260  .width = 352,
261  .height = 288,
262  },
263  },
264  .set_crop = &pas106b_set_crop,
265  .pix_format = {
266  .width = 352,
267  .height = 288,
268  .pixelformat = V4L2_PIX_FMT_SBGGR8,
269  .priv = 8, /* we use this field as 'bits per pixel' */
270  },
271  .set_pix_format = &pas106b_set_pix_format
272 };
273 
274 
276 {
277  int r0 = 0, r1 = 0;
278  unsigned int pid = 0;
279 
280  /*
281  Minimal initialization to enable the I2C communication
282  NOTE: do NOT change the values!
283  */
284  if (sn9c102_write_const_regs(cam,
285  {0x01, 0x01}, /* sensor power down */
286  {0x00, 0x01}, /* sensor power on */
287  {0x28, 0x17})) /* sensor clock at 24 MHz */
288  return -EIO;
289 
290  r0 = sn9c102_i2c_try_read(cam, &pas106b, 0x00);
291  r1 = sn9c102_i2c_try_read(cam, &pas106b, 0x01);
292  if (r0 < 0 || r1 < 0)
293  return -EIO;
294 
295  pid = (r0 << 11) | ((r1 & 0xf0) >> 4);
296  if (pid != 0x007)
297  return -ENODEV;
298 
299  sn9c102_attach_sensor(cam, &pas106b);
300 
301  return 0;
302 }