1 /* 2 * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher 3 * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland 4 * Copyright (c) 2002, 2003 Tuukka Toivonen 5 * Copyright (c) 2008 Erik Andrén 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * 21 * P/N 861037: Sensor HDCS1000 ASIC STV0600 22 * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 23 * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express 24 * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam 25 * P/N 861075-0040: Sensor HDCS1000 ASIC 26 * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB 27 * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web 28 */ 29 30 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 31 32 #include "stv06xx_vv6410.h" 33 34 static struct v4l2_pix_format vv6410_mode[] = { 35 { 36 356, 37 292, 38 V4L2_PIX_FMT_SGRBG8, 39 V4L2_FIELD_NONE, 40 .sizeimage = 356 * 292, 41 .bytesperline = 356, 42 .colorspace = V4L2_COLORSPACE_SRGB, 43 .priv = 0 44 } 45 }; 46 47 static int vv6410_s_ctrl(struct v4l2_ctrl *ctrl) 48 { 49 struct gspca_dev *gspca_dev = 50 container_of(ctrl->handler, struct gspca_dev, ctrl_handler); 51 int err = -EINVAL; 52 53 switch (ctrl->id) { 54 case V4L2_CID_HFLIP: 55 if (!gspca_dev->streaming) 56 return 0; 57 err = vv6410_set_hflip(gspca_dev, ctrl->val); 58 break; 59 case V4L2_CID_VFLIP: 60 if (!gspca_dev->streaming) 61 return 0; 62 err = vv6410_set_vflip(gspca_dev, ctrl->val); 63 break; 64 case V4L2_CID_GAIN: 65 err = vv6410_set_analog_gain(gspca_dev, ctrl->val); 66 break; 67 case V4L2_CID_EXPOSURE: 68 err = vv6410_set_exposure(gspca_dev, ctrl->val); 69 break; 70 } 71 return err; 72 } 73 74 static const struct v4l2_ctrl_ops vv6410_ctrl_ops = { 75 .s_ctrl = vv6410_s_ctrl, 76 }; 77 78 static int vv6410_probe(struct sd *sd) 79 { 80 u16 data; 81 int err; 82 83 err = stv06xx_read_sensor(sd, VV6410_DEVICEH, &data); 84 if (err < 0) 85 return -ENODEV; 86 87 if (data != 0x19) 88 return -ENODEV; 89 90 pr_info("vv6410 sensor detected\n"); 91 92 sd->gspca_dev.cam.cam_mode = vv6410_mode; 93 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(vv6410_mode); 94 return 0; 95 } 96 97 static int vv6410_init_controls(struct sd *sd) 98 { 99 struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler; 100 101 v4l2_ctrl_handler_init(hdl, 2); 102 /* Disable the hardware VFLIP and HFLIP as we currently lack a 103 mechanism to adjust the image offset in such a way that 104 we don't need to renegotiate the announced format */ 105 /* v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops, */ 106 /* V4L2_CID_HFLIP, 0, 1, 1, 0); */ 107 /* v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops, */ 108 /* V4L2_CID_VFLIP, 0, 1, 1, 0); */ 109 v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops, 110 V4L2_CID_EXPOSURE, 0, 32768, 1, 20000); 111 v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops, 112 V4L2_CID_GAIN, 0, 15, 1, 10); 113 return hdl->error; 114 } 115 116 static int vv6410_init(struct sd *sd) 117 { 118 int err = 0, i; 119 120 for (i = 0; i < ARRAY_SIZE(stv_bridge_init); i++) 121 stv06xx_write_bridge(sd, stv_bridge_init[i].addr, stv_bridge_init[i].data); 122 123 if (err < 0) 124 return err; 125 126 err = stv06xx_write_sensor_bytes(sd, (u8 *) vv6410_sensor_init, 127 ARRAY_SIZE(vv6410_sensor_init)); 128 return (err < 0) ? err : 0; 129 } 130 131 static int vv6410_start(struct sd *sd) 132 { 133 int err; 134 struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; 135 struct cam *cam = &sd->gspca_dev.cam; 136 u32 priv = cam->cam_mode[sd->gspca_dev.curr_mode].priv; 137 138 if (priv & VV6410_SUBSAMPLE) { 139 PDEBUG(D_CONF, "Enabling subsampling"); 140 stv06xx_write_bridge(sd, STV_Y_CTRL, 0x02); 141 stv06xx_write_bridge(sd, STV_X_CTRL, 0x06); 142 143 stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x10); 144 } else { 145 stv06xx_write_bridge(sd, STV_Y_CTRL, 0x01); 146 stv06xx_write_bridge(sd, STV_X_CTRL, 0x0a); 147 stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x00); 148 149 } 150 151 /* Turn on LED */ 152 err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_ON); 153 if (err < 0) 154 return err; 155 156 err = stv06xx_write_sensor(sd, VV6410_SETUP0, 0); 157 if (err < 0) 158 return err; 159 160 PDEBUG(D_STREAM, "Starting stream"); 161 162 return 0; 163 } 164 165 static int vv6410_stop(struct sd *sd) 166 { 167 struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; 168 int err; 169 170 /* Turn off LED */ 171 err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_OFF); 172 if (err < 0) 173 return err; 174 175 err = stv06xx_write_sensor(sd, VV6410_SETUP0, VV6410_LOW_POWER_MODE); 176 if (err < 0) 177 return err; 178 179 PDEBUG(D_STREAM, "Halting stream"); 180 181 return (err < 0) ? err : 0; 182 } 183 184 static int vv6410_dump(struct sd *sd) 185 { 186 u8 i; 187 int err = 0; 188 189 pr_info("Dumping all vv6410 sensor registers\n"); 190 for (i = 0; i < 0xff && !err; i++) { 191 u16 data; 192 err = stv06xx_read_sensor(sd, i, &data); 193 pr_info("Register 0x%x contained 0x%x\n", i, data); 194 } 195 return (err < 0) ? err : 0; 196 } 197 198 static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val) 199 { 200 int err; 201 u16 i2c_data; 202 struct sd *sd = (struct sd *) gspca_dev; 203 204 err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data); 205 if (err < 0) 206 return err; 207 208 if (val) 209 i2c_data |= VV6410_HFLIP; 210 else 211 i2c_data &= ~VV6410_HFLIP; 212 213 PDEBUG(D_CONF, "Set horizontal flip to %d", val); 214 err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data); 215 216 return (err < 0) ? err : 0; 217 } 218 219 static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val) 220 { 221 int err; 222 u16 i2c_data; 223 struct sd *sd = (struct sd *) gspca_dev; 224 225 err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data); 226 if (err < 0) 227 return err; 228 229 if (val) 230 i2c_data |= VV6410_VFLIP; 231 else 232 i2c_data &= ~VV6410_VFLIP; 233 234 PDEBUG(D_CONF, "Set vertical flip to %d", val); 235 err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data); 236 237 return (err < 0) ? err : 0; 238 } 239 240 static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val) 241 { 242 int err; 243 struct sd *sd = (struct sd *) gspca_dev; 244 245 PDEBUG(D_CONF, "Set analog gain to %d", val); 246 err = stv06xx_write_sensor(sd, VV6410_ANALOGGAIN, 0xf0 | (val & 0xf)); 247 248 return (err < 0) ? err : 0; 249 } 250 251 static int vv6410_set_exposure(struct gspca_dev *gspca_dev, __s32 val) 252 { 253 int err; 254 struct sd *sd = (struct sd *) gspca_dev; 255 unsigned int fine, coarse; 256 257 val = (val * val >> 14) + val / 4; 258 259 fine = val % VV6410_CIF_LINELENGTH; 260 coarse = min(512, val / VV6410_CIF_LINELENGTH); 261 262 PDEBUG(D_CONF, "Set coarse exposure to %d, fine expsure to %d", 263 coarse, fine); 264 265 err = stv06xx_write_sensor(sd, VV6410_FINEH, fine >> 8); 266 if (err < 0) 267 goto out; 268 269 err = stv06xx_write_sensor(sd, VV6410_FINEL, fine & 0xff); 270 if (err < 0) 271 goto out; 272 273 err = stv06xx_write_sensor(sd, VV6410_COARSEH, coarse >> 8); 274 if (err < 0) 275 goto out; 276 277 err = stv06xx_write_sensor(sd, VV6410_COARSEL, coarse & 0xff); 278 279 out: 280 return err; 281 } 282