1/*************************************************************************** 2 * Plug-in for MI-0360 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 mi0360_init(struct sn9c102_device* cam) 27{ 28 struct sn9c102_sensor* s = sn9c102_get_sensor(cam); 29 int err = 0; 30 31 switch (sn9c102_get_bridge(cam)) { 32 case BRIDGE_SN9C103: 33 err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, 34 {0x0a, 0x14}, {0x40, 0x01}, 35 {0x20, 0x17}, {0x07, 0x18}, 36 {0xa0, 0x19}, {0x02, 0x1c}, 37 {0x03, 0x1d}, {0x0f, 0x1e}, 38 {0x0c, 0x1f}, {0x00, 0x20}, 39 {0x10, 0x21}, {0x20, 0x22}, 40 {0x30, 0x23}, {0x40, 0x24}, 41 {0x50, 0x25}, {0x60, 0x26}, 42 {0x70, 0x27}, {0x80, 0x28}, 43 {0x90, 0x29}, {0xa0, 0x2a}, 44 {0xb0, 0x2b}, {0xc0, 0x2c}, 45 {0xd0, 0x2d}, {0xe0, 0x2e}, 46 {0xf0, 0x2f}, {0xff, 0x30}); 47 break; 48 case BRIDGE_SN9C105: 49 case BRIDGE_SN9C120: 50 err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02}, 51 {0x00, 0x03}, {0x1a, 0x04}, 52 {0x50, 0x05}, {0x20, 0x06}, 53 {0x10, 0x07}, {0x03, 0x10}, 54 {0x08, 0x14}, {0xa2, 0x17}, 55 {0x47, 0x18}, {0x00, 0x19}, 56 {0x1d, 0x1a}, {0x10, 0x1b}, 57 {0x02, 0x1c}, {0x03, 0x1d}, 58 {0x0f, 0x1e}, {0x0c, 0x1f}, 59 {0x00, 0x20}, {0x29, 0x21}, 60 {0x40, 0x22}, {0x54, 0x23}, 61 {0x66, 0x24}, {0x76, 0x25}, 62 {0x85, 0x26}, {0x94, 0x27}, 63 {0xa1, 0x28}, {0xae, 0x29}, 64 {0xbb, 0x2a}, {0xc7, 0x2b}, 65 {0xd3, 0x2c}, {0xde, 0x2d}, 66 {0xea, 0x2e}, {0xf4, 0x2f}, 67 {0xff, 0x30}, {0x00, 0x3F}, 68 {0xC7, 0x40}, {0x01, 0x41}, 69 {0x44, 0x42}, {0x00, 0x43}, 70 {0x44, 0x44}, {0x00, 0x45}, 71 {0x44, 0x46}, {0x00, 0x47}, 72 {0xC7, 0x48}, {0x01, 0x49}, 73 {0xC7, 0x4A}, {0x01, 0x4B}, 74 {0xC7, 0x4C}, {0x01, 0x4D}, 75 {0x44, 0x4E}, {0x00, 0x4F}, 76 {0x44, 0x50}, {0x00, 0x51}, 77 {0x44, 0x52}, {0x00, 0x53}, 78 {0xC7, 0x54}, {0x01, 0x55}, 79 {0xC7, 0x56}, {0x01, 0x57}, 80 {0xC7, 0x58}, {0x01, 0x59}, 81 {0x44, 0x5A}, {0x00, 0x5B}, 82 {0x44, 0x5C}, {0x00, 0x5D}, 83 {0x44, 0x5E}, {0x00, 0x5F}, 84 {0xC7, 0x60}, {0x01, 0x61}, 85 {0xC7, 0x62}, {0x01, 0x63}, 86 {0xC7, 0x64}, {0x01, 0x65}, 87 {0x44, 0x66}, {0x00, 0x67}, 88 {0x44, 0x68}, {0x00, 0x69}, 89 {0x44, 0x6A}, {0x00, 0x6B}, 90 {0xC7, 0x6C}, {0x01, 0x6D}, 91 {0xC7, 0x6E}, {0x01, 0x6F}, 92 {0xC7, 0x70}, {0x01, 0x71}, 93 {0x44, 0x72}, {0x00, 0x73}, 94 {0x44, 0x74}, {0x00, 0x75}, 95 {0x44, 0x76}, {0x00, 0x77}, 96 {0xC7, 0x78}, {0x01, 0x79}, 97 {0xC7, 0x7A}, {0x01, 0x7B}, 98 {0xC7, 0x7C}, {0x01, 0x7D}, 99 {0x44, 0x7E}, {0x00, 0x7F}, 100 {0x14, 0x84}, {0x00, 0x85}, 101 {0x27, 0x86}, {0x00, 0x87}, 102 {0x07, 0x88}, {0x00, 0x89}, 103 {0xEC, 0x8A}, {0x0f, 0x8B}, 104 {0xD8, 0x8C}, {0x0f, 0x8D}, 105 {0x3D, 0x8E}, {0x00, 0x8F}, 106 {0x3D, 0x90}, {0x00, 0x91}, 107 {0xCD, 0x92}, {0x0f, 0x93}, 108 {0xf7, 0x94}, {0x0f, 0x95}, 109 {0x0C, 0x96}, {0x00, 0x97}, 110 {0x00, 0x98}, {0x66, 0x99}, 111 {0x05, 0x9A}, {0x00, 0x9B}, 112 {0x04, 0x9C}, {0x00, 0x9D}, 113 {0x08, 0x9E}, {0x00, 0x9F}, 114 {0x2D, 0xC0}, {0x2D, 0xC1}, 115 {0x3A, 0xC2}, {0x05, 0xC3}, 116 {0x04, 0xC4}, {0x3F, 0xC5}, 117 {0x00, 0xC6}, {0x00, 0xC7}, 118 {0x50, 0xC8}, {0x3C, 0xC9}, 119 {0x28, 0xCA}, {0xD8, 0xCB}, 120 {0x14, 0xCC}, {0xEC, 0xCD}, 121 {0x32, 0xCE}, {0xDD, 0xCF}, 122 {0x32, 0xD0}, {0xDD, 0xD1}, 123 {0x6A, 0xD2}, {0x50, 0xD3}, 124 {0x00, 0xD4}, {0x00, 0xD5}, 125 {0x00, 0xD6}); 126 break; 127 default: 128 break; 129 } 130 131 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, 132 0x00, 0x01, 0, 0); 133 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, 134 0x00, 0x00, 0, 0); 135 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03, 136 0x01, 0xe1, 0, 0); 137 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04, 138 0x02, 0x81, 0, 0); 139 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05, 140 0x00, 0x17, 0, 0); 141 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06, 142 0x00, 0x11, 0, 0); 143 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x62, 144 0x04, 0x9a, 0, 0); 145 146 return err; 147} 148 149 150static int mi0360_get_ctrl(struct sn9c102_device* cam, 151 struct v4l2_control* ctrl) 152{ 153 struct sn9c102_sensor* s = sn9c102_get_sensor(cam); 154 u8 data[2]; 155 156 switch (ctrl->id) { 157 case V4L2_CID_EXPOSURE: 158 if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x09, 2, 159 data) < 0) 160 return -EIO; 161 ctrl->value = data[0]; 162 return 0; 163 case V4L2_CID_GAIN: 164 if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x35, 2, 165 data) < 0) 166 return -EIO; 167 ctrl->value = data[1]; 168 return 0; 169 case V4L2_CID_RED_BALANCE: 170 if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2c, 2, 171 data) < 0) 172 return -EIO; 173 ctrl->value = data[1]; 174 return 0; 175 case V4L2_CID_BLUE_BALANCE: 176 if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2d, 2, 177 data) < 0) 178 return -EIO; 179 ctrl->value = data[1]; 180 return 0; 181 case SN9C102_V4L2_CID_GREEN_BALANCE: 182 if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2e, 2, 183 data) < 0) 184 return -EIO; 185 ctrl->value = data[1]; 186 return 0; 187 case V4L2_CID_HFLIP: 188 if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2, 189 data) < 0) 190 return -EIO; 191 ctrl->value = data[1] & 0x20 ? 1 : 0; 192 return 0; 193 case V4L2_CID_VFLIP: 194 if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2, 195 data) < 0) 196 return -EIO; 197 ctrl->value = data[1] & 0x80 ? 1 : 0; 198 return 0; 199 default: 200 return -EINVAL; 201 } 202 203 return 0; 204} 205 206 207static int mi0360_set_ctrl(struct sn9c102_device* cam, 208 const struct v4l2_control* ctrl) 209{ 210 struct sn9c102_sensor* s = sn9c102_get_sensor(cam); 211 int err = 0; 212 213 switch (ctrl->id) { 214 case V4L2_CID_EXPOSURE: 215 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 216 0x09, ctrl->value, 0x00, 217 0, 0); 218 break; 219 case V4L2_CID_GAIN: 220 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 221 0x35, 0x03, ctrl->value, 222 0, 0); 223 break; 224 case V4L2_CID_RED_BALANCE: 225 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 226 0x2c, 0x03, ctrl->value, 227 0, 0); 228 break; 229 case V4L2_CID_BLUE_BALANCE: 230 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 231 0x2d, 0x03, ctrl->value, 232 0, 0); 233 break; 234 case SN9C102_V4L2_CID_GREEN_BALANCE: 235 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 236 0x2b, 0x03, ctrl->value, 237 0, 0); 238 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 239 0x2e, 0x03, ctrl->value, 240 0, 0); 241 break; 242 case V4L2_CID_HFLIP: 243 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 244 0x20, ctrl->value ? 0x40:0x00, 245 ctrl->value ? 0x20:0x00, 246 0, 0); 247 break; 248 case V4L2_CID_VFLIP: 249 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 250 0x20, ctrl->value ? 0x80:0x00, 251 ctrl->value ? 0x80:0x00, 252 0, 0); 253 break; 254 default: 255 return -EINVAL; 256 } 257 258 return err ? -EIO : 0; 259} 260 261 262static int mi0360_set_crop(struct sn9c102_device* cam, 263 const struct v4l2_rect* rect) 264{ 265 struct sn9c102_sensor* s = sn9c102_get_sensor(cam); 266 int err = 0; 267 u8 h_start = 0, v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; 268 269 switch (sn9c102_get_bridge(cam)) { 270 case BRIDGE_SN9C103: 271 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0; 272 break; 273 case BRIDGE_SN9C105: 274 case BRIDGE_SN9C120: 275 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1; 276 break; 277 default: 278 break; 279 } 280 281 err += sn9c102_write_reg(cam, h_start, 0x12); 282 err += sn9c102_write_reg(cam, v_start, 0x13); 283 284 return err; 285} 286 287 288static int mi0360_set_pix_format(struct sn9c102_device* cam, 289 const struct v4l2_pix_format* pix) 290{ 291 struct sn9c102_sensor* s = sn9c102_get_sensor(cam); 292 int err = 0; 293 294 if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) { 295 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 296 0x0a, 0x00, 0x05, 0, 0); 297 err += sn9c102_write_reg(cam, 0x60, 0x19); 298 if (sn9c102_get_bridge(cam) == BRIDGE_SN9C105 || 299 sn9c102_get_bridge(cam) == BRIDGE_SN9C120) 300 err += sn9c102_write_reg(cam, 0xa6, 0x17); 301 } else { 302 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 303 0x0a, 0x00, 0x02, 0, 0); 304 err += sn9c102_write_reg(cam, 0x20, 0x19); 305 if (sn9c102_get_bridge(cam) == BRIDGE_SN9C105 || 306 sn9c102_get_bridge(cam) == BRIDGE_SN9C120) 307 err += sn9c102_write_reg(cam, 0xa2, 0x17); 308 } 309 310 return err; 311} 312 313 314static const struct sn9c102_sensor mi0360 = { 315 .name = "MI-0360", 316 .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", 317 .supported_bridge = BRIDGE_SN9C103 | BRIDGE_SN9C105 | BRIDGE_SN9C120, 318 .frequency = SN9C102_I2C_100KHZ, 319 .interface = SN9C102_I2C_2WIRES, 320 .i2c_slave_id = 0x5d, 321 .init = &mi0360_init, 322 .qctrl = { 323 { 324 .id = V4L2_CID_EXPOSURE, 325 .type = V4L2_CTRL_TYPE_INTEGER, 326 .name = "exposure", 327 .minimum = 0x00, 328 .maximum = 0x0f, 329 .step = 0x01, 330 .default_value = 0x05, 331 .flags = 0, 332 }, 333 { 334 .id = V4L2_CID_GAIN, 335 .type = V4L2_CTRL_TYPE_INTEGER, 336 .name = "global gain", 337 .minimum = 0x00, 338 .maximum = 0x7f, 339 .step = 0x01, 340 .default_value = 0x25, 341 .flags = 0, 342 }, 343 { 344 .id = V4L2_CID_HFLIP, 345 .type = V4L2_CTRL_TYPE_BOOLEAN, 346 .name = "horizontal mirror", 347 .minimum = 0, 348 .maximum = 1, 349 .step = 1, 350 .default_value = 0, 351 .flags = 0, 352 }, 353 { 354 .id = V4L2_CID_VFLIP, 355 .type = V4L2_CTRL_TYPE_BOOLEAN, 356 .name = "vertical mirror", 357 .minimum = 0, 358 .maximum = 1, 359 .step = 1, 360 .default_value = 0, 361 .flags = 0, 362 }, 363 { 364 .id = V4L2_CID_BLUE_BALANCE, 365 .type = V4L2_CTRL_TYPE_INTEGER, 366 .name = "blue balance", 367 .minimum = 0x00, 368 .maximum = 0x7f, 369 .step = 0x01, 370 .default_value = 0x0f, 371 .flags = 0, 372 }, 373 { 374 .id = V4L2_CID_RED_BALANCE, 375 .type = V4L2_CTRL_TYPE_INTEGER, 376 .name = "red balance", 377 .minimum = 0x00, 378 .maximum = 0x7f, 379 .step = 0x01, 380 .default_value = 0x32, 381 .flags = 0, 382 }, 383 { 384 .id = SN9C102_V4L2_CID_GREEN_BALANCE, 385 .type = V4L2_CTRL_TYPE_INTEGER, 386 .name = "green balance", 387 .minimum = 0x00, 388 .maximum = 0x7f, 389 .step = 0x01, 390 .default_value = 0x25, 391 .flags = 0, 392 }, 393 }, 394 .get_ctrl = &mi0360_get_ctrl, 395 .set_ctrl = &mi0360_set_ctrl, 396 .cropcap = { 397 .bounds = { 398 .left = 0, 399 .top = 0, 400 .width = 640, 401 .height = 480, 402 }, 403 .defrect = { 404 .left = 0, 405 .top = 0, 406 .width = 640, 407 .height = 480, 408 }, 409 }, 410 .set_crop = &mi0360_set_crop, 411 .pix_format = { 412 .width = 640, 413 .height = 480, 414 .pixelformat = V4L2_PIX_FMT_SBGGR8, 415 .priv = 8, 416 }, 417 .set_pix_format = &mi0360_set_pix_format 418}; 419 420 421int sn9c102_probe_mi0360(struct sn9c102_device* cam) 422{ 423 424 u8 data[2]; 425 426 switch (sn9c102_get_bridge(cam)) { 427 case BRIDGE_SN9C103: 428 if (sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01}, 429 {0x28, 0x17})) 430 return -EIO; 431 break; 432 case BRIDGE_SN9C105: 433 case BRIDGE_SN9C120: 434 if (sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1}, 435 {0x01, 0x01}, {0x00, 0x01}, 436 {0x28, 0x17})) 437 return -EIO; 438 break; 439 default: 440 break; 441 } 442 443 if (sn9c102_i2c_try_raw_read(cam, &mi0360, mi0360.i2c_slave_id, 0x00, 444 2, data) < 0) 445 return -EIO; 446 447 if (data[0] != 0x82 || data[1] != 0x43) 448 return -ENODEV; 449 450 sn9c102_attach_sensor(cam, &mi0360); 451 452 return 0; 453} 454