Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher
0004  *            Mark Cave-Ayland, Carlo E Prelz, Dick Streefland
0005  * Copyright (c) 2002, 2003 Tuukka Toivonen
0006  * Copyright (c) 2008 Erik Andrén
0007  *
0008  * P/N 861037:      Sensor HDCS1000        ASIC STV0600
0009  * P/N 861050-0010: Sensor HDCS1000        ASIC STV0600
0010  * P/N 861050-0020: Sensor Photobit PB100  ASIC STV0600-1 - QuickCam Express
0011  * P/N 861055:      Sensor ST VV6410       ASIC STV0610   - LEGO cam
0012  * P/N 861075-0040: Sensor HDCS1000        ASIC
0013  * P/N 961179-0700: Sensor ST VV6410       ASIC STV0602   - Dexxa WebCam USB
0014  * P/N 861040-0000: Sensor ST VV6410       ASIC STV0610   - QuickCam Web
0015  */
0016 
0017 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0018 
0019 #include "stv06xx_vv6410.h"
0020 
0021 static struct v4l2_pix_format vv6410_mode[] = {
0022     {
0023         356,
0024         292,
0025         V4L2_PIX_FMT_SGRBG8,
0026         V4L2_FIELD_NONE,
0027         .sizeimage = 356 * 292,
0028         .bytesperline = 356,
0029         .colorspace = V4L2_COLORSPACE_SRGB,
0030         .priv = 0
0031     }
0032 };
0033 
0034 static int vv6410_s_ctrl(struct v4l2_ctrl *ctrl)
0035 {
0036     struct gspca_dev *gspca_dev =
0037         container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
0038     int err = -EINVAL;
0039 
0040     switch (ctrl->id) {
0041     case V4L2_CID_HFLIP:
0042         if (!gspca_dev->streaming)
0043             return 0;
0044         err = vv6410_set_hflip(gspca_dev, ctrl->val);
0045         break;
0046     case V4L2_CID_VFLIP:
0047         if (!gspca_dev->streaming)
0048             return 0;
0049         err = vv6410_set_vflip(gspca_dev, ctrl->val);
0050         break;
0051     case V4L2_CID_GAIN:
0052         err = vv6410_set_analog_gain(gspca_dev, ctrl->val);
0053         break;
0054     case V4L2_CID_EXPOSURE:
0055         err = vv6410_set_exposure(gspca_dev, ctrl->val);
0056         break;
0057     }
0058     return err;
0059 }
0060 
0061 static const struct v4l2_ctrl_ops vv6410_ctrl_ops = {
0062     .s_ctrl = vv6410_s_ctrl,
0063 };
0064 
0065 static int vv6410_probe(struct sd *sd)
0066 {
0067     u16 data;
0068     int err;
0069 
0070     err = stv06xx_read_sensor(sd, VV6410_DEVICEH, &data);
0071     if (err < 0)
0072         return -ENODEV;
0073 
0074     if (data != 0x19)
0075         return -ENODEV;
0076 
0077     pr_info("vv6410 sensor detected\n");
0078 
0079     sd->gspca_dev.cam.cam_mode = vv6410_mode;
0080     sd->gspca_dev.cam.nmodes = ARRAY_SIZE(vv6410_mode);
0081     return 0;
0082 }
0083 
0084 static int vv6410_init_controls(struct sd *sd)
0085 {
0086     struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
0087 
0088     v4l2_ctrl_handler_init(hdl, 2);
0089     /* Disable the hardware VFLIP and HFLIP as we currently lack a
0090        mechanism to adjust the image offset in such a way that
0091        we don't need to renegotiate the announced format */
0092     /* v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops, */
0093     /*      V4L2_CID_HFLIP, 0, 1, 1, 0); */
0094     /* v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops, */
0095     /*      V4L2_CID_VFLIP, 0, 1, 1, 0); */
0096     v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops,
0097             V4L2_CID_EXPOSURE, 0, 32768, 1, 20000);
0098     v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops,
0099             V4L2_CID_GAIN, 0, 15, 1, 10);
0100     return hdl->error;
0101 }
0102 
0103 static int vv6410_init(struct sd *sd)
0104 {
0105     int err = 0, i;
0106 
0107     for (i = 0; i < ARRAY_SIZE(stv_bridge_init); i++)
0108         stv06xx_write_bridge(sd, stv_bridge_init[i].addr, stv_bridge_init[i].data);
0109 
0110     err = stv06xx_write_sensor_bytes(sd, (u8 *) vv6410_sensor_init,
0111                      ARRAY_SIZE(vv6410_sensor_init));
0112     return (err < 0) ? err : 0;
0113 }
0114 
0115 static int vv6410_start(struct sd *sd)
0116 {
0117     int err;
0118     struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
0119     struct cam *cam = &sd->gspca_dev.cam;
0120     u32 priv = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
0121 
0122     if (priv & VV6410_SUBSAMPLE) {
0123         gspca_dbg(gspca_dev, D_CONF, "Enabling subsampling\n");
0124         stv06xx_write_bridge(sd, STV_Y_CTRL, 0x02);
0125         stv06xx_write_bridge(sd, STV_X_CTRL, 0x06);
0126 
0127         stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x10);
0128     } else {
0129         stv06xx_write_bridge(sd, STV_Y_CTRL, 0x01);
0130         stv06xx_write_bridge(sd, STV_X_CTRL, 0x0a);
0131         stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x00);
0132 
0133     }
0134 
0135     /* Turn on LED */
0136     err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_ON);
0137     if (err < 0)
0138         return err;
0139 
0140     err = stv06xx_write_sensor(sd, VV6410_SETUP0, 0);
0141     if (err < 0)
0142         return err;
0143 
0144     gspca_dbg(gspca_dev, D_STREAM, "Starting stream\n");
0145 
0146     return 0;
0147 }
0148 
0149 static int vv6410_stop(struct sd *sd)
0150 {
0151     struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
0152     int err;
0153 
0154     /* Turn off LED */
0155     err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_OFF);
0156     if (err < 0)
0157         return err;
0158 
0159     err = stv06xx_write_sensor(sd, VV6410_SETUP0, VV6410_LOW_POWER_MODE);
0160     if (err < 0)
0161         return err;
0162 
0163     gspca_dbg(gspca_dev, D_STREAM, "Halting stream\n");
0164 
0165     return 0;
0166 }
0167 
0168 static int vv6410_dump(struct sd *sd)
0169 {
0170     u8 i;
0171     int err = 0;
0172 
0173     pr_info("Dumping all vv6410 sensor registers\n");
0174     for (i = 0; i < 0xff && !err; i++) {
0175         u16 data;
0176         err = stv06xx_read_sensor(sd, i, &data);
0177         pr_info("Register 0x%x contained 0x%x\n", i, data);
0178     }
0179     return (err < 0) ? err : 0;
0180 }
0181 
0182 static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
0183 {
0184     int err;
0185     u16 i2c_data;
0186     struct sd *sd = (struct sd *) gspca_dev;
0187 
0188     err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
0189     if (err < 0)
0190         return err;
0191 
0192     if (val)
0193         i2c_data |= VV6410_HFLIP;
0194     else
0195         i2c_data &= ~VV6410_HFLIP;
0196 
0197     gspca_dbg(gspca_dev, D_CONF, "Set horizontal flip to %d\n", val);
0198     err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data);
0199 
0200     return (err < 0) ? err : 0;
0201 }
0202 
0203 static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
0204 {
0205     int err;
0206     u16 i2c_data;
0207     struct sd *sd = (struct sd *) gspca_dev;
0208 
0209     err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
0210     if (err < 0)
0211         return err;
0212 
0213     if (val)
0214         i2c_data |= VV6410_VFLIP;
0215     else
0216         i2c_data &= ~VV6410_VFLIP;
0217 
0218     gspca_dbg(gspca_dev, D_CONF, "Set vertical flip to %d\n", val);
0219     err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data);
0220 
0221     return (err < 0) ? err : 0;
0222 }
0223 
0224 static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val)
0225 {
0226     int err;
0227     struct sd *sd = (struct sd *) gspca_dev;
0228 
0229     gspca_dbg(gspca_dev, D_CONF, "Set analog gain to %d\n", val);
0230     err = stv06xx_write_sensor(sd, VV6410_ANALOGGAIN, 0xf0 | (val & 0xf));
0231 
0232     return (err < 0) ? err : 0;
0233 }
0234 
0235 static int vv6410_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
0236 {
0237     int err;
0238     struct sd *sd = (struct sd *) gspca_dev;
0239     unsigned int fine, coarse;
0240 
0241     val = (val * val >> 14) + val / 4;
0242 
0243     fine = val % VV6410_CIF_LINELENGTH;
0244     coarse = min(512, val / VV6410_CIF_LINELENGTH);
0245 
0246     gspca_dbg(gspca_dev, D_CONF, "Set coarse exposure to %d, fine exposure to %d\n",
0247           coarse, fine);
0248 
0249     err = stv06xx_write_sensor(sd, VV6410_FINEH, fine >> 8);
0250     if (err < 0)
0251         goto out;
0252 
0253     err = stv06xx_write_sensor(sd, VV6410_FINEL, fine & 0xff);
0254     if (err < 0)
0255         goto out;
0256 
0257     err = stv06xx_write_sensor(sd, VV6410_COARSEH, coarse >> 8);
0258     if (err < 0)
0259         goto out;
0260 
0261     err = stv06xx_write_sensor(sd, VV6410_COARSEL, coarse & 0xff);
0262 
0263 out:
0264     return err;
0265 }