1/*************************************************************************** 2 * Plug-in for PAS202BCB image sensor connected to the SN9C1xx PC Camera * 3 * Controllers * 4 * * 5 * Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio * 6 * <medaglia@undl.org.br> * 7 * http://cadu.homelinux.com:8080/ * 8 * * 9 * Support for SN9C103, DAC Magnitude, exposure and green gain controls * 10 * added by Luca Risolia <luca.risolia@studio.unibo.it> * 11 * * 12 * This program is free software; you can redistribute it and/or modify * 13 * it under the terms of the GNU General Public License as published by * 14 * the Free Software Foundation; either version 2 of the License, or * 15 * (at your option) any later version. * 16 * * 17 * This program is distributed in the hope that it will be useful, * 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 20 * GNU General Public License for more details. * 21 * * 22 * You should have received a copy of the GNU General Public License * 23 * along with this program; if not, write to the Free Software * 24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 25 ***************************************************************************/ 26 27#include <linux/delay.h> 28#include "sn9c102_sensor.h" 29#include "sn9c102_devtable.h" 30 31 32static int pas202bcb_init(struct sn9c102_device* cam) 33{ 34 int err = 0; 35 36 switch (sn9c102_get_bridge(cam)) { 37 case BRIDGE_SN9C101: 38 case BRIDGE_SN9C102: 39 err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, 40 {0x00, 0x14}, {0x20, 0x17}, 41 {0x30, 0x19}, {0x09, 0x18}); 42 break; 43 case BRIDGE_SN9C103: 44 err = sn9c102_write_const_regs(cam, {0x00, 0x02}, {0x00, 0x03}, 45 {0x1a, 0x04}, {0x20, 0x05}, 46 {0x20, 0x06}, {0x20, 0x07}, 47 {0x00, 0x10}, {0x00, 0x11}, 48 {0x00, 0x14}, {0x20, 0x17}, 49 {0x30, 0x19}, {0x09, 0x18}, 50 {0x02, 0x1c}, {0x03, 0x1d}, 51 {0x0f, 0x1e}, {0x0c, 0x1f}, 52 {0x00, 0x20}, {0x10, 0x21}, 53 {0x20, 0x22}, {0x30, 0x23}, 54 {0x40, 0x24}, {0x50, 0x25}, 55 {0x60, 0x26}, {0x70, 0x27}, 56 {0x80, 0x28}, {0x90, 0x29}, 57 {0xa0, 0x2a}, {0xb0, 0x2b}, 58 {0xc0, 0x2c}, {0xd0, 0x2d}, 59 {0xe0, 0x2e}, {0xf0, 0x2f}, 60 {0xff, 0x30}); 61 break; 62 default: 63 break; 64 } 65 66 err += sn9c102_i2c_write(cam, 0x02, 0x14); 67 err += sn9c102_i2c_write(cam, 0x03, 0x40); 68 err += sn9c102_i2c_write(cam, 0x0d, 0x2c); 69 err += sn9c102_i2c_write(cam, 0x0e, 0x01); 70 err += sn9c102_i2c_write(cam, 0x0f, 0xa9); 71 err += sn9c102_i2c_write(cam, 0x10, 0x08); 72 err += sn9c102_i2c_write(cam, 0x13, 0x63); 73 err += sn9c102_i2c_write(cam, 0x15, 0x70); 74 err += sn9c102_i2c_write(cam, 0x11, 0x01); 75 76 msleep(400); 77 78 return err; 79} 80 81 82static int pas202bcb_get_ctrl(struct sn9c102_device* cam, 83 struct v4l2_control* ctrl) 84{ 85 switch (ctrl->id) { 86 case V4L2_CID_EXPOSURE: 87 { 88 int r1 = sn9c102_i2c_read(cam, 0x04), 89 r2 = sn9c102_i2c_read(cam, 0x05); 90 if (r1 < 0 || r2 < 0) 91 return -EIO; 92 ctrl->value = (r1 << 6) | (r2 & 0x3f); 93 } 94 return 0; 95 case V4L2_CID_RED_BALANCE: 96 if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0) 97 return -EIO; 98 ctrl->value &= 0x0f; 99 return 0; 100 case V4L2_CID_BLUE_BALANCE: 101 if ((ctrl->value = sn9c102_i2c_read(cam, 0x07)) < 0) 102 return -EIO; 103 ctrl->value &= 0x0f; 104 return 0; 105 case V4L2_CID_GAIN: 106 if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0) 107 return -EIO; 108 ctrl->value &= 0x1f; 109 return 0; 110 case SN9C102_V4L2_CID_GREEN_BALANCE: 111 if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0) 112 return -EIO; 113 ctrl->value &= 0x0f; 114 return 0; 115 case SN9C102_V4L2_CID_DAC_MAGNITUDE: 116 if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0) 117 return -EIO; 118 return 0; 119 default: 120 return -EINVAL; 121 } 122} 123 124 125static int pas202bcb_set_pix_format(struct sn9c102_device* cam, 126 const struct v4l2_pix_format* pix) 127{ 128 int err = 0; 129 130 if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) 131 err += sn9c102_write_reg(cam, 0x28, 0x17); 132 else 133 err += sn9c102_write_reg(cam, 0x20, 0x17); 134 135 return err; 136} 137 138 139static int pas202bcb_set_ctrl(struct sn9c102_device* cam, 140 const struct v4l2_control* ctrl) 141{ 142 int err = 0; 143 144 switch (ctrl->id) { 145 case V4L2_CID_EXPOSURE: 146 err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6); 147 err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f); 148 break; 149 case V4L2_CID_RED_BALANCE: 150 err += sn9c102_i2c_write(cam, 0x09, ctrl->value); 151 break; 152 case V4L2_CID_BLUE_BALANCE: 153 err += sn9c102_i2c_write(cam, 0x07, ctrl->value); 154 break; 155 case V4L2_CID_GAIN: 156 err += sn9c102_i2c_write(cam, 0x10, ctrl->value); 157 break; 158 case SN9C102_V4L2_CID_GREEN_BALANCE: 159 err += sn9c102_i2c_write(cam, 0x08, ctrl->value); 160 break; 161 case SN9C102_V4L2_CID_DAC_MAGNITUDE: 162 err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); 163 break; 164 default: 165 return -EINVAL; 166 } 167 err += sn9c102_i2c_write(cam, 0x11, 0x01); 168 169 return err ? -EIO : 0; 170} 171 172 173static int pas202bcb_set_crop(struct sn9c102_device* cam, 174 const struct v4l2_rect* rect) 175{ 176 struct sn9c102_sensor* s = sn9c102_get_sensor(cam); 177 int err = 0; 178 u8 h_start = 0, 179 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3; 180 181 switch (sn9c102_get_bridge(cam)) { 182 case BRIDGE_SN9C101: 183 case BRIDGE_SN9C102: 184 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4; 185 break; 186 case BRIDGE_SN9C103: 187 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3; 188 break; 189 default: 190 break; 191 } 192 193 err += sn9c102_write_reg(cam, h_start, 0x12); 194 err += sn9c102_write_reg(cam, v_start, 0x13); 195 196 return err; 197} 198 199 200static const struct sn9c102_sensor pas202bcb = { 201 .name = "PAS202BCB", 202 .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", 203 .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, 204 .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, 205 .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, 206 .interface = SN9C102_I2C_2WIRES, 207 .i2c_slave_id = 0x40, 208 .init = &pas202bcb_init, 209 .qctrl = { 210 { 211 .id = V4L2_CID_EXPOSURE, 212 .type = V4L2_CTRL_TYPE_INTEGER, 213 .name = "exposure", 214 .minimum = 0x01e5, 215 .maximum = 0x3fff, 216 .step = 0x0001, 217 .default_value = 0x01e5, 218 .flags = 0, 219 }, 220 { 221 .id = V4L2_CID_GAIN, 222 .type = V4L2_CTRL_TYPE_INTEGER, 223 .name = "global gain", 224 .minimum = 0x00, 225 .maximum = 0x1f, 226 .step = 0x01, 227 .default_value = 0x0b, 228 .flags = 0, 229 }, 230 { 231 .id = V4L2_CID_RED_BALANCE, 232 .type = V4L2_CTRL_TYPE_INTEGER, 233 .name = "red balance", 234 .minimum = 0x00, 235 .maximum = 0x0f, 236 .step = 0x01, 237 .default_value = 0x00, 238 .flags = 0, 239 }, 240 { 241 .id = V4L2_CID_BLUE_BALANCE, 242 .type = V4L2_CTRL_TYPE_INTEGER, 243 .name = "blue balance", 244 .minimum = 0x00, 245 .maximum = 0x0f, 246 .step = 0x01, 247 .default_value = 0x05, 248 .flags = 0, 249 }, 250 { 251 .id = SN9C102_V4L2_CID_GREEN_BALANCE, 252 .type = V4L2_CTRL_TYPE_INTEGER, 253 .name = "green balance", 254 .minimum = 0x00, 255 .maximum = 0x0f, 256 .step = 0x01, 257 .default_value = 0x00, 258 .flags = 0, 259 }, 260 { 261 .id = SN9C102_V4L2_CID_DAC_MAGNITUDE, 262 .type = V4L2_CTRL_TYPE_INTEGER, 263 .name = "DAC magnitude", 264 .minimum = 0x00, 265 .maximum = 0xff, 266 .step = 0x01, 267 .default_value = 0x04, 268 .flags = 0, 269 }, 270 }, 271 .get_ctrl = &pas202bcb_get_ctrl, 272 .set_ctrl = &pas202bcb_set_ctrl, 273 .cropcap = { 274 .bounds = { 275 .left = 0, 276 .top = 0, 277 .width = 640, 278 .height = 480, 279 }, 280 .defrect = { 281 .left = 0, 282 .top = 0, 283 .width = 640, 284 .height = 480, 285 }, 286 }, 287 .set_crop = &pas202bcb_set_crop, 288 .pix_format = { 289 .width = 640, 290 .height = 480, 291 .pixelformat = V4L2_PIX_FMT_SBGGR8, 292 .priv = 8, 293 }, 294 .set_pix_format = &pas202bcb_set_pix_format 295}; 296 297 298int sn9c102_probe_pas202bcb(struct sn9c102_device* cam) 299{ 300 int r0 = 0, r1 = 0, err = 0; 301 unsigned int pid = 0; 302 303 /* 304 * Minimal initialization to enable the I2C communication 305 * NOTE: do NOT change the values! 306 */ 307 switch (sn9c102_get_bridge(cam)) { 308 case BRIDGE_SN9C101: 309 case BRIDGE_SN9C102: 310 err = sn9c102_write_const_regs(cam, 311 {0x01, 0x01}, /* power down */ 312 {0x40, 0x01}, /* power on */ 313 {0x28, 0x17});/* clock 24 MHz */ 314 break; 315 case BRIDGE_SN9C103: /* do _not_ change anything! */ 316 err = sn9c102_write_const_regs(cam, {0x09, 0x01}, {0x44, 0x01}, 317 {0x44, 0x02}, {0x29, 0x17}); 318 break; 319 default: 320 break; 321 } 322 323 r0 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x00); 324 r1 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x01); 325 326 if (err || r0 < 0 || r1 < 0) 327 return -EIO; 328 329 pid = (r0 << 4) | ((r1 & 0xf0) >> 4); 330 if (pid != 0x017) 331 return -ENODEV; 332 333 sn9c102_attach_sensor(cam, &pas202bcb); 334 335 return 0; 336} 337