162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher 462306a36Sopenharmony_ci * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland 562306a36Sopenharmony_ci * Copyright (c) 2002, 2003 Tuukka Toivonen 662306a36Sopenharmony_ci * Copyright (c) 2008 Erik Andrén 762306a36Sopenharmony_ci * Copyright (c) 2008 Chia-I Wu 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * P/N 861037: Sensor HDCS1000 ASIC STV0600 1062306a36Sopenharmony_ci * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 1162306a36Sopenharmony_ci * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express 1262306a36Sopenharmony_ci * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam 1362306a36Sopenharmony_ci * P/N 861075-0040: Sensor HDCS1000 ASIC 1462306a36Sopenharmony_ci * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB 1562306a36Sopenharmony_ci * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web 1662306a36Sopenharmony_ci */ 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "stv06xx_hdcs.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic struct v4l2_pix_format hdcs1x00_mode[] = { 2362306a36Sopenharmony_ci { 2462306a36Sopenharmony_ci HDCS_1X00_DEF_WIDTH, 2562306a36Sopenharmony_ci HDCS_1X00_DEF_HEIGHT, 2662306a36Sopenharmony_ci V4L2_PIX_FMT_SGRBG8, 2762306a36Sopenharmony_ci V4L2_FIELD_NONE, 2862306a36Sopenharmony_ci .sizeimage = 2962306a36Sopenharmony_ci HDCS_1X00_DEF_WIDTH * HDCS_1X00_DEF_HEIGHT, 3062306a36Sopenharmony_ci .bytesperline = HDCS_1X00_DEF_WIDTH, 3162306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 3262306a36Sopenharmony_ci .priv = 1 3362306a36Sopenharmony_ci } 3462306a36Sopenharmony_ci}; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic struct v4l2_pix_format hdcs1020_mode[] = { 3762306a36Sopenharmony_ci { 3862306a36Sopenharmony_ci HDCS_1020_DEF_WIDTH, 3962306a36Sopenharmony_ci HDCS_1020_DEF_HEIGHT, 4062306a36Sopenharmony_ci V4L2_PIX_FMT_SGRBG8, 4162306a36Sopenharmony_ci V4L2_FIELD_NONE, 4262306a36Sopenharmony_ci .sizeimage = 4362306a36Sopenharmony_ci HDCS_1020_DEF_WIDTH * HDCS_1020_DEF_HEIGHT, 4462306a36Sopenharmony_ci .bytesperline = HDCS_1020_DEF_WIDTH, 4562306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 4662306a36Sopenharmony_ci .priv = 1 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci}; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cienum hdcs_power_state { 5162306a36Sopenharmony_ci HDCS_STATE_SLEEP, 5262306a36Sopenharmony_ci HDCS_STATE_IDLE, 5362306a36Sopenharmony_ci HDCS_STATE_RUN 5462306a36Sopenharmony_ci}; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* no lock? */ 5762306a36Sopenharmony_cistruct hdcs { 5862306a36Sopenharmony_ci enum hdcs_power_state state; 5962306a36Sopenharmony_ci int w, h; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci /* visible area of the sensor array */ 6262306a36Sopenharmony_ci struct { 6362306a36Sopenharmony_ci int left, top; 6462306a36Sopenharmony_ci int width, height; 6562306a36Sopenharmony_ci int border; 6662306a36Sopenharmony_ci } array; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci struct { 6962306a36Sopenharmony_ci /* Column timing overhead */ 7062306a36Sopenharmony_ci u8 cto; 7162306a36Sopenharmony_ci /* Column processing overhead */ 7262306a36Sopenharmony_ci u8 cpo; 7362306a36Sopenharmony_ci /* Row sample period constant */ 7462306a36Sopenharmony_ci u16 rs; 7562306a36Sopenharmony_ci /* Exposure reset duration */ 7662306a36Sopenharmony_ci u16 er; 7762306a36Sopenharmony_ci } exp; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci int psmp; 8062306a36Sopenharmony_ci}; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic int hdcs_reg_write_seq(struct sd *sd, u8 reg, u8 *vals, u8 len) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci u8 regs[I2C_MAX_BYTES * 2]; 8562306a36Sopenharmony_ci int i; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci if (unlikely((len <= 0) || (len >= I2C_MAX_BYTES) || 8862306a36Sopenharmony_ci (reg + len > 0xff))) 8962306a36Sopenharmony_ci return -EINVAL; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci for (i = 0; i < len; i++) { 9262306a36Sopenharmony_ci regs[2 * i] = reg; 9362306a36Sopenharmony_ci regs[2 * i + 1] = vals[i]; 9462306a36Sopenharmony_ci /* All addresses are shifted left one bit 9562306a36Sopenharmony_ci * as bit 0 toggles r/w */ 9662306a36Sopenharmony_ci reg += 2; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci return stv06xx_write_sensor_bytes(sd, regs, len); 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic int hdcs_set_state(struct sd *sd, enum hdcs_power_state state) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci struct hdcs *hdcs = sd->sensor_priv; 10562306a36Sopenharmony_ci u8 val; 10662306a36Sopenharmony_ci int ret; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if (hdcs->state == state) 10962306a36Sopenharmony_ci return 0; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci /* we need to go idle before running or sleeping */ 11262306a36Sopenharmony_ci if (hdcs->state != HDCS_STATE_IDLE) { 11362306a36Sopenharmony_ci ret = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 0); 11462306a36Sopenharmony_ci if (ret) 11562306a36Sopenharmony_ci return ret; 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci hdcs->state = HDCS_STATE_IDLE; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (state == HDCS_STATE_IDLE) 12162306a36Sopenharmony_ci return 0; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci switch (state) { 12462306a36Sopenharmony_ci case HDCS_STATE_SLEEP: 12562306a36Sopenharmony_ci val = HDCS_SLEEP_MODE; 12662306a36Sopenharmony_ci break; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci case HDCS_STATE_RUN: 12962306a36Sopenharmony_ci val = HDCS_RUN_ENABLE; 13062306a36Sopenharmony_ci break; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci default: 13362306a36Sopenharmony_ci return -EINVAL; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci ret = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), val); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci /* Update the state if the write succeeded */ 13962306a36Sopenharmony_ci if (!ret) 14062306a36Sopenharmony_ci hdcs->state = state; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci return ret; 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic int hdcs_reset(struct sd *sd) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci struct hdcs *hdcs = sd->sensor_priv; 14862306a36Sopenharmony_ci int err; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci err = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 1); 15162306a36Sopenharmony_ci if (err < 0) 15262306a36Sopenharmony_ci return err; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci err = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 0); 15562306a36Sopenharmony_ci if (err < 0) 15662306a36Sopenharmony_ci hdcs->state = HDCS_STATE_IDLE; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci return err; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 16462306a36Sopenharmony_ci struct hdcs *hdcs = sd->sensor_priv; 16562306a36Sopenharmony_ci int rowexp, srowexp; 16662306a36Sopenharmony_ci int max_srowexp; 16762306a36Sopenharmony_ci /* Column time period */ 16862306a36Sopenharmony_ci int ct; 16962306a36Sopenharmony_ci /* Column processing period */ 17062306a36Sopenharmony_ci int cp; 17162306a36Sopenharmony_ci /* Row processing period */ 17262306a36Sopenharmony_ci int rp; 17362306a36Sopenharmony_ci /* Minimum number of column timing periods 17462306a36Sopenharmony_ci within the column processing period */ 17562306a36Sopenharmony_ci int mnct; 17662306a36Sopenharmony_ci int cycles, err; 17762306a36Sopenharmony_ci u8 exp[14]; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci cycles = val * HDCS_CLK_FREQ_MHZ * 257; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci ct = hdcs->exp.cto + hdcs->psmp + (HDCS_ADC_START_SIG_DUR + 2); 18262306a36Sopenharmony_ci cp = hdcs->exp.cto + (hdcs->w * ct / 2); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci /* the cycles one row takes */ 18562306a36Sopenharmony_ci rp = hdcs->exp.rs + cp; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci rowexp = cycles / rp; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* the remaining cycles */ 19062306a36Sopenharmony_ci cycles -= rowexp * rp; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci /* calculate sub-row exposure */ 19362306a36Sopenharmony_ci if (IS_1020(sd)) { 19462306a36Sopenharmony_ci /* see HDCS-1020 datasheet 3.5.6.4, p. 63 */ 19562306a36Sopenharmony_ci srowexp = hdcs->w - (cycles + hdcs->exp.er + 13) / ct; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci mnct = (hdcs->exp.er + 12 + ct - 1) / ct; 19862306a36Sopenharmony_ci max_srowexp = hdcs->w - mnct; 19962306a36Sopenharmony_ci } else { 20062306a36Sopenharmony_ci /* see HDCS-1000 datasheet 3.4.5.5, p. 61 */ 20162306a36Sopenharmony_ci srowexp = cp - hdcs->exp.er - 6 - cycles; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci mnct = (hdcs->exp.er + 5 + ct - 1) / ct; 20462306a36Sopenharmony_ci max_srowexp = cp - mnct * ct - 1; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if (srowexp < 0) 20862306a36Sopenharmony_ci srowexp = 0; 20962306a36Sopenharmony_ci else if (srowexp > max_srowexp) 21062306a36Sopenharmony_ci srowexp = max_srowexp; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (IS_1020(sd)) { 21362306a36Sopenharmony_ci exp[0] = HDCS20_CONTROL; 21462306a36Sopenharmony_ci exp[1] = 0x00; /* Stop streaming */ 21562306a36Sopenharmony_ci exp[2] = HDCS_ROWEXPL; 21662306a36Sopenharmony_ci exp[3] = rowexp & 0xff; 21762306a36Sopenharmony_ci exp[4] = HDCS_ROWEXPH; 21862306a36Sopenharmony_ci exp[5] = rowexp >> 8; 21962306a36Sopenharmony_ci exp[6] = HDCS20_SROWEXP; 22062306a36Sopenharmony_ci exp[7] = (srowexp >> 2) & 0xff; 22162306a36Sopenharmony_ci exp[8] = HDCS20_ERROR; 22262306a36Sopenharmony_ci exp[9] = 0x10; /* Clear exposure error flag*/ 22362306a36Sopenharmony_ci exp[10] = HDCS20_CONTROL; 22462306a36Sopenharmony_ci exp[11] = 0x04; /* Restart streaming */ 22562306a36Sopenharmony_ci err = stv06xx_write_sensor_bytes(sd, exp, 6); 22662306a36Sopenharmony_ci } else { 22762306a36Sopenharmony_ci exp[0] = HDCS00_CONTROL; 22862306a36Sopenharmony_ci exp[1] = 0x00; /* Stop streaming */ 22962306a36Sopenharmony_ci exp[2] = HDCS_ROWEXPL; 23062306a36Sopenharmony_ci exp[3] = rowexp & 0xff; 23162306a36Sopenharmony_ci exp[4] = HDCS_ROWEXPH; 23262306a36Sopenharmony_ci exp[5] = rowexp >> 8; 23362306a36Sopenharmony_ci exp[6] = HDCS00_SROWEXPL; 23462306a36Sopenharmony_ci exp[7] = srowexp & 0xff; 23562306a36Sopenharmony_ci exp[8] = HDCS00_SROWEXPH; 23662306a36Sopenharmony_ci exp[9] = srowexp >> 8; 23762306a36Sopenharmony_ci exp[10] = HDCS_STATUS; 23862306a36Sopenharmony_ci exp[11] = 0x10; /* Clear exposure error flag*/ 23962306a36Sopenharmony_ci exp[12] = HDCS00_CONTROL; 24062306a36Sopenharmony_ci exp[13] = 0x04; /* Restart streaming */ 24162306a36Sopenharmony_ci err = stv06xx_write_sensor_bytes(sd, exp, 7); 24262306a36Sopenharmony_ci if (err < 0) 24362306a36Sopenharmony_ci return err; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_CONF, "Writing exposure %d, rowexp %d, srowexp %d\n", 24662306a36Sopenharmony_ci val, rowexp, srowexp); 24762306a36Sopenharmony_ci return err; 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic int hdcs_set_gains(struct sd *sd, u8 g) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci int err; 25362306a36Sopenharmony_ci u8 gains[4]; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci /* the voltage gain Av = (1 + 19 * val / 127) * (1 + bit7) */ 25662306a36Sopenharmony_ci if (g > 127) 25762306a36Sopenharmony_ci g = 0x80 | (g / 2); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci gains[0] = g; 26062306a36Sopenharmony_ci gains[1] = g; 26162306a36Sopenharmony_ci gains[2] = g; 26262306a36Sopenharmony_ci gains[3] = g; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci err = hdcs_reg_write_seq(sd, HDCS_ERECPGA, gains, 4); 26562306a36Sopenharmony_ci return err; 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_cistatic int hdcs_set_gain(struct gspca_dev *gspca_dev, __s32 val) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_CONF, "Writing gain %d\n", val); 27162306a36Sopenharmony_ci return hdcs_set_gains((struct sd *) gspca_dev, 27262306a36Sopenharmony_ci val & 0xff); 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic int hdcs_set_size(struct sd *sd, 27662306a36Sopenharmony_ci unsigned int width, unsigned int height) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci struct hdcs *hdcs = sd->sensor_priv; 27962306a36Sopenharmony_ci u8 win[4]; 28062306a36Sopenharmony_ci unsigned int x, y; 28162306a36Sopenharmony_ci int err; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci /* must be multiple of 4 */ 28462306a36Sopenharmony_ci width = (width + 3) & ~0x3; 28562306a36Sopenharmony_ci height = (height + 3) & ~0x3; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (width > hdcs->array.width) 28862306a36Sopenharmony_ci width = hdcs->array.width; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if (IS_1020(sd)) { 29162306a36Sopenharmony_ci /* the borders are also invalid */ 29262306a36Sopenharmony_ci if (height + 2 * hdcs->array.border + HDCS_1020_BOTTOM_Y_SKIP 29362306a36Sopenharmony_ci > hdcs->array.height) 29462306a36Sopenharmony_ci height = hdcs->array.height - 2 * hdcs->array.border - 29562306a36Sopenharmony_ci HDCS_1020_BOTTOM_Y_SKIP; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci y = (hdcs->array.height - HDCS_1020_BOTTOM_Y_SKIP - height) / 2 29862306a36Sopenharmony_ci + hdcs->array.top; 29962306a36Sopenharmony_ci } else { 30062306a36Sopenharmony_ci if (height > hdcs->array.height) 30162306a36Sopenharmony_ci height = hdcs->array.height; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci y = hdcs->array.top + (hdcs->array.height - height) / 2; 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci x = hdcs->array.left + (hdcs->array.width - width) / 2; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci win[0] = y / 4; 30962306a36Sopenharmony_ci win[1] = x / 4; 31062306a36Sopenharmony_ci win[2] = (y + height) / 4 - 1; 31162306a36Sopenharmony_ci win[3] = (x + width) / 4 - 1; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci err = hdcs_reg_write_seq(sd, HDCS_FWROW, win, 4); 31462306a36Sopenharmony_ci if (err < 0) 31562306a36Sopenharmony_ci return err; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci /* Update the current width and height */ 31862306a36Sopenharmony_ci hdcs->w = width; 31962306a36Sopenharmony_ci hdcs->h = height; 32062306a36Sopenharmony_ci return err; 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic int hdcs_s_ctrl(struct v4l2_ctrl *ctrl) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci struct gspca_dev *gspca_dev = 32662306a36Sopenharmony_ci container_of(ctrl->handler, struct gspca_dev, ctrl_handler); 32762306a36Sopenharmony_ci int err = -EINVAL; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci switch (ctrl->id) { 33062306a36Sopenharmony_ci case V4L2_CID_GAIN: 33162306a36Sopenharmony_ci err = hdcs_set_gain(gspca_dev, ctrl->val); 33262306a36Sopenharmony_ci break; 33362306a36Sopenharmony_ci case V4L2_CID_EXPOSURE: 33462306a36Sopenharmony_ci err = hdcs_set_exposure(gspca_dev, ctrl->val); 33562306a36Sopenharmony_ci break; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci return err; 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic const struct v4l2_ctrl_ops hdcs_ctrl_ops = { 34162306a36Sopenharmony_ci .s_ctrl = hdcs_s_ctrl, 34262306a36Sopenharmony_ci}; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistatic int hdcs_init_controls(struct sd *sd) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci v4l2_ctrl_handler_init(hdl, 2); 34962306a36Sopenharmony_ci v4l2_ctrl_new_std(hdl, &hdcs_ctrl_ops, 35062306a36Sopenharmony_ci V4L2_CID_EXPOSURE, 0, 0xff, 1, HDCS_DEFAULT_EXPOSURE); 35162306a36Sopenharmony_ci v4l2_ctrl_new_std(hdl, &hdcs_ctrl_ops, 35262306a36Sopenharmony_ci V4L2_CID_GAIN, 0, 0xff, 1, HDCS_DEFAULT_GAIN); 35362306a36Sopenharmony_ci return hdl->error; 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic int hdcs_probe_1x00(struct sd *sd) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci struct hdcs *hdcs; 35962306a36Sopenharmony_ci u16 sensor; 36062306a36Sopenharmony_ci int ret; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci ret = stv06xx_read_sensor(sd, HDCS_IDENT, &sensor); 36362306a36Sopenharmony_ci if (ret < 0 || sensor != 0x08) 36462306a36Sopenharmony_ci return -ENODEV; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci pr_info("HDCS-1000/1100 sensor detected\n"); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci sd->gspca_dev.cam.cam_mode = hdcs1x00_mode; 36962306a36Sopenharmony_ci sd->gspca_dev.cam.nmodes = ARRAY_SIZE(hdcs1x00_mode); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL); 37262306a36Sopenharmony_ci if (!hdcs) 37362306a36Sopenharmony_ci return -ENOMEM; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci hdcs->array.left = 8; 37662306a36Sopenharmony_ci hdcs->array.top = 8; 37762306a36Sopenharmony_ci hdcs->array.width = HDCS_1X00_DEF_WIDTH; 37862306a36Sopenharmony_ci hdcs->array.height = HDCS_1X00_DEF_HEIGHT; 37962306a36Sopenharmony_ci hdcs->array.border = 4; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci hdcs->exp.cto = 4; 38262306a36Sopenharmony_ci hdcs->exp.cpo = 2; 38362306a36Sopenharmony_ci hdcs->exp.rs = 186; 38462306a36Sopenharmony_ci hdcs->exp.er = 100; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci /* 38762306a36Sopenharmony_ci * Frame rate on HDCS-1000 with STV600 depends on PSMP: 38862306a36Sopenharmony_ci * 4 = doesn't work at all 38962306a36Sopenharmony_ci * 5 = 7.8 fps, 39062306a36Sopenharmony_ci * 6 = 6.9 fps, 39162306a36Sopenharmony_ci * 8 = 6.3 fps, 39262306a36Sopenharmony_ci * 10 = 5.5 fps, 39362306a36Sopenharmony_ci * 15 = 4.4 fps, 39462306a36Sopenharmony_ci * 31 = 2.8 fps 39562306a36Sopenharmony_ci * 39662306a36Sopenharmony_ci * Frame rate on HDCS-1000 with STV602 depends on PSMP: 39762306a36Sopenharmony_ci * 15 = doesn't work at all 39862306a36Sopenharmony_ci * 18 = doesn't work at all 39962306a36Sopenharmony_ci * 19 = 7.3 fps 40062306a36Sopenharmony_ci * 20 = 7.4 fps 40162306a36Sopenharmony_ci * 21 = 7.4 fps 40262306a36Sopenharmony_ci * 22 = 7.4 fps 40362306a36Sopenharmony_ci * 24 = 6.3 fps 40462306a36Sopenharmony_ci * 30 = 5.4 fps 40562306a36Sopenharmony_ci */ 40662306a36Sopenharmony_ci hdcs->psmp = (sd->bridge == BRIDGE_STV602) ? 20 : 5; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci sd->sensor_priv = hdcs; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci return 0; 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cistatic int hdcs_probe_1020(struct sd *sd) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci struct hdcs *hdcs; 41662306a36Sopenharmony_ci u16 sensor; 41762306a36Sopenharmony_ci int ret; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci ret = stv06xx_read_sensor(sd, HDCS_IDENT, &sensor); 42062306a36Sopenharmony_ci if (ret < 0 || sensor != 0x10) 42162306a36Sopenharmony_ci return -ENODEV; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci pr_info("HDCS-1020 sensor detected\n"); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci sd->gspca_dev.cam.cam_mode = hdcs1020_mode; 42662306a36Sopenharmony_ci sd->gspca_dev.cam.nmodes = ARRAY_SIZE(hdcs1020_mode); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL); 42962306a36Sopenharmony_ci if (!hdcs) 43062306a36Sopenharmony_ci return -ENOMEM; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci /* 43362306a36Sopenharmony_ci * From Andrey's test image: looks like HDCS-1020 upper-left 43462306a36Sopenharmony_ci * visible pixel is at 24,8 (y maybe even smaller?) and lower-right 43562306a36Sopenharmony_ci * visible pixel at 375,299 (x maybe even larger?) 43662306a36Sopenharmony_ci */ 43762306a36Sopenharmony_ci hdcs->array.left = 24; 43862306a36Sopenharmony_ci hdcs->array.top = 4; 43962306a36Sopenharmony_ci hdcs->array.width = HDCS_1020_DEF_WIDTH; 44062306a36Sopenharmony_ci hdcs->array.height = 304; 44162306a36Sopenharmony_ci hdcs->array.border = 4; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci hdcs->psmp = 6; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci hdcs->exp.cto = 3; 44662306a36Sopenharmony_ci hdcs->exp.cpo = 3; 44762306a36Sopenharmony_ci hdcs->exp.rs = 155; 44862306a36Sopenharmony_ci hdcs->exp.er = 96; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci sd->sensor_priv = hdcs; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci return 0; 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic int hdcs_start(struct sd *sd) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_STREAM, "Starting stream\n"); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci return hdcs_set_state(sd, HDCS_STATE_RUN); 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_cistatic int hdcs_stop(struct sd *sd) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_STREAM, "Halting stream\n"); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci return hdcs_set_state(sd, HDCS_STATE_SLEEP); 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cistatic int hdcs_init(struct sd *sd) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci struct hdcs *hdcs = sd->sensor_priv; 47662306a36Sopenharmony_ci int i, err = 0; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci /* Set the STV0602AA in STV0600 emulation mode */ 47962306a36Sopenharmony_ci if (sd->bridge == BRIDGE_STV602) 48062306a36Sopenharmony_ci stv06xx_write_bridge(sd, STV_STV0600_EMULATION, 1); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* Execute the bridge init */ 48362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(stv_bridge_init) && !err; i++) { 48462306a36Sopenharmony_ci err = stv06xx_write_bridge(sd, stv_bridge_init[i][0], 48562306a36Sopenharmony_ci stv_bridge_init[i][1]); 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci if (err < 0) 48862306a36Sopenharmony_ci return err; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci /* sensor soft reset */ 49162306a36Sopenharmony_ci hdcs_reset(sd); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci /* Execute the sensor init */ 49462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(stv_sensor_init) && !err; i++) { 49562306a36Sopenharmony_ci err = stv06xx_write_sensor(sd, stv_sensor_init[i][0], 49662306a36Sopenharmony_ci stv_sensor_init[i][1]); 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci if (err < 0) 49962306a36Sopenharmony_ci return err; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci /* Enable continuous frame capture, bit 2: stop when frame complete */ 50262306a36Sopenharmony_ci err = stv06xx_write_sensor(sd, HDCS_REG_CONFIG(sd), BIT(3)); 50362306a36Sopenharmony_ci if (err < 0) 50462306a36Sopenharmony_ci return err; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci /* Set PGA sample duration 50762306a36Sopenharmony_ci (was 0x7E for the STV602, but caused slow framerate with HDCS-1020) */ 50862306a36Sopenharmony_ci if (IS_1020(sd)) 50962306a36Sopenharmony_ci err = stv06xx_write_sensor(sd, HDCS_TCTRL, 51062306a36Sopenharmony_ci (HDCS_ADC_START_SIG_DUR << 6) | hdcs->psmp); 51162306a36Sopenharmony_ci else 51262306a36Sopenharmony_ci err = stv06xx_write_sensor(sd, HDCS_TCTRL, 51362306a36Sopenharmony_ci (HDCS_ADC_START_SIG_DUR << 5) | hdcs->psmp); 51462306a36Sopenharmony_ci if (err < 0) 51562306a36Sopenharmony_ci return err; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci return hdcs_set_size(sd, hdcs->array.width, hdcs->array.height); 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_cistatic int hdcs_dump(struct sd *sd) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci u16 reg, val; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci pr_info("Dumping sensor registers:\n"); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci for (reg = HDCS_IDENT; reg <= HDCS_ROWEXPH; reg++) { 52762306a36Sopenharmony_ci stv06xx_read_sensor(sd, reg, &val); 52862306a36Sopenharmony_ci pr_info("reg 0x%02x = 0x%02x\n", reg, val); 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci return 0; 53162306a36Sopenharmony_ci} 532