1/* 2 * Support for the sensor part which is integrated (I think) into the 3 * st6422 stv06xx alike bridge, as its integrated there are no i2c writes 4 * but instead direct bridge writes. 5 * 6 * Copyright (c) 2009 Hans de Goede <hdegoede@redhat.com> 7 * 8 * Strongly based on qc-usb-messenger, which is: 9 * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher 10 * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland 11 * Copyright (c) 2002, 2003 Tuukka Toivonen 12 * 13 * This program is free software; you can redistribute it and/or modify 14 * it under the terms of the GNU General Public License as published by 15 * the Free Software Foundation; either version 2 of the License, or 16 * (at your option) any later version. 17 * 18 * This program is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 * GNU General Public License for more details. 22 * 23 * You should have received a copy of the GNU General Public License 24 * along with this program; if not, write to the Free Software 25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 26 * 27 */ 28 29#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 30 31#include "stv06xx_st6422.h" 32 33static struct v4l2_pix_format st6422_mode[] = { 34 /* Note we actually get 124 lines of data, of which we skip the 4st 35 4 as they are garbage */ 36 { 37 162, 38 120, 39 V4L2_PIX_FMT_SGRBG8, 40 V4L2_FIELD_NONE, 41 .sizeimage = 162 * 120, 42 .bytesperline = 162, 43 .colorspace = V4L2_COLORSPACE_SRGB, 44 .priv = 1 45 }, 46 /* Note we actually get 248 lines of data, of which we skip the 4st 47 4 as they are garbage, and we tell the app it only gets the 48 first 240 of the 244 lines it actually gets, so that it ignores 49 the last 4. */ 50 { 51 324, 52 240, 53 V4L2_PIX_FMT_SGRBG8, 54 V4L2_FIELD_NONE, 55 .sizeimage = 324 * 244, 56 .bytesperline = 324, 57 .colorspace = V4L2_COLORSPACE_SRGB, 58 .priv = 0 59 }, 60}; 61 62/* V4L2 controls supported by the driver */ 63static int setbrightness(struct sd *sd, s32 val); 64static int setcontrast(struct sd *sd, s32 val); 65static int setgain(struct sd *sd, u8 gain); 66static int setexposure(struct sd *sd, s16 expo); 67 68static int st6422_s_ctrl(struct v4l2_ctrl *ctrl) 69{ 70 struct gspca_dev *gspca_dev = 71 container_of(ctrl->handler, struct gspca_dev, ctrl_handler); 72 struct sd *sd = (struct sd *)gspca_dev; 73 int err = -EINVAL; 74 75 switch (ctrl->id) { 76 case V4L2_CID_BRIGHTNESS: 77 err = setbrightness(sd, ctrl->val); 78 break; 79 case V4L2_CID_CONTRAST: 80 err = setcontrast(sd, ctrl->val); 81 break; 82 case V4L2_CID_GAIN: 83 err = setgain(sd, ctrl->val); 84 break; 85 case V4L2_CID_EXPOSURE: 86 err = setexposure(sd, ctrl->val); 87 break; 88 } 89 90 /* commit settings */ 91 if (err >= 0) 92 err = stv06xx_write_bridge(sd, 0x143f, 0x01); 93 sd->gspca_dev.usb_err = err; 94 return err; 95} 96 97static const struct v4l2_ctrl_ops st6422_ctrl_ops = { 98 .s_ctrl = st6422_s_ctrl, 99}; 100 101static int st6422_init_controls(struct sd *sd) 102{ 103 struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler; 104 105 v4l2_ctrl_handler_init(hdl, 4); 106 v4l2_ctrl_new_std(hdl, &st6422_ctrl_ops, 107 V4L2_CID_BRIGHTNESS, 0, 31, 1, 3); 108 v4l2_ctrl_new_std(hdl, &st6422_ctrl_ops, 109 V4L2_CID_CONTRAST, 0, 15, 1, 11); 110 v4l2_ctrl_new_std(hdl, &st6422_ctrl_ops, 111 V4L2_CID_EXPOSURE, 0, 1023, 1, 256); 112 v4l2_ctrl_new_std(hdl, &st6422_ctrl_ops, 113 V4L2_CID_GAIN, 0, 255, 1, 64); 114 115 return hdl->error; 116} 117 118static int st6422_probe(struct sd *sd) 119{ 120 if (sd->bridge != BRIDGE_ST6422) 121 return -ENODEV; 122 123 pr_info("st6422 sensor detected\n"); 124 125 sd->gspca_dev.cam.cam_mode = st6422_mode; 126 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(st6422_mode); 127 return 0; 128} 129 130static int st6422_init(struct sd *sd) 131{ 132 int err = 0, i; 133 134 const u16 st6422_bridge_init[][2] = { 135 { STV_ISO_ENABLE, 0x00 }, /* disable capture */ 136 { 0x1436, 0x00 }, 137 { 0x1432, 0x03 }, /* 0x00-0x1F brightness */ 138 { 0x143a, 0xf9 }, /* 0x00-0x0F contrast */ 139 { 0x0509, 0x38 }, /* R */ 140 { 0x050a, 0x38 }, /* G */ 141 { 0x050b, 0x38 }, /* B */ 142 { 0x050c, 0x2a }, 143 { 0x050d, 0x01 }, 144 145 146 { 0x1431, 0x00 }, /* 0x00-0x07 ??? */ 147 { 0x1433, 0x34 }, /* 160x120, 0x00-0x01 night filter */ 148 { 0x1438, 0x18 }, /* 640x480 */ 149/* 18 bayes */ 150/* 10 compressed? */ 151 152 { 0x1439, 0x00 }, 153/* anti-noise? 0xa2 gives a perfect image */ 154 155 { 0x143b, 0x05 }, 156 { 0x143c, 0x00 }, /* 0x00-0x01 - ??? */ 157 158 159/* shutter time 0x0000-0x03FF */ 160/* low value give good picures on moving objects (but requires much light) */ 161/* high value gives good picures in darkness (but tends to be overexposed) */ 162 { 0x143e, 0x01 }, 163 { 0x143d, 0x00 }, 164 165 { 0x1442, 0xe2 }, 166/* write: 1x1x xxxx */ 167/* read: 1x1x xxxx */ 168/* bit 5 == button pressed and hold if 0 */ 169/* write 0xe2,0xea */ 170 171/* 0x144a */ 172/* 0x00 init */ 173/* bit 7 == button has been pressed, but not handled */ 174 175/* interrupt */ 176/* if(urb->iso_frame_desc[i].status == 0x80) { */ 177/* if(urb->iso_frame_desc[i].status == 0x88) { */ 178 179 { 0x1500, 0xd0 }, 180 { 0x1500, 0xd0 }, 181 { 0x1500, 0x50 }, /* 0x00 - 0xFF 0x80 == compr ? */ 182 183 { 0x1501, 0xaf }, 184/* high val-> light area gets darker */ 185/* low val -> light area gets lighter */ 186 { 0x1502, 0xc2 }, 187/* high val-> light area gets darker */ 188/* low val -> light area gets lighter */ 189 { 0x1503, 0x45 }, 190/* high val-> light area gets darker */ 191/* low val -> light area gets lighter */ 192 { 0x1505, 0x02 }, 193/* 2 : 324x248 80352 bytes */ 194/* 7 : 248x162 40176 bytes */ 195/* c+f: 162*124 20088 bytes */ 196 197 { 0x150e, 0x8e }, 198 { 0x150f, 0x37 }, 199 { 0x15c0, 0x00 }, 200 { 0x15c3, 0x08 }, /* 0x04/0x14 ... test pictures ??? */ 201 202 203 { 0x143f, 0x01 }, /* commit settings */ 204 205 }; 206 207 for (i = 0; i < ARRAY_SIZE(st6422_bridge_init) && !err; i++) { 208 err = stv06xx_write_bridge(sd, st6422_bridge_init[i][0], 209 st6422_bridge_init[i][1]); 210 } 211 212 return err; 213} 214 215static int setbrightness(struct sd *sd, s32 val) 216{ 217 /* val goes from 0 -> 31 */ 218 return stv06xx_write_bridge(sd, 0x1432, val); 219} 220 221static int setcontrast(struct sd *sd, s32 val) 222{ 223 /* Val goes from 0 -> 15 */ 224 return stv06xx_write_bridge(sd, 0x143a, val | 0xf0); 225} 226 227static int setgain(struct sd *sd, u8 gain) 228{ 229 int err; 230 231 /* Set red, green, blue, gain */ 232 err = stv06xx_write_bridge(sd, 0x0509, gain); 233 if (err < 0) 234 return err; 235 236 err = stv06xx_write_bridge(sd, 0x050a, gain); 237 if (err < 0) 238 return err; 239 240 err = stv06xx_write_bridge(sd, 0x050b, gain); 241 if (err < 0) 242 return err; 243 244 /* 2 mystery writes */ 245 err = stv06xx_write_bridge(sd, 0x050c, 0x2a); 246 if (err < 0) 247 return err; 248 249 return stv06xx_write_bridge(sd, 0x050d, 0x01); 250} 251 252static int setexposure(struct sd *sd, s16 expo) 253{ 254 int err; 255 256 err = stv06xx_write_bridge(sd, 0x143d, expo & 0xff); 257 if (err < 0) 258 return err; 259 260 return stv06xx_write_bridge(sd, 0x143e, expo >> 8); 261} 262 263static int st6422_start(struct sd *sd) 264{ 265 int err; 266 struct cam *cam = &sd->gspca_dev.cam; 267 268 if (cam->cam_mode[sd->gspca_dev.curr_mode].priv) 269 err = stv06xx_write_bridge(sd, 0x1505, 0x0f); 270 else 271 err = stv06xx_write_bridge(sd, 0x1505, 0x02); 272 if (err < 0) 273 return err; 274 275 /* commit settings */ 276 err = stv06xx_write_bridge(sd, 0x143f, 0x01); 277 return (err < 0) ? err : 0; 278} 279 280static int st6422_stop(struct sd *sd) 281{ 282 struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; 283 284 PDEBUG(D_STREAM, "Halting stream"); 285 286 return 0; 287} 288