1/*************************************************************************** 2 * Plug-in for HV7131R image sensor connected to the SN9C1xx PC Camera * 3 * Controllers * 4 * * 5 * Copyright (C) 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 26static 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 140static 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; 148 case V4L2_CID_RED_BALANCE: 149 if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0) 150 return -EIO; 151 ctrl->value = ctrl->value & 0x3f; 152 return 0; 153 case V4L2_CID_BLUE_BALANCE: 154 if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0) 155 return -EIO; 156 ctrl->value = ctrl->value & 0x3f; 157 return 0; 158 case SN9C102_V4L2_CID_GREEN_BALANCE: 159 if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0) 160 return -EIO; 161 ctrl->value = ctrl->value & 0x3f; 162 return 0; 163 case V4L2_CID_BLACK_LEVEL: 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 174static 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; 183 case V4L2_CID_RED_BALANCE: 184 err += sn9c102_i2c_write(cam, 0x31, ctrl->value); 185 break; 186 case V4L2_CID_BLUE_BALANCE: 187 err += sn9c102_i2c_write(cam, 0x33, ctrl->value); 188 break; 189 case SN9C102_V4L2_CID_GREEN_BALANCE: 190 err += sn9c102_i2c_write(cam, 0x32, ctrl->value); 191 break; 192 case V4L2_CID_BLACK_LEVEL: 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 209static 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 224static 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 257static const struct sn9c102_sensor hv7131r = { 258 .name = "HV7131R", 259 .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", 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 { 298 .id = SN9C102_V4L2_CID_GREEN_BALANCE, 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 345int sn9c102_probe_hv7131r(struct sn9c102_device* cam) 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} 364