1/*************************************************************************** 2 * Plug-in for MI-0343 image sensor connected to the SN9C1xx PC Camera * 3 * Controllers * 4 * * 5 * Copyright (C) 2004-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 mi0343_init(struct sn9c102_device* cam) 27{ 28 struct sn9c102_sensor* s = sn9c102_get_sensor(cam); 29 int err = 0; 30 31 err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, 32 {0x0a, 0x14}, {0x40, 0x01}, 33 {0x20, 0x17}, {0x07, 0x18}, 34 {0xa0, 0x19}); 35 36 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, 37 0x00, 0x01, 0, 0); 38 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, 39 0x00, 0x00, 0, 0); 40 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03, 41 0x01, 0xe1, 0, 0); 42 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04, 43 0x02, 0x81, 0, 0); 44 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05, 45 0x00, 0x17, 0, 0); 46 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06, 47 0x00, 0x11, 0, 0); 48 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x62, 49 0x04, 0x9a, 0, 0); 50 51 return err; 52} 53 54 55static int mi0343_get_ctrl(struct sn9c102_device* cam, 56 struct v4l2_control* ctrl) 57{ 58 struct sn9c102_sensor* s = sn9c102_get_sensor(cam); 59 u8 data[2]; 60 61 switch (ctrl->id) { 62 case V4L2_CID_EXPOSURE: 63 if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x09, 2, 64 data) < 0) 65 return -EIO; 66 ctrl->value = data[0]; 67 return 0; 68 case V4L2_CID_GAIN: 69 if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x35, 2, 70 data) < 0) 71 return -EIO; 72 break; 73 case V4L2_CID_HFLIP: 74 if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2, 75 data) < 0) 76 return -EIO; 77 ctrl->value = data[1] & 0x20 ? 1 : 0; 78 return 0; 79 case V4L2_CID_VFLIP: 80 if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2, 81 data) < 0) 82 return -EIO; 83 ctrl->value = data[1] & 0x80 ? 1 : 0; 84 return 0; 85 case V4L2_CID_RED_BALANCE: 86 if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2d, 2, 87 data) < 0) 88 return -EIO; 89 break; 90 case V4L2_CID_BLUE_BALANCE: 91 if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2c, 2, 92 data) < 0) 93 return -EIO; 94 break; 95 case SN9C102_V4L2_CID_GREEN_BALANCE: 96 if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2e, 2, 97 data) < 0) 98 return -EIO; 99 break; 100 default: 101 return -EINVAL; 102 } 103 104 switch (ctrl->id) { 105 case V4L2_CID_GAIN: 106 case V4L2_CID_RED_BALANCE: 107 case V4L2_CID_BLUE_BALANCE: 108 case SN9C102_V4L2_CID_GREEN_BALANCE: 109 ctrl->value = data[1] | (data[0] << 8); 110 if (ctrl->value >= 0x10 && ctrl->value <= 0x3f) 111 ctrl->value -= 0x10; 112 else if (ctrl->value >= 0x60 && ctrl->value <= 0x7f) 113 ctrl->value -= 0x60; 114 else if (ctrl->value >= 0xe0 && ctrl->value <= 0xff) 115 ctrl->value -= 0xe0; 116 } 117 118 return 0; 119} 120 121 122static int mi0343_set_ctrl(struct sn9c102_device* cam, 123 const struct v4l2_control* ctrl) 124{ 125 struct sn9c102_sensor* s = sn9c102_get_sensor(cam); 126 u16 reg = 0; 127 int err = 0; 128 129 switch (ctrl->id) { 130 case V4L2_CID_GAIN: 131 case V4L2_CID_RED_BALANCE: 132 case V4L2_CID_BLUE_BALANCE: 133 case SN9C102_V4L2_CID_GREEN_BALANCE: 134 if (ctrl->value <= (0x3f-0x10)) 135 reg = 0x10 + ctrl->value; 136 else if (ctrl->value <= ((0x3f-0x10) + (0x7f-0x60))) 137 reg = 0x60 + (ctrl->value - (0x3f-0x10)); 138 else 139 reg = 0xe0 + (ctrl->value - (0x3f-0x10) - (0x7f-0x60)); 140 break; 141 } 142 143 switch (ctrl->id) { 144 case V4L2_CID_EXPOSURE: 145 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 146 0x09, ctrl->value, 0x00, 147 0, 0); 148 break; 149 case V4L2_CID_GAIN: 150 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 151 0x35, reg >> 8, reg & 0xff, 152 0, 0); 153 break; 154 case V4L2_CID_HFLIP: 155 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 156 0x20, ctrl->value ? 0x40:0x00, 157 ctrl->value ? 0x20:0x00, 158 0, 0); 159 break; 160 case V4L2_CID_VFLIP: 161 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 162 0x20, ctrl->value ? 0x80:0x00, 163 ctrl->value ? 0x80:0x00, 164 0, 0); 165 break; 166 case V4L2_CID_RED_BALANCE: 167 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 168 0x2d, reg >> 8, reg & 0xff, 169 0, 0); 170 break; 171 case V4L2_CID_BLUE_BALANCE: 172 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 173 0x2c, reg >> 8, reg & 0xff, 174 0, 0); 175 break; 176 case SN9C102_V4L2_CID_GREEN_BALANCE: 177 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 178 0x2b, reg >> 8, reg & 0xff, 179 0, 0); 180 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 181 0x2e, reg >> 8, reg & 0xff, 182 0, 0); 183 break; 184 default: 185 return -EINVAL; 186 } 187 188 return err ? -EIO : 0; 189} 190 191 192static int mi0343_set_crop(struct sn9c102_device* cam, 193 const struct v4l2_rect* rect) 194{ 195 struct sn9c102_sensor* s = sn9c102_get_sensor(cam); 196 int err = 0; 197 u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0, 198 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2; 199 200 err += sn9c102_write_reg(cam, h_start, 0x12); 201 err += sn9c102_write_reg(cam, v_start, 0x13); 202 203 return err; 204} 205 206 207static int mi0343_set_pix_format(struct sn9c102_device* cam, 208 const struct v4l2_pix_format* pix) 209{ 210 struct sn9c102_sensor* s = sn9c102_get_sensor(cam); 211 int err = 0; 212 213 if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) { 214 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 215 0x0a, 0x00, 0x03, 0, 0); 216 err += sn9c102_write_reg(cam, 0x20, 0x19); 217 } else { 218 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 219 0x0a, 0x00, 0x05, 0, 0); 220 err += sn9c102_write_reg(cam, 0xa0, 0x19); 221 } 222 223 return err; 224} 225 226 227static const struct sn9c102_sensor mi0343 = { 228 .name = "MI-0343", 229 .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", 230 .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, 231 .frequency = SN9C102_I2C_100KHZ, 232 .interface = SN9C102_I2C_2WIRES, 233 .i2c_slave_id = 0x5d, 234 .init = &mi0343_init, 235 .qctrl = { 236 { 237 .id = V4L2_CID_EXPOSURE, 238 .type = V4L2_CTRL_TYPE_INTEGER, 239 .name = "exposure", 240 .minimum = 0x00, 241 .maximum = 0x0f, 242 .step = 0x01, 243 .default_value = 0x06, 244 .flags = 0, 245 }, 246 { 247 .id = V4L2_CID_GAIN, 248 .type = V4L2_CTRL_TYPE_INTEGER, 249 .name = "global gain", 250 .minimum = 0x00, 251 .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),/*0x6d*/ 252 .step = 0x01, 253 .default_value = 0x00, 254 .flags = 0, 255 }, 256 { 257 .id = V4L2_CID_HFLIP, 258 .type = V4L2_CTRL_TYPE_BOOLEAN, 259 .name = "horizontal mirror", 260 .minimum = 0, 261 .maximum = 1, 262 .step = 1, 263 .default_value = 0, 264 .flags = 0, 265 }, 266 { 267 .id = V4L2_CID_VFLIP, 268 .type = V4L2_CTRL_TYPE_BOOLEAN, 269 .name = "vertical mirror", 270 .minimum = 0, 271 .maximum = 1, 272 .step = 1, 273 .default_value = 0, 274 .flags = 0, 275 }, 276 { 277 .id = V4L2_CID_RED_BALANCE, 278 .type = V4L2_CTRL_TYPE_INTEGER, 279 .name = "red balance", 280 .minimum = 0x00, 281 .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0), 282 .step = 0x01, 283 .default_value = 0x00, 284 .flags = 0, 285 }, 286 { 287 .id = V4L2_CID_BLUE_BALANCE, 288 .type = V4L2_CTRL_TYPE_INTEGER, 289 .name = "blue balance", 290 .minimum = 0x00, 291 .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0), 292 .step = 0x01, 293 .default_value = 0x00, 294 .flags = 0, 295 }, 296 { 297 .id = SN9C102_V4L2_CID_GREEN_BALANCE, 298 .type = V4L2_CTRL_TYPE_INTEGER, 299 .name = "green balance", 300 .minimum = 0x00, 301 .maximum = ((0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0)), 302 .step = 0x01, 303 .default_value = 0x00, 304 .flags = 0, 305 }, 306 }, 307 .get_ctrl = &mi0343_get_ctrl, 308 .set_ctrl = &mi0343_set_ctrl, 309 .cropcap = { 310 .bounds = { 311 .left = 0, 312 .top = 0, 313 .width = 640, 314 .height = 480, 315 }, 316 .defrect = { 317 .left = 0, 318 .top = 0, 319 .width = 640, 320 .height = 480, 321 }, 322 }, 323 .set_crop = &mi0343_set_crop, 324 .pix_format = { 325 .width = 640, 326 .height = 480, 327 .pixelformat = V4L2_PIX_FMT_SBGGR8, 328 .priv = 8, 329 }, 330 .set_pix_format = &mi0343_set_pix_format 331}; 332 333 334int sn9c102_probe_mi0343(struct sn9c102_device* cam) 335{ 336 u8 data[2]; 337 338 if (sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01}, 339 {0x28, 0x17})) 340 return -EIO; 341 342 if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, 0x00, 343 2, data) < 0) 344 return -EIO; 345 346 if (data[1] != 0x42 || data[0] != 0xe3) 347 return -ENODEV; 348 349 sn9c102_attach_sensor(cam, &mi0343); 350 351 return 0; 352} 353