1/* 2 * Driver for the ov7660 sensor 3 * 4 * Copyright (C) 2009 Erik Andr��n 5 * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. 6 * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br> 7 * 8 * Portions of code to USB interface and ALi driver software, 9 * Copyright (c) 2006 Willem Duinker 10 * v4l2 interface modeled after the V4L2 driver 11 * for SN9C10x PC Camera Controllers 12 * 13 * This program is free software; you can redistribute it and/or 14 * modify it under the terms of the GNU General Public License as 15 * published by the Free Software Foundation, version 2. 16 * 17 */ 18 19#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 20 21#include "m5602_ov7660.h" 22 23static int ov7660_s_ctrl(struct v4l2_ctrl *ctrl); 24static void ov7660_dump_registers(struct sd *sd); 25 26static struct v4l2_pix_format ov7660_modes[] = { 27 { 28 640, 29 480, 30 V4L2_PIX_FMT_SBGGR8, 31 V4L2_FIELD_NONE, 32 .sizeimage = 33 640 * 480, 34 .bytesperline = 640, 35 .colorspace = V4L2_COLORSPACE_SRGB, 36 .priv = 0 37 } 38}; 39 40static const struct v4l2_ctrl_ops ov7660_ctrl_ops = { 41 .s_ctrl = ov7660_s_ctrl, 42}; 43 44int ov7660_probe(struct sd *sd) 45{ 46 int err = 0, i; 47 u8 prod_id = 0, ver_id = 0; 48 49 if (force_sensor) { 50 if (force_sensor == OV7660_SENSOR) { 51 pr_info("Forcing an %s sensor\n", ov7660.name); 52 goto sensor_found; 53 } 54 /* If we want to force another sensor, 55 don't try to probe this one */ 56 return -ENODEV; 57 } 58 59 /* Do the preinit */ 60 for (i = 0; i < ARRAY_SIZE(preinit_ov7660) && !err; i++) { 61 u8 data[2]; 62 63 if (preinit_ov7660[i][0] == BRIDGE) { 64 err = m5602_write_bridge(sd, 65 preinit_ov7660[i][1], 66 preinit_ov7660[i][2]); 67 } else { 68 data[0] = preinit_ov7660[i][2]; 69 err = m5602_write_sensor(sd, 70 preinit_ov7660[i][1], data, 1); 71 } 72 } 73 if (err < 0) 74 return err; 75 76 if (m5602_read_sensor(sd, OV7660_PID, &prod_id, 1)) 77 return -ENODEV; 78 79 if (m5602_read_sensor(sd, OV7660_VER, &ver_id, 1)) 80 return -ENODEV; 81 82 pr_info("Sensor reported 0x%x%x\n", prod_id, ver_id); 83 84 if ((prod_id == 0x76) && (ver_id == 0x60)) { 85 pr_info("Detected a ov7660 sensor\n"); 86 goto sensor_found; 87 } 88 return -ENODEV; 89 90sensor_found: 91 sd->gspca_dev.cam.cam_mode = ov7660_modes; 92 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov7660_modes); 93 94 return 0; 95} 96 97int ov7660_init(struct sd *sd) 98{ 99 int i, err; 100 101 /* Init the sensor */ 102 for (i = 0; i < ARRAY_SIZE(init_ov7660); i++) { 103 u8 data[2]; 104 105 if (init_ov7660[i][0] == BRIDGE) { 106 err = m5602_write_bridge(sd, 107 init_ov7660[i][1], 108 init_ov7660[i][2]); 109 } else { 110 data[0] = init_ov7660[i][2]; 111 err = m5602_write_sensor(sd, 112 init_ov7660[i][1], data, 1); 113 } 114 if (err < 0) 115 return err; 116 } 117 118 if (dump_sensor) 119 ov7660_dump_registers(sd); 120 121 return 0; 122} 123 124int ov7660_init_controls(struct sd *sd) 125{ 126 struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler; 127 128 sd->gspca_dev.vdev.ctrl_handler = hdl; 129 v4l2_ctrl_handler_init(hdl, 6); 130 131 v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE, 132 0, 1, 1, 1); 133 v4l2_ctrl_new_std_menu(hdl, &ov7660_ctrl_ops, 134 V4L2_CID_EXPOSURE_AUTO, 1, 0, V4L2_EXPOSURE_AUTO); 135 136 sd->autogain = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, 137 V4L2_CID_AUTOGAIN, 0, 1, 1, 1); 138 sd->gain = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_GAIN, 0, 139 255, 1, OV7660_DEFAULT_GAIN); 140 141 sd->hflip = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_HFLIP, 142 0, 1, 1, 0); 143 sd->vflip = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_VFLIP, 144 0, 1, 1, 0); 145 146 if (hdl->error) { 147 pr_err("Could not initialize controls\n"); 148 return hdl->error; 149 } 150 151 v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, false); 152 v4l2_ctrl_cluster(2, &sd->hflip); 153 154 return 0; 155} 156 157int ov7660_start(struct sd *sd) 158{ 159 return 0; 160} 161 162int ov7660_stop(struct sd *sd) 163{ 164 return 0; 165} 166 167void ov7660_disconnect(struct sd *sd) 168{ 169 ov7660_stop(sd); 170 171 sd->sensor = NULL; 172} 173 174static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val) 175{ 176 int err; 177 u8 i2c_data = val; 178 struct sd *sd = (struct sd *) gspca_dev; 179 180 PDEBUG(D_CONF, "Setting gain to %d", val); 181 182 err = m5602_write_sensor(sd, OV7660_GAIN, &i2c_data, 1); 183 return err; 184} 185 186static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev, 187 __s32 val) 188{ 189 int err; 190 u8 i2c_data; 191 struct sd *sd = (struct sd *) gspca_dev; 192 193 PDEBUG(D_CONF, "Set auto white balance to %d", val); 194 195 err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1); 196 if (err < 0) 197 return err; 198 199 i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1)); 200 err = m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1); 201 202 return err; 203} 204 205static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val) 206{ 207 int err; 208 u8 i2c_data; 209 struct sd *sd = (struct sd *) gspca_dev; 210 211 PDEBUG(D_CONF, "Set auto gain control to %d", val); 212 213 err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1); 214 if (err < 0) 215 return err; 216 217 i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2)); 218 219 return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1); 220} 221 222static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev, 223 __s32 val) 224{ 225 int err; 226 u8 i2c_data; 227 struct sd *sd = (struct sd *) gspca_dev; 228 229 PDEBUG(D_CONF, "Set auto exposure control to %d", val); 230 231 err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1); 232 if (err < 0) 233 return err; 234 235 val = (val == V4L2_EXPOSURE_AUTO); 236 i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0)); 237 238 return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1); 239} 240 241static int ov7660_set_hvflip(struct gspca_dev *gspca_dev) 242{ 243 int err; 244 u8 i2c_data; 245 struct sd *sd = (struct sd *) gspca_dev; 246 247 PDEBUG(D_CONF, "Set hvflip to %d, %d", sd->hflip->val, sd->vflip->val); 248 249 i2c_data = (sd->hflip->val << 5) | (sd->vflip->val << 4); 250 251 err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1); 252 253 return err; 254} 255 256static int ov7660_s_ctrl(struct v4l2_ctrl *ctrl) 257{ 258 struct gspca_dev *gspca_dev = 259 container_of(ctrl->handler, struct gspca_dev, ctrl_handler); 260 struct sd *sd = (struct sd *) gspca_dev; 261 int err; 262 263 if (!gspca_dev->streaming) 264 return 0; 265 266 switch (ctrl->id) { 267 case V4L2_CID_AUTO_WHITE_BALANCE: 268 err = ov7660_set_auto_white_balance(gspca_dev, ctrl->val); 269 break; 270 case V4L2_CID_EXPOSURE_AUTO: 271 err = ov7660_set_auto_exposure(gspca_dev, ctrl->val); 272 break; 273 case V4L2_CID_AUTOGAIN: 274 err = ov7660_set_auto_gain(gspca_dev, ctrl->val); 275 if (err || ctrl->val) 276 return err; 277 err = ov7660_set_gain(gspca_dev, sd->gain->val); 278 break; 279 case V4L2_CID_HFLIP: 280 err = ov7660_set_hvflip(gspca_dev); 281 break; 282 default: 283 return -EINVAL; 284 } 285 286 return err; 287} 288 289static void ov7660_dump_registers(struct sd *sd) 290{ 291 int address; 292 pr_info("Dumping the ov7660 register state\n"); 293 for (address = 0; address < 0xa9; address++) { 294 u8 value; 295 m5602_read_sensor(sd, address, &value, 1); 296 pr_info("register 0x%x contains 0x%x\n", address, value); 297 } 298 299 pr_info("ov7660 register state dump complete\n"); 300 301 pr_info("Probing for which registers that are read/write\n"); 302 for (address = 0; address < 0xff; address++) { 303 u8 old_value, ctrl_value; 304 u8 test_value[2] = {0xff, 0xff}; 305 306 m5602_read_sensor(sd, address, &old_value, 1); 307 m5602_write_sensor(sd, address, test_value, 1); 308 m5602_read_sensor(sd, address, &ctrl_value, 1); 309 310 if (ctrl_value == test_value[0]) 311 pr_info("register 0x%x is writeable\n", address); 312 else 313 pr_info("register 0x%x is read only\n", address); 314 315 /* Restore original value */ 316 m5602_write_sensor(sd, address, &old_value, 1); 317 } 318} 319