162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * ov534-ov7xxx gspca driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2008 Antonio Ospite <ospite@studenti.unina.it> 662306a36Sopenharmony_ci * Copyright (C) 2008 Jim Paris <jim@jtan.com> 762306a36Sopenharmony_ci * Copyright (C) 2009 Jean-Francois Moine http://moinejf.free.fr 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Based on a prototype written by Mark Ferrell <majortrips@gmail.com> 1062306a36Sopenharmony_ci * USB protocol reverse engineered by Jim Paris <jim@jtan.com> 1162306a36Sopenharmony_ci * https://jim.sh/svn/jim/devl/playstation/ps3/eye/test/ 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * PS3 Eye camera enhanced by Richard Kaswy http://kaswy.free.fr 1462306a36Sopenharmony_ci * PS3 Eye camera - brightness, contrast, awb, agc, aec controls 1562306a36Sopenharmony_ci * added by Max Thrun <bear24rw@gmail.com> 1662306a36Sopenharmony_ci * PS3 Eye camera - FPS range extended by Joseph Howse 1762306a36Sopenharmony_ci * <josephhowse@nummist.com> https://nummist.com 1862306a36Sopenharmony_ci */ 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define MODULE_NAME "ov534" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include "gspca.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include <linux/fixp-arith.h> 2762306a36Sopenharmony_ci#include <media/v4l2-ctrls.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define OV534_REG_ADDRESS 0xf1 /* sensor address */ 3062306a36Sopenharmony_ci#define OV534_REG_SUBADDR 0xf2 3162306a36Sopenharmony_ci#define OV534_REG_WRITE 0xf3 3262306a36Sopenharmony_ci#define OV534_REG_READ 0xf4 3362306a36Sopenharmony_ci#define OV534_REG_OPERATION 0xf5 3462306a36Sopenharmony_ci#define OV534_REG_STATUS 0xf6 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define OV534_OP_WRITE_3 0x37 3762306a36Sopenharmony_ci#define OV534_OP_WRITE_2 0x33 3862306a36Sopenharmony_ci#define OV534_OP_READ_2 0xf9 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define CTRL_TIMEOUT 500 4162306a36Sopenharmony_ci#define DEFAULT_FRAME_RATE 30 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ciMODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>"); 4462306a36Sopenharmony_ciMODULE_DESCRIPTION("GSPCA/OV534 USB Camera Driver"); 4562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* specific webcam descriptor */ 4862306a36Sopenharmony_cistruct sd { 4962306a36Sopenharmony_ci struct gspca_dev gspca_dev; /* !! must be the first item */ 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci struct v4l2_ctrl_handler ctrl_handler; 5262306a36Sopenharmony_ci struct v4l2_ctrl *hue; 5362306a36Sopenharmony_ci struct v4l2_ctrl *saturation; 5462306a36Sopenharmony_ci struct v4l2_ctrl *brightness; 5562306a36Sopenharmony_ci struct v4l2_ctrl *contrast; 5662306a36Sopenharmony_ci struct { /* gain control cluster */ 5762306a36Sopenharmony_ci struct v4l2_ctrl *autogain; 5862306a36Sopenharmony_ci struct v4l2_ctrl *gain; 5962306a36Sopenharmony_ci }; 6062306a36Sopenharmony_ci struct v4l2_ctrl *autowhitebalance; 6162306a36Sopenharmony_ci struct { /* exposure control cluster */ 6262306a36Sopenharmony_ci struct v4l2_ctrl *autoexposure; 6362306a36Sopenharmony_ci struct v4l2_ctrl *exposure; 6462306a36Sopenharmony_ci }; 6562306a36Sopenharmony_ci struct v4l2_ctrl *sharpness; 6662306a36Sopenharmony_ci struct v4l2_ctrl *hflip; 6762306a36Sopenharmony_ci struct v4l2_ctrl *vflip; 6862306a36Sopenharmony_ci struct v4l2_ctrl *plfreq; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci __u32 last_pts; 7162306a36Sopenharmony_ci u16 last_fid; 7262306a36Sopenharmony_ci u8 frame_rate; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci u8 sensor; 7562306a36Sopenharmony_ci}; 7662306a36Sopenharmony_cienum sensors { 7762306a36Sopenharmony_ci SENSOR_OV767x, 7862306a36Sopenharmony_ci SENSOR_OV772x, 7962306a36Sopenharmony_ci NSENSORS 8062306a36Sopenharmony_ci}; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic int sd_start(struct gspca_dev *gspca_dev); 8362306a36Sopenharmony_cistatic void sd_stopN(struct gspca_dev *gspca_dev); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic const struct v4l2_pix_format ov772x_mode[] = { 8762306a36Sopenharmony_ci {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, 8862306a36Sopenharmony_ci .bytesperline = 320 * 2, 8962306a36Sopenharmony_ci .sizeimage = 320 * 240 * 2, 9062306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 9162306a36Sopenharmony_ci .priv = 1}, 9262306a36Sopenharmony_ci {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, 9362306a36Sopenharmony_ci .bytesperline = 640 * 2, 9462306a36Sopenharmony_ci .sizeimage = 640 * 480 * 2, 9562306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 9662306a36Sopenharmony_ci .priv = 0}, 9762306a36Sopenharmony_ci {320, 240, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, 9862306a36Sopenharmony_ci .bytesperline = 320, 9962306a36Sopenharmony_ci .sizeimage = 320 * 240, 10062306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 10162306a36Sopenharmony_ci .priv = 1}, 10262306a36Sopenharmony_ci {640, 480, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, 10362306a36Sopenharmony_ci .bytesperline = 640, 10462306a36Sopenharmony_ci .sizeimage = 640 * 480, 10562306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 10662306a36Sopenharmony_ci .priv = 0}, 10762306a36Sopenharmony_ci}; 10862306a36Sopenharmony_cistatic const struct v4l2_pix_format ov767x_mode[] = { 10962306a36Sopenharmony_ci {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, 11062306a36Sopenharmony_ci .bytesperline = 320, 11162306a36Sopenharmony_ci .sizeimage = 320 * 240 * 3 / 8 + 590, 11262306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_JPEG}, 11362306a36Sopenharmony_ci {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, 11462306a36Sopenharmony_ci .bytesperline = 640, 11562306a36Sopenharmony_ci .sizeimage = 640 * 480 * 3 / 8 + 590, 11662306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_JPEG}, 11762306a36Sopenharmony_ci}; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic const u8 qvga_rates[] = {187, 150, 137, 125, 100, 75, 60, 50, 37, 30}; 12062306a36Sopenharmony_cistatic const u8 vga_rates[] = {60, 50, 40, 30, 15}; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic const struct framerates ov772x_framerates[] = { 12362306a36Sopenharmony_ci { /* 320x240 */ 12462306a36Sopenharmony_ci .rates = qvga_rates, 12562306a36Sopenharmony_ci .nrates = ARRAY_SIZE(qvga_rates), 12662306a36Sopenharmony_ci }, 12762306a36Sopenharmony_ci { /* 640x480 */ 12862306a36Sopenharmony_ci .rates = vga_rates, 12962306a36Sopenharmony_ci .nrates = ARRAY_SIZE(vga_rates), 13062306a36Sopenharmony_ci }, 13162306a36Sopenharmony_ci { /* 320x240 SGBRG8 */ 13262306a36Sopenharmony_ci .rates = qvga_rates, 13362306a36Sopenharmony_ci .nrates = ARRAY_SIZE(qvga_rates), 13462306a36Sopenharmony_ci }, 13562306a36Sopenharmony_ci { /* 640x480 SGBRG8 */ 13662306a36Sopenharmony_ci .rates = vga_rates, 13762306a36Sopenharmony_ci .nrates = ARRAY_SIZE(vga_rates), 13862306a36Sopenharmony_ci }, 13962306a36Sopenharmony_ci}; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistruct reg_array { 14262306a36Sopenharmony_ci const u8 (*val)[2]; 14362306a36Sopenharmony_ci int len; 14462306a36Sopenharmony_ci}; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic const u8 bridge_init_767x[][2] = { 14762306a36Sopenharmony_ci/* comments from the ms-win file apollo7670.set */ 14862306a36Sopenharmony_ci/* str1 */ 14962306a36Sopenharmony_ci {0xf1, 0x42}, 15062306a36Sopenharmony_ci {0x88, 0xf8}, 15162306a36Sopenharmony_ci {0x89, 0xff}, 15262306a36Sopenharmony_ci {0x76, 0x03}, 15362306a36Sopenharmony_ci {0x92, 0x03}, 15462306a36Sopenharmony_ci {0x95, 0x10}, 15562306a36Sopenharmony_ci {0xe2, 0x00}, 15662306a36Sopenharmony_ci {0xe7, 0x3e}, 15762306a36Sopenharmony_ci {0x8d, 0x1c}, 15862306a36Sopenharmony_ci {0x8e, 0x00}, 15962306a36Sopenharmony_ci {0x8f, 0x00}, 16062306a36Sopenharmony_ci {0x1f, 0x00}, 16162306a36Sopenharmony_ci {0xc3, 0xf9}, 16262306a36Sopenharmony_ci {0x89, 0xff}, 16362306a36Sopenharmony_ci {0x88, 0xf8}, 16462306a36Sopenharmony_ci {0x76, 0x03}, 16562306a36Sopenharmony_ci {0x92, 0x01}, 16662306a36Sopenharmony_ci {0x93, 0x18}, 16762306a36Sopenharmony_ci {0x1c, 0x00}, 16862306a36Sopenharmony_ci {0x1d, 0x48}, 16962306a36Sopenharmony_ci {0x1d, 0x00}, 17062306a36Sopenharmony_ci {0x1d, 0xff}, 17162306a36Sopenharmony_ci {0x1d, 0x02}, 17262306a36Sopenharmony_ci {0x1d, 0x58}, 17362306a36Sopenharmony_ci {0x1d, 0x00}, 17462306a36Sopenharmony_ci {0x1c, 0x0a}, 17562306a36Sopenharmony_ci {0x1d, 0x0a}, 17662306a36Sopenharmony_ci {0x1d, 0x0e}, 17762306a36Sopenharmony_ci {0xc0, 0x50}, /* HSize 640 */ 17862306a36Sopenharmony_ci {0xc1, 0x3c}, /* VSize 480 */ 17962306a36Sopenharmony_ci {0x34, 0x05}, /* enable Audio Suspend mode */ 18062306a36Sopenharmony_ci {0xc2, 0x0c}, /* Input YUV */ 18162306a36Sopenharmony_ci {0xc3, 0xf9}, /* enable PRE */ 18262306a36Sopenharmony_ci {0x34, 0x05}, /* enable Audio Suspend mode */ 18362306a36Sopenharmony_ci {0xe7, 0x2e}, /* this solves failure of "SuspendResumeTest" */ 18462306a36Sopenharmony_ci {0x31, 0xf9}, /* enable 1.8V Suspend */ 18562306a36Sopenharmony_ci {0x35, 0x02}, /* turn on JPEG */ 18662306a36Sopenharmony_ci {0xd9, 0x10}, 18762306a36Sopenharmony_ci {0x25, 0x42}, /* GPIO[8]:Input */ 18862306a36Sopenharmony_ci {0x94, 0x11}, /* If the default setting is loaded when 18962306a36Sopenharmony_ci * system boots up, this flag is closed here */ 19062306a36Sopenharmony_ci}; 19162306a36Sopenharmony_cistatic const u8 sensor_init_767x[][2] = { 19262306a36Sopenharmony_ci {0x12, 0x80}, 19362306a36Sopenharmony_ci {0x11, 0x03}, 19462306a36Sopenharmony_ci {0x3a, 0x04}, 19562306a36Sopenharmony_ci {0x12, 0x00}, 19662306a36Sopenharmony_ci {0x17, 0x13}, 19762306a36Sopenharmony_ci {0x18, 0x01}, 19862306a36Sopenharmony_ci {0x32, 0xb6}, 19962306a36Sopenharmony_ci {0x19, 0x02}, 20062306a36Sopenharmony_ci {0x1a, 0x7a}, 20162306a36Sopenharmony_ci {0x03, 0x0a}, 20262306a36Sopenharmony_ci {0x0c, 0x00}, 20362306a36Sopenharmony_ci {0x3e, 0x00}, 20462306a36Sopenharmony_ci {0x70, 0x3a}, 20562306a36Sopenharmony_ci {0x71, 0x35}, 20662306a36Sopenharmony_ci {0x72, 0x11}, 20762306a36Sopenharmony_ci {0x73, 0xf0}, 20862306a36Sopenharmony_ci {0xa2, 0x02}, 20962306a36Sopenharmony_ci {0x7a, 0x2a}, /* set Gamma=1.6 below */ 21062306a36Sopenharmony_ci {0x7b, 0x12}, 21162306a36Sopenharmony_ci {0x7c, 0x1d}, 21262306a36Sopenharmony_ci {0x7d, 0x2d}, 21362306a36Sopenharmony_ci {0x7e, 0x45}, 21462306a36Sopenharmony_ci {0x7f, 0x50}, 21562306a36Sopenharmony_ci {0x80, 0x59}, 21662306a36Sopenharmony_ci {0x81, 0x62}, 21762306a36Sopenharmony_ci {0x82, 0x6b}, 21862306a36Sopenharmony_ci {0x83, 0x73}, 21962306a36Sopenharmony_ci {0x84, 0x7b}, 22062306a36Sopenharmony_ci {0x85, 0x8a}, 22162306a36Sopenharmony_ci {0x86, 0x98}, 22262306a36Sopenharmony_ci {0x87, 0xb2}, 22362306a36Sopenharmony_ci {0x88, 0xca}, 22462306a36Sopenharmony_ci {0x89, 0xe0}, 22562306a36Sopenharmony_ci {0x13, 0xe0}, 22662306a36Sopenharmony_ci {0x00, 0x00}, 22762306a36Sopenharmony_ci {0x10, 0x00}, 22862306a36Sopenharmony_ci {0x0d, 0x40}, 22962306a36Sopenharmony_ci {0x14, 0x38}, /* gain max 16x */ 23062306a36Sopenharmony_ci {0xa5, 0x05}, 23162306a36Sopenharmony_ci {0xab, 0x07}, 23262306a36Sopenharmony_ci {0x24, 0x95}, 23362306a36Sopenharmony_ci {0x25, 0x33}, 23462306a36Sopenharmony_ci {0x26, 0xe3}, 23562306a36Sopenharmony_ci {0x9f, 0x78}, 23662306a36Sopenharmony_ci {0xa0, 0x68}, 23762306a36Sopenharmony_ci {0xa1, 0x03}, 23862306a36Sopenharmony_ci {0xa6, 0xd8}, 23962306a36Sopenharmony_ci {0xa7, 0xd8}, 24062306a36Sopenharmony_ci {0xa8, 0xf0}, 24162306a36Sopenharmony_ci {0xa9, 0x90}, 24262306a36Sopenharmony_ci {0xaa, 0x94}, 24362306a36Sopenharmony_ci {0x13, 0xe5}, 24462306a36Sopenharmony_ci {0x0e, 0x61}, 24562306a36Sopenharmony_ci {0x0f, 0x4b}, 24662306a36Sopenharmony_ci {0x16, 0x02}, 24762306a36Sopenharmony_ci {0x21, 0x02}, 24862306a36Sopenharmony_ci {0x22, 0x91}, 24962306a36Sopenharmony_ci {0x29, 0x07}, 25062306a36Sopenharmony_ci {0x33, 0x0b}, 25162306a36Sopenharmony_ci {0x35, 0x0b}, 25262306a36Sopenharmony_ci {0x37, 0x1d}, 25362306a36Sopenharmony_ci {0x38, 0x71}, 25462306a36Sopenharmony_ci {0x39, 0x2a}, 25562306a36Sopenharmony_ci {0x3c, 0x78}, 25662306a36Sopenharmony_ci {0x4d, 0x40}, 25762306a36Sopenharmony_ci {0x4e, 0x20}, 25862306a36Sopenharmony_ci {0x69, 0x00}, 25962306a36Sopenharmony_ci {0x6b, 0x4a}, 26062306a36Sopenharmony_ci {0x74, 0x10}, 26162306a36Sopenharmony_ci {0x8d, 0x4f}, 26262306a36Sopenharmony_ci {0x8e, 0x00}, 26362306a36Sopenharmony_ci {0x8f, 0x00}, 26462306a36Sopenharmony_ci {0x90, 0x00}, 26562306a36Sopenharmony_ci {0x91, 0x00}, 26662306a36Sopenharmony_ci {0x96, 0x00}, 26762306a36Sopenharmony_ci {0x9a, 0x80}, 26862306a36Sopenharmony_ci {0xb0, 0x84}, 26962306a36Sopenharmony_ci {0xb1, 0x0c}, 27062306a36Sopenharmony_ci {0xb2, 0x0e}, 27162306a36Sopenharmony_ci {0xb3, 0x82}, 27262306a36Sopenharmony_ci {0xb8, 0x0a}, 27362306a36Sopenharmony_ci {0x43, 0x0a}, 27462306a36Sopenharmony_ci {0x44, 0xf0}, 27562306a36Sopenharmony_ci {0x45, 0x34}, 27662306a36Sopenharmony_ci {0x46, 0x58}, 27762306a36Sopenharmony_ci {0x47, 0x28}, 27862306a36Sopenharmony_ci {0x48, 0x3a}, 27962306a36Sopenharmony_ci {0x59, 0x88}, 28062306a36Sopenharmony_ci {0x5a, 0x88}, 28162306a36Sopenharmony_ci {0x5b, 0x44}, 28262306a36Sopenharmony_ci {0x5c, 0x67}, 28362306a36Sopenharmony_ci {0x5d, 0x49}, 28462306a36Sopenharmony_ci {0x5e, 0x0e}, 28562306a36Sopenharmony_ci {0x6c, 0x0a}, 28662306a36Sopenharmony_ci {0x6d, 0x55}, 28762306a36Sopenharmony_ci {0x6e, 0x11}, 28862306a36Sopenharmony_ci {0x6f, 0x9f}, 28962306a36Sopenharmony_ci {0x6a, 0x40}, 29062306a36Sopenharmony_ci {0x01, 0x40}, 29162306a36Sopenharmony_ci {0x02, 0x40}, 29262306a36Sopenharmony_ci {0x13, 0xe7}, 29362306a36Sopenharmony_ci {0x4f, 0x80}, 29462306a36Sopenharmony_ci {0x50, 0x80}, 29562306a36Sopenharmony_ci {0x51, 0x00}, 29662306a36Sopenharmony_ci {0x52, 0x22}, 29762306a36Sopenharmony_ci {0x53, 0x5e}, 29862306a36Sopenharmony_ci {0x54, 0x80}, 29962306a36Sopenharmony_ci {0x58, 0x9e}, 30062306a36Sopenharmony_ci {0x41, 0x08}, 30162306a36Sopenharmony_ci {0x3f, 0x00}, 30262306a36Sopenharmony_ci {0x75, 0x04}, 30362306a36Sopenharmony_ci {0x76, 0xe1}, 30462306a36Sopenharmony_ci {0x4c, 0x00}, 30562306a36Sopenharmony_ci {0x77, 0x01}, 30662306a36Sopenharmony_ci {0x3d, 0xc2}, 30762306a36Sopenharmony_ci {0x4b, 0x09}, 30862306a36Sopenharmony_ci {0xc9, 0x60}, 30962306a36Sopenharmony_ci {0x41, 0x38}, /* jfm: auto sharpness + auto de-noise */ 31062306a36Sopenharmony_ci {0x56, 0x40}, 31162306a36Sopenharmony_ci {0x34, 0x11}, 31262306a36Sopenharmony_ci {0x3b, 0xc2}, 31362306a36Sopenharmony_ci {0xa4, 0x8a}, /* Night mode trigger point */ 31462306a36Sopenharmony_ci {0x96, 0x00}, 31562306a36Sopenharmony_ci {0x97, 0x30}, 31662306a36Sopenharmony_ci {0x98, 0x20}, 31762306a36Sopenharmony_ci {0x99, 0x20}, 31862306a36Sopenharmony_ci {0x9a, 0x84}, 31962306a36Sopenharmony_ci {0x9b, 0x29}, 32062306a36Sopenharmony_ci {0x9c, 0x03}, 32162306a36Sopenharmony_ci {0x9d, 0x4c}, 32262306a36Sopenharmony_ci {0x9e, 0x3f}, 32362306a36Sopenharmony_ci {0x78, 0x04}, 32462306a36Sopenharmony_ci {0x79, 0x01}, 32562306a36Sopenharmony_ci {0xc8, 0xf0}, 32662306a36Sopenharmony_ci {0x79, 0x0f}, 32762306a36Sopenharmony_ci {0xc8, 0x00}, 32862306a36Sopenharmony_ci {0x79, 0x10}, 32962306a36Sopenharmony_ci {0xc8, 0x7e}, 33062306a36Sopenharmony_ci {0x79, 0x0a}, 33162306a36Sopenharmony_ci {0xc8, 0x80}, 33262306a36Sopenharmony_ci {0x79, 0x0b}, 33362306a36Sopenharmony_ci {0xc8, 0x01}, 33462306a36Sopenharmony_ci {0x79, 0x0c}, 33562306a36Sopenharmony_ci {0xc8, 0x0f}, 33662306a36Sopenharmony_ci {0x79, 0x0d}, 33762306a36Sopenharmony_ci {0xc8, 0x20}, 33862306a36Sopenharmony_ci {0x79, 0x09}, 33962306a36Sopenharmony_ci {0xc8, 0x80}, 34062306a36Sopenharmony_ci {0x79, 0x02}, 34162306a36Sopenharmony_ci {0xc8, 0xc0}, 34262306a36Sopenharmony_ci {0x79, 0x03}, 34362306a36Sopenharmony_ci {0xc8, 0x20}, 34462306a36Sopenharmony_ci {0x79, 0x26}, 34562306a36Sopenharmony_ci}; 34662306a36Sopenharmony_cistatic const u8 bridge_start_vga_767x[][2] = { 34762306a36Sopenharmony_ci/* str59 JPG */ 34862306a36Sopenharmony_ci {0x94, 0xaa}, 34962306a36Sopenharmony_ci {0xf1, 0x42}, 35062306a36Sopenharmony_ci {0xe5, 0x04}, 35162306a36Sopenharmony_ci {0xc0, 0x50}, 35262306a36Sopenharmony_ci {0xc1, 0x3c}, 35362306a36Sopenharmony_ci {0xc2, 0x0c}, 35462306a36Sopenharmony_ci {0x35, 0x02}, /* turn on JPEG */ 35562306a36Sopenharmony_ci {0xd9, 0x10}, 35662306a36Sopenharmony_ci {0xda, 0x00}, /* for higher clock rate(30fps) */ 35762306a36Sopenharmony_ci {0x34, 0x05}, /* enable Audio Suspend mode */ 35862306a36Sopenharmony_ci {0xc3, 0xf9}, /* enable PRE */ 35962306a36Sopenharmony_ci {0x8c, 0x00}, /* CIF VSize LSB[2:0] */ 36062306a36Sopenharmony_ci {0x8d, 0x1c}, /* output YUV */ 36162306a36Sopenharmony_ci/* {0x34, 0x05}, * enable Audio Suspend mode (?) */ 36262306a36Sopenharmony_ci {0x50, 0x00}, /* H/V divider=0 */ 36362306a36Sopenharmony_ci {0x51, 0xa0}, /* input H=640/4 */ 36462306a36Sopenharmony_ci {0x52, 0x3c}, /* input V=480/4 */ 36562306a36Sopenharmony_ci {0x53, 0x00}, /* offset X=0 */ 36662306a36Sopenharmony_ci {0x54, 0x00}, /* offset Y=0 */ 36762306a36Sopenharmony_ci {0x55, 0x00}, /* H/V size[8]=0 */ 36862306a36Sopenharmony_ci {0x57, 0x00}, /* H-size[9]=0 */ 36962306a36Sopenharmony_ci {0x5c, 0x00}, /* output size[9:8]=0 */ 37062306a36Sopenharmony_ci {0x5a, 0xa0}, /* output H=640/4 */ 37162306a36Sopenharmony_ci {0x5b, 0x78}, /* output V=480/4 */ 37262306a36Sopenharmony_ci {0x1c, 0x0a}, 37362306a36Sopenharmony_ci {0x1d, 0x0a}, 37462306a36Sopenharmony_ci {0x94, 0x11}, 37562306a36Sopenharmony_ci}; 37662306a36Sopenharmony_cistatic const u8 sensor_start_vga_767x[][2] = { 37762306a36Sopenharmony_ci {0x11, 0x01}, 37862306a36Sopenharmony_ci {0x1e, 0x04}, 37962306a36Sopenharmony_ci {0x19, 0x02}, 38062306a36Sopenharmony_ci {0x1a, 0x7a}, 38162306a36Sopenharmony_ci}; 38262306a36Sopenharmony_cistatic const u8 bridge_start_qvga_767x[][2] = { 38362306a36Sopenharmony_ci/* str86 JPG */ 38462306a36Sopenharmony_ci {0x94, 0xaa}, 38562306a36Sopenharmony_ci {0xf1, 0x42}, 38662306a36Sopenharmony_ci {0xe5, 0x04}, 38762306a36Sopenharmony_ci {0xc0, 0x80}, 38862306a36Sopenharmony_ci {0xc1, 0x60}, 38962306a36Sopenharmony_ci {0xc2, 0x0c}, 39062306a36Sopenharmony_ci {0x35, 0x02}, /* turn on JPEG */ 39162306a36Sopenharmony_ci {0xd9, 0x10}, 39262306a36Sopenharmony_ci {0xc0, 0x50}, /* CIF HSize 640 */ 39362306a36Sopenharmony_ci {0xc1, 0x3c}, /* CIF VSize 480 */ 39462306a36Sopenharmony_ci {0x8c, 0x00}, /* CIF VSize LSB[2:0] */ 39562306a36Sopenharmony_ci {0x8d, 0x1c}, /* output YUV */ 39662306a36Sopenharmony_ci {0x34, 0x05}, /* enable Audio Suspend mode */ 39762306a36Sopenharmony_ci {0xc2, 0x4c}, /* output YUV and Enable DCW */ 39862306a36Sopenharmony_ci {0xc3, 0xf9}, /* enable PRE */ 39962306a36Sopenharmony_ci {0x1c, 0x00}, /* indirect addressing */ 40062306a36Sopenharmony_ci {0x1d, 0x48}, /* output YUV422 */ 40162306a36Sopenharmony_ci {0x50, 0x89}, /* H/V divider=/2; plus DCW AVG */ 40262306a36Sopenharmony_ci {0x51, 0xa0}, /* DCW input H=640/4 */ 40362306a36Sopenharmony_ci {0x52, 0x78}, /* DCW input V=480/4 */ 40462306a36Sopenharmony_ci {0x53, 0x00}, /* offset X=0 */ 40562306a36Sopenharmony_ci {0x54, 0x00}, /* offset Y=0 */ 40662306a36Sopenharmony_ci {0x55, 0x00}, /* H/V size[8]=0 */ 40762306a36Sopenharmony_ci {0x57, 0x00}, /* H-size[9]=0 */ 40862306a36Sopenharmony_ci {0x5c, 0x00}, /* DCW output size[9:8]=0 */ 40962306a36Sopenharmony_ci {0x5a, 0x50}, /* DCW output H=320/4 */ 41062306a36Sopenharmony_ci {0x5b, 0x3c}, /* DCW output V=240/4 */ 41162306a36Sopenharmony_ci {0x1c, 0x0a}, 41262306a36Sopenharmony_ci {0x1d, 0x0a}, 41362306a36Sopenharmony_ci {0x94, 0x11}, 41462306a36Sopenharmony_ci}; 41562306a36Sopenharmony_cistatic const u8 sensor_start_qvga_767x[][2] = { 41662306a36Sopenharmony_ci {0x11, 0x01}, 41762306a36Sopenharmony_ci {0x1e, 0x04}, 41862306a36Sopenharmony_ci {0x19, 0x02}, 41962306a36Sopenharmony_ci {0x1a, 0x7a}, 42062306a36Sopenharmony_ci}; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic const u8 bridge_init_772x[][2] = { 42362306a36Sopenharmony_ci { 0x88, 0xf8 }, 42462306a36Sopenharmony_ci { 0x89, 0xff }, 42562306a36Sopenharmony_ci { 0x76, 0x03 }, 42662306a36Sopenharmony_ci { 0x92, 0x01 }, 42762306a36Sopenharmony_ci { 0x93, 0x18 }, 42862306a36Sopenharmony_ci { 0x94, 0x10 }, 42962306a36Sopenharmony_ci { 0x95, 0x10 }, 43062306a36Sopenharmony_ci { 0xe2, 0x00 }, 43162306a36Sopenharmony_ci { 0xe7, 0x3e }, 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci { 0x96, 0x00 }, 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci { 0x97, 0x20 }, 43662306a36Sopenharmony_ci { 0x97, 0x20 }, 43762306a36Sopenharmony_ci { 0x97, 0x20 }, 43862306a36Sopenharmony_ci { 0x97, 0x0a }, 43962306a36Sopenharmony_ci { 0x97, 0x3f }, 44062306a36Sopenharmony_ci { 0x97, 0x4a }, 44162306a36Sopenharmony_ci { 0x97, 0x20 }, 44262306a36Sopenharmony_ci { 0x97, 0x15 }, 44362306a36Sopenharmony_ci { 0x97, 0x0b }, 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci { 0x8e, 0x40 }, 44662306a36Sopenharmony_ci { 0x1f, 0x81 }, 44762306a36Sopenharmony_ci { 0x34, 0x05 }, 44862306a36Sopenharmony_ci { 0xe3, 0x04 }, 44962306a36Sopenharmony_ci { 0x89, 0x00 }, 45062306a36Sopenharmony_ci { 0x76, 0x00 }, 45162306a36Sopenharmony_ci { 0xe7, 0x2e }, 45262306a36Sopenharmony_ci { 0x31, 0xf9 }, 45362306a36Sopenharmony_ci { 0x25, 0x42 }, 45462306a36Sopenharmony_ci { 0x21, 0xf0 }, 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci { 0x1c, 0x0a }, 45762306a36Sopenharmony_ci { 0x1d, 0x08 }, /* turn on UVC header */ 45862306a36Sopenharmony_ci { 0x1d, 0x0e }, /* .. */ 45962306a36Sopenharmony_ci}; 46062306a36Sopenharmony_cistatic const u8 sensor_init_772x[][2] = { 46162306a36Sopenharmony_ci { 0x12, 0x80 }, 46262306a36Sopenharmony_ci { 0x11, 0x01 }, 46362306a36Sopenharmony_ci/*fixme: better have a delay?*/ 46462306a36Sopenharmony_ci { 0x11, 0x01 }, 46562306a36Sopenharmony_ci { 0x11, 0x01 }, 46662306a36Sopenharmony_ci { 0x11, 0x01 }, 46762306a36Sopenharmony_ci { 0x11, 0x01 }, 46862306a36Sopenharmony_ci { 0x11, 0x01 }, 46962306a36Sopenharmony_ci { 0x11, 0x01 }, 47062306a36Sopenharmony_ci { 0x11, 0x01 }, 47162306a36Sopenharmony_ci { 0x11, 0x01 }, 47262306a36Sopenharmony_ci { 0x11, 0x01 }, 47362306a36Sopenharmony_ci { 0x11, 0x01 }, 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci { 0x3d, 0x03 }, 47662306a36Sopenharmony_ci { 0x17, 0x26 }, 47762306a36Sopenharmony_ci { 0x18, 0xa0 }, 47862306a36Sopenharmony_ci { 0x19, 0x07 }, 47962306a36Sopenharmony_ci { 0x1a, 0xf0 }, 48062306a36Sopenharmony_ci { 0x32, 0x00 }, 48162306a36Sopenharmony_ci { 0x29, 0xa0 }, 48262306a36Sopenharmony_ci { 0x2c, 0xf0 }, 48362306a36Sopenharmony_ci { 0x65, 0x20 }, 48462306a36Sopenharmony_ci { 0x11, 0x01 }, 48562306a36Sopenharmony_ci { 0x42, 0x7f }, 48662306a36Sopenharmony_ci { 0x63, 0xaa }, /* AWB - was e0 */ 48762306a36Sopenharmony_ci { 0x64, 0xff }, 48862306a36Sopenharmony_ci { 0x66, 0x00 }, 48962306a36Sopenharmony_ci { 0x13, 0xf0 }, /* com8 */ 49062306a36Sopenharmony_ci { 0x0d, 0x41 }, 49162306a36Sopenharmony_ci { 0x0f, 0xc5 }, 49262306a36Sopenharmony_ci { 0x14, 0x11 }, 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci { 0x22, 0x7f }, 49562306a36Sopenharmony_ci { 0x23, 0x03 }, 49662306a36Sopenharmony_ci { 0x24, 0x40 }, 49762306a36Sopenharmony_ci { 0x25, 0x30 }, 49862306a36Sopenharmony_ci { 0x26, 0xa1 }, 49962306a36Sopenharmony_ci { 0x2a, 0x00 }, 50062306a36Sopenharmony_ci { 0x2b, 0x00 }, 50162306a36Sopenharmony_ci { 0x6b, 0xaa }, 50262306a36Sopenharmony_ci { 0x13, 0xff }, /* AWB */ 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci { 0x90, 0x05 }, 50562306a36Sopenharmony_ci { 0x91, 0x01 }, 50662306a36Sopenharmony_ci { 0x92, 0x03 }, 50762306a36Sopenharmony_ci { 0x93, 0x00 }, 50862306a36Sopenharmony_ci { 0x94, 0x60 }, 50962306a36Sopenharmony_ci { 0x95, 0x3c }, 51062306a36Sopenharmony_ci { 0x96, 0x24 }, 51162306a36Sopenharmony_ci { 0x97, 0x1e }, 51262306a36Sopenharmony_ci { 0x98, 0x62 }, 51362306a36Sopenharmony_ci { 0x99, 0x80 }, 51462306a36Sopenharmony_ci { 0x9a, 0x1e }, 51562306a36Sopenharmony_ci { 0x9b, 0x08 }, 51662306a36Sopenharmony_ci { 0x9c, 0x20 }, 51762306a36Sopenharmony_ci { 0x9e, 0x81 }, 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci { 0xa6, 0x07 }, 52062306a36Sopenharmony_ci { 0x7e, 0x0c }, 52162306a36Sopenharmony_ci { 0x7f, 0x16 }, 52262306a36Sopenharmony_ci { 0x80, 0x2a }, 52362306a36Sopenharmony_ci { 0x81, 0x4e }, 52462306a36Sopenharmony_ci { 0x82, 0x61 }, 52562306a36Sopenharmony_ci { 0x83, 0x6f }, 52662306a36Sopenharmony_ci { 0x84, 0x7b }, 52762306a36Sopenharmony_ci { 0x85, 0x86 }, 52862306a36Sopenharmony_ci { 0x86, 0x8e }, 52962306a36Sopenharmony_ci { 0x87, 0x97 }, 53062306a36Sopenharmony_ci { 0x88, 0xa4 }, 53162306a36Sopenharmony_ci { 0x89, 0xaf }, 53262306a36Sopenharmony_ci { 0x8a, 0xc5 }, 53362306a36Sopenharmony_ci { 0x8b, 0xd7 }, 53462306a36Sopenharmony_ci { 0x8c, 0xe8 }, 53562306a36Sopenharmony_ci { 0x8d, 0x20 }, 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci { 0x2b, 0x00 }, 53862306a36Sopenharmony_ci { 0x22, 0x7f }, 53962306a36Sopenharmony_ci { 0x23, 0x03 }, 54062306a36Sopenharmony_ci { 0x11, 0x01 }, 54162306a36Sopenharmony_ci { 0x64, 0xff }, 54262306a36Sopenharmony_ci { 0x0d, 0x41 }, 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci { 0x14, 0x41 }, 54562306a36Sopenharmony_ci { 0x0e, 0xcd }, 54662306a36Sopenharmony_ci { 0xac, 0xbf }, 54762306a36Sopenharmony_ci { 0x8e, 0x00 }, /* De-noise threshold */ 54862306a36Sopenharmony_ci}; 54962306a36Sopenharmony_cistatic const u8 bridge_start_vga_yuyv_772x[][2] = { 55062306a36Sopenharmony_ci {0x88, 0x00}, 55162306a36Sopenharmony_ci {0x1c, 0x00}, 55262306a36Sopenharmony_ci {0x1d, 0x40}, 55362306a36Sopenharmony_ci {0x1d, 0x02}, 55462306a36Sopenharmony_ci {0x1d, 0x00}, 55562306a36Sopenharmony_ci {0x1d, 0x02}, 55662306a36Sopenharmony_ci {0x1d, 0x58}, 55762306a36Sopenharmony_ci {0x1d, 0x00}, 55862306a36Sopenharmony_ci {0x8d, 0x1c}, 55962306a36Sopenharmony_ci {0x8e, 0x80}, 56062306a36Sopenharmony_ci {0xc0, 0x50}, 56162306a36Sopenharmony_ci {0xc1, 0x3c}, 56262306a36Sopenharmony_ci {0xc2, 0x0c}, 56362306a36Sopenharmony_ci {0xc3, 0x69}, 56462306a36Sopenharmony_ci}; 56562306a36Sopenharmony_cistatic const u8 sensor_start_vga_yuyv_772x[][2] = { 56662306a36Sopenharmony_ci {0x12, 0x00}, 56762306a36Sopenharmony_ci {0x17, 0x26}, 56862306a36Sopenharmony_ci {0x18, 0xa0}, 56962306a36Sopenharmony_ci {0x19, 0x07}, 57062306a36Sopenharmony_ci {0x1a, 0xf0}, 57162306a36Sopenharmony_ci {0x29, 0xa0}, 57262306a36Sopenharmony_ci {0x2c, 0xf0}, 57362306a36Sopenharmony_ci {0x65, 0x20}, 57462306a36Sopenharmony_ci {0x67, 0x00}, 57562306a36Sopenharmony_ci}; 57662306a36Sopenharmony_cistatic const u8 bridge_start_qvga_yuyv_772x[][2] = { 57762306a36Sopenharmony_ci {0x88, 0x00}, 57862306a36Sopenharmony_ci {0x1c, 0x00}, 57962306a36Sopenharmony_ci {0x1d, 0x40}, 58062306a36Sopenharmony_ci {0x1d, 0x02}, 58162306a36Sopenharmony_ci {0x1d, 0x00}, 58262306a36Sopenharmony_ci {0x1d, 0x01}, 58362306a36Sopenharmony_ci {0x1d, 0x4b}, 58462306a36Sopenharmony_ci {0x1d, 0x00}, 58562306a36Sopenharmony_ci {0x8d, 0x1c}, 58662306a36Sopenharmony_ci {0x8e, 0x80}, 58762306a36Sopenharmony_ci {0xc0, 0x28}, 58862306a36Sopenharmony_ci {0xc1, 0x1e}, 58962306a36Sopenharmony_ci {0xc2, 0x0c}, 59062306a36Sopenharmony_ci {0xc3, 0x69}, 59162306a36Sopenharmony_ci}; 59262306a36Sopenharmony_cistatic const u8 sensor_start_qvga_yuyv_772x[][2] = { 59362306a36Sopenharmony_ci {0x12, 0x40}, 59462306a36Sopenharmony_ci {0x17, 0x3f}, 59562306a36Sopenharmony_ci {0x18, 0x50}, 59662306a36Sopenharmony_ci {0x19, 0x03}, 59762306a36Sopenharmony_ci {0x1a, 0x78}, 59862306a36Sopenharmony_ci {0x29, 0x50}, 59962306a36Sopenharmony_ci {0x2c, 0x78}, 60062306a36Sopenharmony_ci {0x65, 0x2f}, 60162306a36Sopenharmony_ci {0x67, 0x00}, 60262306a36Sopenharmony_ci}; 60362306a36Sopenharmony_cistatic const u8 bridge_start_vga_gbrg_772x[][2] = { 60462306a36Sopenharmony_ci {0x88, 0x08}, 60562306a36Sopenharmony_ci {0x1c, 0x00}, 60662306a36Sopenharmony_ci {0x1d, 0x00}, 60762306a36Sopenharmony_ci {0x1d, 0x02}, 60862306a36Sopenharmony_ci {0x1d, 0x00}, 60962306a36Sopenharmony_ci {0x1d, 0x01}, 61062306a36Sopenharmony_ci {0x1d, 0x2c}, 61162306a36Sopenharmony_ci {0x1d, 0x00}, 61262306a36Sopenharmony_ci {0x8d, 0x00}, 61362306a36Sopenharmony_ci {0x8e, 0x00}, 61462306a36Sopenharmony_ci {0xc0, 0x50}, 61562306a36Sopenharmony_ci {0xc1, 0x3c}, 61662306a36Sopenharmony_ci {0xc2, 0x01}, 61762306a36Sopenharmony_ci {0xc3, 0x01}, 61862306a36Sopenharmony_ci}; 61962306a36Sopenharmony_cistatic const u8 sensor_start_vga_gbrg_772x[][2] = { 62062306a36Sopenharmony_ci {0x12, 0x01}, 62162306a36Sopenharmony_ci {0x17, 0x26}, 62262306a36Sopenharmony_ci {0x18, 0xa0}, 62362306a36Sopenharmony_ci {0x19, 0x07}, 62462306a36Sopenharmony_ci {0x1a, 0xf0}, 62562306a36Sopenharmony_ci {0x29, 0xa0}, 62662306a36Sopenharmony_ci {0x2c, 0xf0}, 62762306a36Sopenharmony_ci {0x65, 0x20}, 62862306a36Sopenharmony_ci {0x67, 0x02}, 62962306a36Sopenharmony_ci}; 63062306a36Sopenharmony_cistatic const u8 bridge_start_qvga_gbrg_772x[][2] = { 63162306a36Sopenharmony_ci {0x88, 0x08}, 63262306a36Sopenharmony_ci {0x1c, 0x00}, 63362306a36Sopenharmony_ci {0x1d, 0x00}, 63462306a36Sopenharmony_ci {0x1d, 0x02}, 63562306a36Sopenharmony_ci {0x1d, 0x00}, 63662306a36Sopenharmony_ci {0x1d, 0x00}, 63762306a36Sopenharmony_ci {0x1d, 0x4b}, 63862306a36Sopenharmony_ci {0x1d, 0x00}, 63962306a36Sopenharmony_ci {0x8d, 0x00}, 64062306a36Sopenharmony_ci {0x8e, 0x00}, 64162306a36Sopenharmony_ci {0xc0, 0x28}, 64262306a36Sopenharmony_ci {0xc1, 0x1e}, 64362306a36Sopenharmony_ci {0xc2, 0x01}, 64462306a36Sopenharmony_ci {0xc3, 0x01}, 64562306a36Sopenharmony_ci}; 64662306a36Sopenharmony_cistatic const u8 sensor_start_qvga_gbrg_772x[][2] = { 64762306a36Sopenharmony_ci {0x12, 0x41}, 64862306a36Sopenharmony_ci {0x17, 0x3f}, 64962306a36Sopenharmony_ci {0x18, 0x50}, 65062306a36Sopenharmony_ci {0x19, 0x03}, 65162306a36Sopenharmony_ci {0x1a, 0x78}, 65262306a36Sopenharmony_ci {0x29, 0x50}, 65362306a36Sopenharmony_ci {0x2c, 0x78}, 65462306a36Sopenharmony_ci {0x65, 0x2f}, 65562306a36Sopenharmony_ci {0x67, 0x02}, 65662306a36Sopenharmony_ci}; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_cistatic void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci struct usb_device *udev = gspca_dev->dev; 66162306a36Sopenharmony_ci int ret; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci if (gspca_dev->usb_err < 0) 66462306a36Sopenharmony_ci return; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_USBO, "SET 01 0000 %04x %02x\n", reg, val); 66762306a36Sopenharmony_ci gspca_dev->usb_buf[0] = val; 66862306a36Sopenharmony_ci ret = usb_control_msg(udev, 66962306a36Sopenharmony_ci usb_sndctrlpipe(udev, 0), 67062306a36Sopenharmony_ci 0x01, 67162306a36Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 67262306a36Sopenharmony_ci 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT); 67362306a36Sopenharmony_ci if (ret < 0) { 67462306a36Sopenharmony_ci pr_err("write failed %d\n", ret); 67562306a36Sopenharmony_ci gspca_dev->usb_err = ret; 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci} 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_cistatic u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci struct usb_device *udev = gspca_dev->dev; 68262306a36Sopenharmony_ci int ret; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci if (gspca_dev->usb_err < 0) 68562306a36Sopenharmony_ci return 0; 68662306a36Sopenharmony_ci ret = usb_control_msg(udev, 68762306a36Sopenharmony_ci usb_rcvctrlpipe(udev, 0), 68862306a36Sopenharmony_ci 0x01, 68962306a36Sopenharmony_ci USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 69062306a36Sopenharmony_ci 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT); 69162306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_USBI, "GET 01 0000 %04x %02x\n", 69262306a36Sopenharmony_ci reg, gspca_dev->usb_buf[0]); 69362306a36Sopenharmony_ci if (ret < 0) { 69462306a36Sopenharmony_ci pr_err("read failed %d\n", ret); 69562306a36Sopenharmony_ci gspca_dev->usb_err = ret; 69662306a36Sopenharmony_ci /* 69762306a36Sopenharmony_ci * Make sure the result is zeroed to avoid uninitialized 69862306a36Sopenharmony_ci * values. 69962306a36Sopenharmony_ci */ 70062306a36Sopenharmony_ci gspca_dev->usb_buf[0] = 0; 70162306a36Sopenharmony_ci } 70262306a36Sopenharmony_ci return gspca_dev->usb_buf[0]; 70362306a36Sopenharmony_ci} 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci/* Two bits control LED: 0x21 bit 7 and 0x23 bit 7. 70662306a36Sopenharmony_ci * (direction and output)? */ 70762306a36Sopenharmony_cistatic void ov534_set_led(struct gspca_dev *gspca_dev, int status) 70862306a36Sopenharmony_ci{ 70962306a36Sopenharmony_ci u8 data; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_CONF, "led status: %d\n", status); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci data = ov534_reg_read(gspca_dev, 0x21); 71462306a36Sopenharmony_ci data |= 0x80; 71562306a36Sopenharmony_ci ov534_reg_write(gspca_dev, 0x21, data); 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci data = ov534_reg_read(gspca_dev, 0x23); 71862306a36Sopenharmony_ci if (status) 71962306a36Sopenharmony_ci data |= 0x80; 72062306a36Sopenharmony_ci else 72162306a36Sopenharmony_ci data &= ~0x80; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci ov534_reg_write(gspca_dev, 0x23, data); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci if (!status) { 72662306a36Sopenharmony_ci data = ov534_reg_read(gspca_dev, 0x21); 72762306a36Sopenharmony_ci data &= ~0x80; 72862306a36Sopenharmony_ci ov534_reg_write(gspca_dev, 0x21, data); 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci} 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_cistatic int sccb_check_status(struct gspca_dev *gspca_dev) 73362306a36Sopenharmony_ci{ 73462306a36Sopenharmony_ci u8 data; 73562306a36Sopenharmony_ci int i; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci for (i = 0; i < 5; i++) { 73862306a36Sopenharmony_ci usleep_range(10000, 20000); 73962306a36Sopenharmony_ci data = ov534_reg_read(gspca_dev, OV534_REG_STATUS); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci switch (data) { 74262306a36Sopenharmony_ci case 0x00: 74362306a36Sopenharmony_ci return 1; 74462306a36Sopenharmony_ci case 0x04: 74562306a36Sopenharmony_ci return 0; 74662306a36Sopenharmony_ci case 0x03: 74762306a36Sopenharmony_ci break; 74862306a36Sopenharmony_ci default: 74962306a36Sopenharmony_ci gspca_err(gspca_dev, "sccb status 0x%02x, attempt %d/5\n", 75062306a36Sopenharmony_ci data, i + 1); 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci return 0; 75462306a36Sopenharmony_ci} 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_cistatic void sccb_reg_write(struct gspca_dev *gspca_dev, u8 reg, u8 val) 75762306a36Sopenharmony_ci{ 75862306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_USBO, "sccb write: %02x %02x\n", reg, val); 75962306a36Sopenharmony_ci ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg); 76062306a36Sopenharmony_ci ov534_reg_write(gspca_dev, OV534_REG_WRITE, val); 76162306a36Sopenharmony_ci ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci if (!sccb_check_status(gspca_dev)) { 76462306a36Sopenharmony_ci pr_err("sccb_reg_write failed\n"); 76562306a36Sopenharmony_ci gspca_dev->usb_err = -EIO; 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci} 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_cistatic u8 sccb_reg_read(struct gspca_dev *gspca_dev, u16 reg) 77062306a36Sopenharmony_ci{ 77162306a36Sopenharmony_ci ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg); 77262306a36Sopenharmony_ci ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_2); 77362306a36Sopenharmony_ci if (!sccb_check_status(gspca_dev)) 77462306a36Sopenharmony_ci pr_err("sccb_reg_read failed 1\n"); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_READ_2); 77762306a36Sopenharmony_ci if (!sccb_check_status(gspca_dev)) 77862306a36Sopenharmony_ci pr_err("sccb_reg_read failed 2\n"); 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci return ov534_reg_read(gspca_dev, OV534_REG_READ); 78162306a36Sopenharmony_ci} 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci/* output a bridge sequence (reg - val) */ 78462306a36Sopenharmony_cistatic void reg_w_array(struct gspca_dev *gspca_dev, 78562306a36Sopenharmony_ci const u8 (*data)[2], int len) 78662306a36Sopenharmony_ci{ 78762306a36Sopenharmony_ci while (--len >= 0) { 78862306a36Sopenharmony_ci ov534_reg_write(gspca_dev, (*data)[0], (*data)[1]); 78962306a36Sopenharmony_ci data++; 79062306a36Sopenharmony_ci } 79162306a36Sopenharmony_ci} 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci/* output a sensor sequence (reg - val) */ 79462306a36Sopenharmony_cistatic void sccb_w_array(struct gspca_dev *gspca_dev, 79562306a36Sopenharmony_ci const u8 (*data)[2], int len) 79662306a36Sopenharmony_ci{ 79762306a36Sopenharmony_ci while (--len >= 0) { 79862306a36Sopenharmony_ci if ((*data)[0] != 0xff) { 79962306a36Sopenharmony_ci sccb_reg_write(gspca_dev, (*data)[0], (*data)[1]); 80062306a36Sopenharmony_ci } else { 80162306a36Sopenharmony_ci sccb_reg_read(gspca_dev, (*data)[1]); 80262306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0xff, 0x00); 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci data++; 80562306a36Sopenharmony_ci } 80662306a36Sopenharmony_ci} 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci/* ov772x specific controls */ 80962306a36Sopenharmony_cistatic void set_frame_rate(struct gspca_dev *gspca_dev) 81062306a36Sopenharmony_ci{ 81162306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 81262306a36Sopenharmony_ci int i; 81362306a36Sopenharmony_ci struct rate_s { 81462306a36Sopenharmony_ci u8 fps; 81562306a36Sopenharmony_ci u8 r11; 81662306a36Sopenharmony_ci u8 r0d; 81762306a36Sopenharmony_ci u8 re5; 81862306a36Sopenharmony_ci }; 81962306a36Sopenharmony_ci const struct rate_s *r; 82062306a36Sopenharmony_ci static const struct rate_s rate_0[] = { /* 640x480 */ 82162306a36Sopenharmony_ci {60, 0x01, 0xc1, 0x04}, 82262306a36Sopenharmony_ci {50, 0x01, 0x41, 0x02}, 82362306a36Sopenharmony_ci {40, 0x02, 0xc1, 0x04}, 82462306a36Sopenharmony_ci {30, 0x04, 0x81, 0x02}, 82562306a36Sopenharmony_ci {15, 0x03, 0x41, 0x04}, 82662306a36Sopenharmony_ci }; 82762306a36Sopenharmony_ci static const struct rate_s rate_1[] = { /* 320x240 */ 82862306a36Sopenharmony_ci/* {205, 0x01, 0xc1, 0x02}, * 205 FPS: video is partly corrupt */ 82962306a36Sopenharmony_ci {187, 0x01, 0x81, 0x02}, /* 187 FPS or below: video is valid */ 83062306a36Sopenharmony_ci {150, 0x01, 0xc1, 0x04}, 83162306a36Sopenharmony_ci {137, 0x02, 0xc1, 0x02}, 83262306a36Sopenharmony_ci {125, 0x02, 0x81, 0x02}, 83362306a36Sopenharmony_ci {100, 0x02, 0xc1, 0x04}, 83462306a36Sopenharmony_ci {75, 0x03, 0xc1, 0x04}, 83562306a36Sopenharmony_ci {60, 0x04, 0xc1, 0x04}, 83662306a36Sopenharmony_ci {50, 0x02, 0x41, 0x04}, 83762306a36Sopenharmony_ci {37, 0x03, 0x41, 0x04}, 83862306a36Sopenharmony_ci {30, 0x04, 0x41, 0x04}, 83962306a36Sopenharmony_ci }; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci if (sd->sensor != SENSOR_OV772x) 84262306a36Sopenharmony_ci return; 84362306a36Sopenharmony_ci if (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv == 0) { 84462306a36Sopenharmony_ci r = rate_0; 84562306a36Sopenharmony_ci i = ARRAY_SIZE(rate_0); 84662306a36Sopenharmony_ci } else { 84762306a36Sopenharmony_ci r = rate_1; 84862306a36Sopenharmony_ci i = ARRAY_SIZE(rate_1); 84962306a36Sopenharmony_ci } 85062306a36Sopenharmony_ci while (--i > 0) { 85162306a36Sopenharmony_ci if (sd->frame_rate >= r->fps) 85262306a36Sopenharmony_ci break; 85362306a36Sopenharmony_ci r++; 85462306a36Sopenharmony_ci } 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0x11, r->r11); 85762306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0x0d, r->r0d); 85862306a36Sopenharmony_ci ov534_reg_write(gspca_dev, 0xe5, r->re5); 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_PROBE, "frame_rate: %d\n", r->fps); 86162306a36Sopenharmony_ci} 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_cistatic void sethue(struct gspca_dev *gspca_dev, s32 val) 86462306a36Sopenharmony_ci{ 86562306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci if (sd->sensor == SENSOR_OV767x) { 86862306a36Sopenharmony_ci /* TBD */ 86962306a36Sopenharmony_ci } else { 87062306a36Sopenharmony_ci s16 huesin; 87162306a36Sopenharmony_ci s16 huecos; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci /* According to the datasheet the registers expect HUESIN and 87462306a36Sopenharmony_ci * HUECOS to be the result of the trigonometric functions, 87562306a36Sopenharmony_ci * scaled by 0x80. 87662306a36Sopenharmony_ci * 87762306a36Sopenharmony_ci * The 0x7fff here represents the maximum absolute value 87862306a36Sopenharmony_ci * returned byt fixp_sin and fixp_cos, so the scaling will 87962306a36Sopenharmony_ci * consider the result like in the interval [-1.0, 1.0]. 88062306a36Sopenharmony_ci */ 88162306a36Sopenharmony_ci huesin = fixp_sin16(val) * 0x80 / 0x7fff; 88262306a36Sopenharmony_ci huecos = fixp_cos16(val) * 0x80 / 0x7fff; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci if (huesin < 0) { 88562306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0xab, 88662306a36Sopenharmony_ci sccb_reg_read(gspca_dev, 0xab) | 0x2); 88762306a36Sopenharmony_ci huesin = -huesin; 88862306a36Sopenharmony_ci } else { 88962306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0xab, 89062306a36Sopenharmony_ci sccb_reg_read(gspca_dev, 0xab) & ~0x2); 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci } 89362306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0xa9, (u8)huecos); 89462306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0xaa, (u8)huesin); 89562306a36Sopenharmony_ci } 89662306a36Sopenharmony_ci} 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_cistatic void setsaturation(struct gspca_dev *gspca_dev, s32 val) 89962306a36Sopenharmony_ci{ 90062306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci if (sd->sensor == SENSOR_OV767x) { 90362306a36Sopenharmony_ci int i; 90462306a36Sopenharmony_ci static u8 color_tb[][6] = { 90562306a36Sopenharmony_ci {0x42, 0x42, 0x00, 0x11, 0x30, 0x41}, 90662306a36Sopenharmony_ci {0x52, 0x52, 0x00, 0x16, 0x3c, 0x52}, 90762306a36Sopenharmony_ci {0x66, 0x66, 0x00, 0x1b, 0x4b, 0x66}, 90862306a36Sopenharmony_ci {0x80, 0x80, 0x00, 0x22, 0x5e, 0x80}, 90962306a36Sopenharmony_ci {0x9a, 0x9a, 0x00, 0x29, 0x71, 0x9a}, 91062306a36Sopenharmony_ci {0xb8, 0xb8, 0x00, 0x31, 0x87, 0xb8}, 91162306a36Sopenharmony_ci {0xdd, 0xdd, 0x00, 0x3b, 0xa2, 0xdd}, 91262306a36Sopenharmony_ci }; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(color_tb[0]); i++) 91562306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0x4f + i, color_tb[val][i]); 91662306a36Sopenharmony_ci } else { 91762306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0xa7, val); /* U saturation */ 91862306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0xa8, val); /* V saturation */ 91962306a36Sopenharmony_ci } 92062306a36Sopenharmony_ci} 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_cistatic void setbrightness(struct gspca_dev *gspca_dev, s32 val) 92362306a36Sopenharmony_ci{ 92462306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci if (sd->sensor == SENSOR_OV767x) { 92762306a36Sopenharmony_ci if (val < 0) 92862306a36Sopenharmony_ci val = 0x80 - val; 92962306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0x55, val); /* bright */ 93062306a36Sopenharmony_ci } else { 93162306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0x9b, val); 93262306a36Sopenharmony_ci } 93362306a36Sopenharmony_ci} 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_cistatic void setcontrast(struct gspca_dev *gspca_dev, s32 val) 93662306a36Sopenharmony_ci{ 93762306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci if (sd->sensor == SENSOR_OV767x) 94062306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0x56, val); /* contras */ 94162306a36Sopenharmony_ci else 94262306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0x9c, val); 94362306a36Sopenharmony_ci} 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_cistatic void setgain(struct gspca_dev *gspca_dev, s32 val) 94662306a36Sopenharmony_ci{ 94762306a36Sopenharmony_ci switch (val & 0x30) { 94862306a36Sopenharmony_ci case 0x00: 94962306a36Sopenharmony_ci val &= 0x0f; 95062306a36Sopenharmony_ci break; 95162306a36Sopenharmony_ci case 0x10: 95262306a36Sopenharmony_ci val &= 0x0f; 95362306a36Sopenharmony_ci val |= 0x30; 95462306a36Sopenharmony_ci break; 95562306a36Sopenharmony_ci case 0x20: 95662306a36Sopenharmony_ci val &= 0x0f; 95762306a36Sopenharmony_ci val |= 0x70; 95862306a36Sopenharmony_ci break; 95962306a36Sopenharmony_ci default: 96062306a36Sopenharmony_ci/* case 0x30: */ 96162306a36Sopenharmony_ci val &= 0x0f; 96262306a36Sopenharmony_ci val |= 0xf0; 96362306a36Sopenharmony_ci break; 96462306a36Sopenharmony_ci } 96562306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0x00, val); 96662306a36Sopenharmony_ci} 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_cistatic s32 getgain(struct gspca_dev *gspca_dev) 96962306a36Sopenharmony_ci{ 97062306a36Sopenharmony_ci return sccb_reg_read(gspca_dev, 0x00); 97162306a36Sopenharmony_ci} 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_cistatic void setexposure(struct gspca_dev *gspca_dev, s32 val) 97462306a36Sopenharmony_ci{ 97562306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci if (sd->sensor == SENSOR_OV767x) { 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci /* set only aec[9:2] */ 98062306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0x10, val); /* aech */ 98162306a36Sopenharmony_ci } else { 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci /* 'val' is one byte and represents half of the exposure value 98462306a36Sopenharmony_ci * we are going to set into registers, a two bytes value: 98562306a36Sopenharmony_ci * 98662306a36Sopenharmony_ci * MSB: ((u16) val << 1) >> 8 == val >> 7 98762306a36Sopenharmony_ci * LSB: ((u16) val << 1) & 0xff == val << 1 98862306a36Sopenharmony_ci */ 98962306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0x08, val >> 7); 99062306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0x10, val << 1); 99162306a36Sopenharmony_ci } 99262306a36Sopenharmony_ci} 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_cistatic s32 getexposure(struct gspca_dev *gspca_dev) 99562306a36Sopenharmony_ci{ 99662306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci if (sd->sensor == SENSOR_OV767x) { 99962306a36Sopenharmony_ci /* get only aec[9:2] */ 100062306a36Sopenharmony_ci return sccb_reg_read(gspca_dev, 0x10); /* aech */ 100162306a36Sopenharmony_ci } else { 100262306a36Sopenharmony_ci u8 hi = sccb_reg_read(gspca_dev, 0x08); 100362306a36Sopenharmony_ci u8 lo = sccb_reg_read(gspca_dev, 0x10); 100462306a36Sopenharmony_ci return (hi << 8 | lo) >> 1; 100562306a36Sopenharmony_ci } 100662306a36Sopenharmony_ci} 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_cistatic void setagc(struct gspca_dev *gspca_dev, s32 val) 100962306a36Sopenharmony_ci{ 101062306a36Sopenharmony_ci if (val) { 101162306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0x13, 101262306a36Sopenharmony_ci sccb_reg_read(gspca_dev, 0x13) | 0x04); 101362306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0x64, 101462306a36Sopenharmony_ci sccb_reg_read(gspca_dev, 0x64) | 0x03); 101562306a36Sopenharmony_ci } else { 101662306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0x13, 101762306a36Sopenharmony_ci sccb_reg_read(gspca_dev, 0x13) & ~0x04); 101862306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0x64, 101962306a36Sopenharmony_ci sccb_reg_read(gspca_dev, 0x64) & ~0x03); 102062306a36Sopenharmony_ci } 102162306a36Sopenharmony_ci} 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_cistatic void setawb(struct gspca_dev *gspca_dev, s32 val) 102462306a36Sopenharmony_ci{ 102562306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci if (val) { 102862306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0x13, 102962306a36Sopenharmony_ci sccb_reg_read(gspca_dev, 0x13) | 0x02); 103062306a36Sopenharmony_ci if (sd->sensor == SENSOR_OV772x) 103162306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0x63, 103262306a36Sopenharmony_ci sccb_reg_read(gspca_dev, 0x63) | 0xc0); 103362306a36Sopenharmony_ci } else { 103462306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0x13, 103562306a36Sopenharmony_ci sccb_reg_read(gspca_dev, 0x13) & ~0x02); 103662306a36Sopenharmony_ci if (sd->sensor == SENSOR_OV772x) 103762306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0x63, 103862306a36Sopenharmony_ci sccb_reg_read(gspca_dev, 0x63) & ~0xc0); 103962306a36Sopenharmony_ci } 104062306a36Sopenharmony_ci} 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_cistatic void setaec(struct gspca_dev *gspca_dev, s32 val) 104362306a36Sopenharmony_ci{ 104462306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 104562306a36Sopenharmony_ci u8 data; 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci data = sd->sensor == SENSOR_OV767x ? 104862306a36Sopenharmony_ci 0x05 : /* agc + aec */ 104962306a36Sopenharmony_ci 0x01; /* agc */ 105062306a36Sopenharmony_ci switch (val) { 105162306a36Sopenharmony_ci case V4L2_EXPOSURE_AUTO: 105262306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0x13, 105362306a36Sopenharmony_ci sccb_reg_read(gspca_dev, 0x13) | data); 105462306a36Sopenharmony_ci break; 105562306a36Sopenharmony_ci case V4L2_EXPOSURE_MANUAL: 105662306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0x13, 105762306a36Sopenharmony_ci sccb_reg_read(gspca_dev, 0x13) & ~data); 105862306a36Sopenharmony_ci break; 105962306a36Sopenharmony_ci } 106062306a36Sopenharmony_ci} 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_cistatic void setsharpness(struct gspca_dev *gspca_dev, s32 val) 106362306a36Sopenharmony_ci{ 106462306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0x91, val); /* Auto de-noise threshold */ 106562306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0x8e, val); /* De-noise threshold */ 106662306a36Sopenharmony_ci} 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_cistatic void sethvflip(struct gspca_dev *gspca_dev, s32 hflip, s32 vflip) 106962306a36Sopenharmony_ci{ 107062306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 107162306a36Sopenharmony_ci u8 val; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci if (sd->sensor == SENSOR_OV767x) { 107462306a36Sopenharmony_ci val = sccb_reg_read(gspca_dev, 0x1e); /* mvfp */ 107562306a36Sopenharmony_ci val &= ~0x30; 107662306a36Sopenharmony_ci if (hflip) 107762306a36Sopenharmony_ci val |= 0x20; 107862306a36Sopenharmony_ci if (vflip) 107962306a36Sopenharmony_ci val |= 0x10; 108062306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0x1e, val); 108162306a36Sopenharmony_ci } else { 108262306a36Sopenharmony_ci val = sccb_reg_read(gspca_dev, 0x0c); 108362306a36Sopenharmony_ci val &= ~0xc0; 108462306a36Sopenharmony_ci if (hflip == 0) 108562306a36Sopenharmony_ci val |= 0x40; 108662306a36Sopenharmony_ci if (vflip == 0) 108762306a36Sopenharmony_ci val |= 0x80; 108862306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0x0c, val); 108962306a36Sopenharmony_ci } 109062306a36Sopenharmony_ci} 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_cistatic void setlightfreq(struct gspca_dev *gspca_dev, s32 val) 109362306a36Sopenharmony_ci{ 109462306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci val = val ? 0x9e : 0x00; 109762306a36Sopenharmony_ci if (sd->sensor == SENSOR_OV767x) { 109862306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0x2a, 0x00); 109962306a36Sopenharmony_ci if (val) 110062306a36Sopenharmony_ci val = 0x9d; /* insert dummy to 25fps for 50Hz */ 110162306a36Sopenharmony_ci } 110262306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0x2b, val); 110362306a36Sopenharmony_ci} 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci/* this function is called at probe time */ 110762306a36Sopenharmony_cistatic int sd_config(struct gspca_dev *gspca_dev, 110862306a36Sopenharmony_ci const struct usb_device_id *id) 110962306a36Sopenharmony_ci{ 111062306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 111162306a36Sopenharmony_ci struct cam *cam; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci cam = &gspca_dev->cam; 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci cam->cam_mode = ov772x_mode; 111662306a36Sopenharmony_ci cam->nmodes = ARRAY_SIZE(ov772x_mode); 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci sd->frame_rate = DEFAULT_FRAME_RATE; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci return 0; 112162306a36Sopenharmony_ci} 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_cistatic int ov534_g_volatile_ctrl(struct v4l2_ctrl *ctrl) 112462306a36Sopenharmony_ci{ 112562306a36Sopenharmony_ci struct sd *sd = container_of(ctrl->handler, struct sd, ctrl_handler); 112662306a36Sopenharmony_ci struct gspca_dev *gspca_dev = &sd->gspca_dev; 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci switch (ctrl->id) { 112962306a36Sopenharmony_ci case V4L2_CID_AUTOGAIN: 113062306a36Sopenharmony_ci gspca_dev->usb_err = 0; 113162306a36Sopenharmony_ci if (ctrl->val && sd->gain && gspca_dev->streaming) 113262306a36Sopenharmony_ci sd->gain->val = getgain(gspca_dev); 113362306a36Sopenharmony_ci return gspca_dev->usb_err; 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci case V4L2_CID_EXPOSURE_AUTO: 113662306a36Sopenharmony_ci gspca_dev->usb_err = 0; 113762306a36Sopenharmony_ci if (ctrl->val == V4L2_EXPOSURE_AUTO && sd->exposure && 113862306a36Sopenharmony_ci gspca_dev->streaming) 113962306a36Sopenharmony_ci sd->exposure->val = getexposure(gspca_dev); 114062306a36Sopenharmony_ci return gspca_dev->usb_err; 114162306a36Sopenharmony_ci } 114262306a36Sopenharmony_ci return -EINVAL; 114362306a36Sopenharmony_ci} 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_cistatic int ov534_s_ctrl(struct v4l2_ctrl *ctrl) 114662306a36Sopenharmony_ci{ 114762306a36Sopenharmony_ci struct sd *sd = container_of(ctrl->handler, struct sd, ctrl_handler); 114862306a36Sopenharmony_ci struct gspca_dev *gspca_dev = &sd->gspca_dev; 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci gspca_dev->usb_err = 0; 115162306a36Sopenharmony_ci if (!gspca_dev->streaming) 115262306a36Sopenharmony_ci return 0; 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci switch (ctrl->id) { 115562306a36Sopenharmony_ci case V4L2_CID_HUE: 115662306a36Sopenharmony_ci sethue(gspca_dev, ctrl->val); 115762306a36Sopenharmony_ci break; 115862306a36Sopenharmony_ci case V4L2_CID_SATURATION: 115962306a36Sopenharmony_ci setsaturation(gspca_dev, ctrl->val); 116062306a36Sopenharmony_ci break; 116162306a36Sopenharmony_ci case V4L2_CID_BRIGHTNESS: 116262306a36Sopenharmony_ci setbrightness(gspca_dev, ctrl->val); 116362306a36Sopenharmony_ci break; 116462306a36Sopenharmony_ci case V4L2_CID_CONTRAST: 116562306a36Sopenharmony_ci setcontrast(gspca_dev, ctrl->val); 116662306a36Sopenharmony_ci break; 116762306a36Sopenharmony_ci case V4L2_CID_AUTOGAIN: 116862306a36Sopenharmony_ci /* case V4L2_CID_GAIN: */ 116962306a36Sopenharmony_ci setagc(gspca_dev, ctrl->val); 117062306a36Sopenharmony_ci if (!gspca_dev->usb_err && !ctrl->val && sd->gain) 117162306a36Sopenharmony_ci setgain(gspca_dev, sd->gain->val); 117262306a36Sopenharmony_ci break; 117362306a36Sopenharmony_ci case V4L2_CID_AUTO_WHITE_BALANCE: 117462306a36Sopenharmony_ci setawb(gspca_dev, ctrl->val); 117562306a36Sopenharmony_ci break; 117662306a36Sopenharmony_ci case V4L2_CID_EXPOSURE_AUTO: 117762306a36Sopenharmony_ci /* case V4L2_CID_EXPOSURE: */ 117862306a36Sopenharmony_ci setaec(gspca_dev, ctrl->val); 117962306a36Sopenharmony_ci if (!gspca_dev->usb_err && ctrl->val == V4L2_EXPOSURE_MANUAL && 118062306a36Sopenharmony_ci sd->exposure) 118162306a36Sopenharmony_ci setexposure(gspca_dev, sd->exposure->val); 118262306a36Sopenharmony_ci break; 118362306a36Sopenharmony_ci case V4L2_CID_SHARPNESS: 118462306a36Sopenharmony_ci setsharpness(gspca_dev, ctrl->val); 118562306a36Sopenharmony_ci break; 118662306a36Sopenharmony_ci case V4L2_CID_HFLIP: 118762306a36Sopenharmony_ci sethvflip(gspca_dev, ctrl->val, sd->vflip->val); 118862306a36Sopenharmony_ci break; 118962306a36Sopenharmony_ci case V4L2_CID_VFLIP: 119062306a36Sopenharmony_ci sethvflip(gspca_dev, sd->hflip->val, ctrl->val); 119162306a36Sopenharmony_ci break; 119262306a36Sopenharmony_ci case V4L2_CID_POWER_LINE_FREQUENCY: 119362306a36Sopenharmony_ci setlightfreq(gspca_dev, ctrl->val); 119462306a36Sopenharmony_ci break; 119562306a36Sopenharmony_ci } 119662306a36Sopenharmony_ci return gspca_dev->usb_err; 119762306a36Sopenharmony_ci} 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_cistatic const struct v4l2_ctrl_ops ov534_ctrl_ops = { 120062306a36Sopenharmony_ci .g_volatile_ctrl = ov534_g_volatile_ctrl, 120162306a36Sopenharmony_ci .s_ctrl = ov534_s_ctrl, 120262306a36Sopenharmony_ci}; 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_cistatic int sd_init_controls(struct gspca_dev *gspca_dev) 120562306a36Sopenharmony_ci{ 120662306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 120762306a36Sopenharmony_ci struct v4l2_ctrl_handler *hdl = &sd->ctrl_handler; 120862306a36Sopenharmony_ci /* parameters with different values between the supported sensors */ 120962306a36Sopenharmony_ci int saturation_min; 121062306a36Sopenharmony_ci int saturation_max; 121162306a36Sopenharmony_ci int saturation_def; 121262306a36Sopenharmony_ci int brightness_min; 121362306a36Sopenharmony_ci int brightness_max; 121462306a36Sopenharmony_ci int brightness_def; 121562306a36Sopenharmony_ci int contrast_max; 121662306a36Sopenharmony_ci int contrast_def; 121762306a36Sopenharmony_ci int exposure_min; 121862306a36Sopenharmony_ci int exposure_max; 121962306a36Sopenharmony_ci int exposure_def; 122062306a36Sopenharmony_ci int hflip_def; 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci if (sd->sensor == SENSOR_OV767x) { 122362306a36Sopenharmony_ci saturation_min = 0; 122462306a36Sopenharmony_ci saturation_max = 6; 122562306a36Sopenharmony_ci saturation_def = 3; 122662306a36Sopenharmony_ci brightness_min = -127; 122762306a36Sopenharmony_ci brightness_max = 127; 122862306a36Sopenharmony_ci brightness_def = 0; 122962306a36Sopenharmony_ci contrast_max = 0x80; 123062306a36Sopenharmony_ci contrast_def = 0x40; 123162306a36Sopenharmony_ci exposure_min = 0x08; 123262306a36Sopenharmony_ci exposure_max = 0x60; 123362306a36Sopenharmony_ci exposure_def = 0x13; 123462306a36Sopenharmony_ci hflip_def = 1; 123562306a36Sopenharmony_ci } else { 123662306a36Sopenharmony_ci saturation_min = 0; 123762306a36Sopenharmony_ci saturation_max = 255; 123862306a36Sopenharmony_ci saturation_def = 64; 123962306a36Sopenharmony_ci brightness_min = 0; 124062306a36Sopenharmony_ci brightness_max = 255; 124162306a36Sopenharmony_ci brightness_def = 0; 124262306a36Sopenharmony_ci contrast_max = 255; 124362306a36Sopenharmony_ci contrast_def = 32; 124462306a36Sopenharmony_ci exposure_min = 0; 124562306a36Sopenharmony_ci exposure_max = 255; 124662306a36Sopenharmony_ci exposure_def = 120; 124762306a36Sopenharmony_ci hflip_def = 0; 124862306a36Sopenharmony_ci } 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci gspca_dev->vdev.ctrl_handler = hdl; 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci v4l2_ctrl_handler_init(hdl, 13); 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci if (sd->sensor == SENSOR_OV772x) 125562306a36Sopenharmony_ci sd->hue = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, 125662306a36Sopenharmony_ci V4L2_CID_HUE, -90, 90, 1, 0); 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci sd->saturation = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, 125962306a36Sopenharmony_ci V4L2_CID_SATURATION, saturation_min, saturation_max, 1, 126062306a36Sopenharmony_ci saturation_def); 126162306a36Sopenharmony_ci sd->brightness = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, 126262306a36Sopenharmony_ci V4L2_CID_BRIGHTNESS, brightness_min, brightness_max, 1, 126362306a36Sopenharmony_ci brightness_def); 126462306a36Sopenharmony_ci sd->contrast = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, 126562306a36Sopenharmony_ci V4L2_CID_CONTRAST, 0, contrast_max, 1, contrast_def); 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci if (sd->sensor == SENSOR_OV772x) { 126862306a36Sopenharmony_ci sd->autogain = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, 126962306a36Sopenharmony_ci V4L2_CID_AUTOGAIN, 0, 1, 1, 1); 127062306a36Sopenharmony_ci sd->gain = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, 127162306a36Sopenharmony_ci V4L2_CID_GAIN, 0, 63, 1, 20); 127262306a36Sopenharmony_ci } 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci sd->autoexposure = v4l2_ctrl_new_std_menu(hdl, &ov534_ctrl_ops, 127562306a36Sopenharmony_ci V4L2_CID_EXPOSURE_AUTO, 127662306a36Sopenharmony_ci V4L2_EXPOSURE_MANUAL, 0, 127762306a36Sopenharmony_ci V4L2_EXPOSURE_AUTO); 127862306a36Sopenharmony_ci sd->exposure = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, 127962306a36Sopenharmony_ci V4L2_CID_EXPOSURE, exposure_min, exposure_max, 1, 128062306a36Sopenharmony_ci exposure_def); 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci sd->autowhitebalance = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, 128362306a36Sopenharmony_ci V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci if (sd->sensor == SENSOR_OV772x) 128662306a36Sopenharmony_ci sd->sharpness = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, 128762306a36Sopenharmony_ci V4L2_CID_SHARPNESS, 0, 63, 1, 0); 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci sd->hflip = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, 129062306a36Sopenharmony_ci V4L2_CID_HFLIP, 0, 1, 1, hflip_def); 129162306a36Sopenharmony_ci sd->vflip = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, 129262306a36Sopenharmony_ci V4L2_CID_VFLIP, 0, 1, 1, 0); 129362306a36Sopenharmony_ci sd->plfreq = v4l2_ctrl_new_std_menu(hdl, &ov534_ctrl_ops, 129462306a36Sopenharmony_ci V4L2_CID_POWER_LINE_FREQUENCY, 129562306a36Sopenharmony_ci V4L2_CID_POWER_LINE_FREQUENCY_50HZ, 0, 129662306a36Sopenharmony_ci V4L2_CID_POWER_LINE_FREQUENCY_DISABLED); 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci if (hdl->error) { 129962306a36Sopenharmony_ci pr_err("Could not initialize controls\n"); 130062306a36Sopenharmony_ci return hdl->error; 130162306a36Sopenharmony_ci } 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci if (sd->sensor == SENSOR_OV772x) 130462306a36Sopenharmony_ci v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, true); 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci v4l2_ctrl_auto_cluster(2, &sd->autoexposure, V4L2_EXPOSURE_MANUAL, 130762306a36Sopenharmony_ci true); 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci return 0; 131062306a36Sopenharmony_ci} 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci/* this function is called at probe and resume time */ 131362306a36Sopenharmony_cistatic int sd_init(struct gspca_dev *gspca_dev) 131462306a36Sopenharmony_ci{ 131562306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 131662306a36Sopenharmony_ci u16 sensor_id; 131762306a36Sopenharmony_ci static const struct reg_array bridge_init[NSENSORS] = { 131862306a36Sopenharmony_ci [SENSOR_OV767x] = {bridge_init_767x, ARRAY_SIZE(bridge_init_767x)}, 131962306a36Sopenharmony_ci [SENSOR_OV772x] = {bridge_init_772x, ARRAY_SIZE(bridge_init_772x)}, 132062306a36Sopenharmony_ci }; 132162306a36Sopenharmony_ci static const struct reg_array sensor_init[NSENSORS] = { 132262306a36Sopenharmony_ci [SENSOR_OV767x] = {sensor_init_767x, ARRAY_SIZE(sensor_init_767x)}, 132362306a36Sopenharmony_ci [SENSOR_OV772x] = {sensor_init_772x, ARRAY_SIZE(sensor_init_772x)}, 132462306a36Sopenharmony_ci }; 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci /* reset bridge */ 132762306a36Sopenharmony_ci ov534_reg_write(gspca_dev, 0xe7, 0x3a); 132862306a36Sopenharmony_ci ov534_reg_write(gspca_dev, 0xe0, 0x08); 132962306a36Sopenharmony_ci msleep(100); 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci /* initialize the sensor address */ 133262306a36Sopenharmony_ci ov534_reg_write(gspca_dev, OV534_REG_ADDRESS, 0x42); 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci /* reset sensor */ 133562306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0x12, 0x80); 133662306a36Sopenharmony_ci usleep_range(10000, 20000); 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci /* probe the sensor */ 133962306a36Sopenharmony_ci sccb_reg_read(gspca_dev, 0x0a); 134062306a36Sopenharmony_ci sensor_id = sccb_reg_read(gspca_dev, 0x0a) << 8; 134162306a36Sopenharmony_ci sccb_reg_read(gspca_dev, 0x0b); 134262306a36Sopenharmony_ci sensor_id |= sccb_reg_read(gspca_dev, 0x0b); 134362306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_PROBE, "Sensor ID: %04x\n", sensor_id); 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci if ((sensor_id & 0xfff0) == 0x7670) { 134662306a36Sopenharmony_ci sd->sensor = SENSOR_OV767x; 134762306a36Sopenharmony_ci gspca_dev->cam.cam_mode = ov767x_mode; 134862306a36Sopenharmony_ci gspca_dev->cam.nmodes = ARRAY_SIZE(ov767x_mode); 134962306a36Sopenharmony_ci } else { 135062306a36Sopenharmony_ci sd->sensor = SENSOR_OV772x; 135162306a36Sopenharmony_ci gspca_dev->cam.bulk = 1; 135262306a36Sopenharmony_ci gspca_dev->cam.bulk_size = 16384; 135362306a36Sopenharmony_ci gspca_dev->cam.bulk_nurbs = 2; 135462306a36Sopenharmony_ci gspca_dev->cam.mode_framerates = ov772x_framerates; 135562306a36Sopenharmony_ci } 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci /* initialize */ 135862306a36Sopenharmony_ci reg_w_array(gspca_dev, bridge_init[sd->sensor].val, 135962306a36Sopenharmony_ci bridge_init[sd->sensor].len); 136062306a36Sopenharmony_ci ov534_set_led(gspca_dev, 1); 136162306a36Sopenharmony_ci sccb_w_array(gspca_dev, sensor_init[sd->sensor].val, 136262306a36Sopenharmony_ci sensor_init[sd->sensor].len); 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci sd_stopN(gspca_dev); 136562306a36Sopenharmony_ci/* set_frame_rate(gspca_dev); */ 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci return gspca_dev->usb_err; 136862306a36Sopenharmony_ci} 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_cistatic int sd_start(struct gspca_dev *gspca_dev) 137162306a36Sopenharmony_ci{ 137262306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 137362306a36Sopenharmony_ci int mode; 137462306a36Sopenharmony_ci static const struct reg_array bridge_start[NSENSORS][4] = { 137562306a36Sopenharmony_ci [SENSOR_OV767x] = {{bridge_start_qvga_767x, 137662306a36Sopenharmony_ci ARRAY_SIZE(bridge_start_qvga_767x)}, 137762306a36Sopenharmony_ci {bridge_start_vga_767x, 137862306a36Sopenharmony_ci ARRAY_SIZE(bridge_start_vga_767x)}}, 137962306a36Sopenharmony_ci [SENSOR_OV772x] = {{bridge_start_qvga_yuyv_772x, 138062306a36Sopenharmony_ci ARRAY_SIZE(bridge_start_qvga_yuyv_772x)}, 138162306a36Sopenharmony_ci {bridge_start_vga_yuyv_772x, 138262306a36Sopenharmony_ci ARRAY_SIZE(bridge_start_vga_yuyv_772x)}, 138362306a36Sopenharmony_ci {bridge_start_qvga_gbrg_772x, 138462306a36Sopenharmony_ci ARRAY_SIZE(bridge_start_qvga_gbrg_772x)}, 138562306a36Sopenharmony_ci {bridge_start_vga_gbrg_772x, 138662306a36Sopenharmony_ci ARRAY_SIZE(bridge_start_vga_gbrg_772x)} }, 138762306a36Sopenharmony_ci }; 138862306a36Sopenharmony_ci static const struct reg_array sensor_start[NSENSORS][4] = { 138962306a36Sopenharmony_ci [SENSOR_OV767x] = {{sensor_start_qvga_767x, 139062306a36Sopenharmony_ci ARRAY_SIZE(sensor_start_qvga_767x)}, 139162306a36Sopenharmony_ci {sensor_start_vga_767x, 139262306a36Sopenharmony_ci ARRAY_SIZE(sensor_start_vga_767x)}}, 139362306a36Sopenharmony_ci [SENSOR_OV772x] = {{sensor_start_qvga_yuyv_772x, 139462306a36Sopenharmony_ci ARRAY_SIZE(sensor_start_qvga_yuyv_772x)}, 139562306a36Sopenharmony_ci {sensor_start_vga_yuyv_772x, 139662306a36Sopenharmony_ci ARRAY_SIZE(sensor_start_vga_yuyv_772x)}, 139762306a36Sopenharmony_ci {sensor_start_qvga_gbrg_772x, 139862306a36Sopenharmony_ci ARRAY_SIZE(sensor_start_qvga_gbrg_772x)}, 139962306a36Sopenharmony_ci {sensor_start_vga_gbrg_772x, 140062306a36Sopenharmony_ci ARRAY_SIZE(sensor_start_vga_gbrg_772x)} }, 140162306a36Sopenharmony_ci }; 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci /* (from ms-win trace) */ 140462306a36Sopenharmony_ci if (sd->sensor == SENSOR_OV767x) 140562306a36Sopenharmony_ci sccb_reg_write(gspca_dev, 0x1e, 0x04); 140662306a36Sopenharmony_ci /* black sun enable ? */ 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci mode = gspca_dev->curr_mode; /* 0: 320x240, 1: 640x480 */ 140962306a36Sopenharmony_ci reg_w_array(gspca_dev, bridge_start[sd->sensor][mode].val, 141062306a36Sopenharmony_ci bridge_start[sd->sensor][mode].len); 141162306a36Sopenharmony_ci sccb_w_array(gspca_dev, sensor_start[sd->sensor][mode].val, 141262306a36Sopenharmony_ci sensor_start[sd->sensor][mode].len); 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci set_frame_rate(gspca_dev); 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci if (sd->hue) 141762306a36Sopenharmony_ci sethue(gspca_dev, v4l2_ctrl_g_ctrl(sd->hue)); 141862306a36Sopenharmony_ci setsaturation(gspca_dev, v4l2_ctrl_g_ctrl(sd->saturation)); 141962306a36Sopenharmony_ci if (sd->autogain) 142062306a36Sopenharmony_ci setagc(gspca_dev, v4l2_ctrl_g_ctrl(sd->autogain)); 142162306a36Sopenharmony_ci setawb(gspca_dev, v4l2_ctrl_g_ctrl(sd->autowhitebalance)); 142262306a36Sopenharmony_ci setaec(gspca_dev, v4l2_ctrl_g_ctrl(sd->autoexposure)); 142362306a36Sopenharmony_ci if (sd->gain) 142462306a36Sopenharmony_ci setgain(gspca_dev, v4l2_ctrl_g_ctrl(sd->gain)); 142562306a36Sopenharmony_ci setexposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure)); 142662306a36Sopenharmony_ci setbrightness(gspca_dev, v4l2_ctrl_g_ctrl(sd->brightness)); 142762306a36Sopenharmony_ci setcontrast(gspca_dev, v4l2_ctrl_g_ctrl(sd->contrast)); 142862306a36Sopenharmony_ci if (sd->sharpness) 142962306a36Sopenharmony_ci setsharpness(gspca_dev, v4l2_ctrl_g_ctrl(sd->sharpness)); 143062306a36Sopenharmony_ci sethvflip(gspca_dev, v4l2_ctrl_g_ctrl(sd->hflip), 143162306a36Sopenharmony_ci v4l2_ctrl_g_ctrl(sd->vflip)); 143262306a36Sopenharmony_ci setlightfreq(gspca_dev, v4l2_ctrl_g_ctrl(sd->plfreq)); 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci ov534_set_led(gspca_dev, 1); 143562306a36Sopenharmony_ci ov534_reg_write(gspca_dev, 0xe0, 0x00); 143662306a36Sopenharmony_ci return gspca_dev->usb_err; 143762306a36Sopenharmony_ci} 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_cistatic void sd_stopN(struct gspca_dev *gspca_dev) 144062306a36Sopenharmony_ci{ 144162306a36Sopenharmony_ci ov534_reg_write(gspca_dev, 0xe0, 0x09); 144262306a36Sopenharmony_ci ov534_set_led(gspca_dev, 0); 144362306a36Sopenharmony_ci} 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */ 144662306a36Sopenharmony_ci#define UVC_STREAM_EOH (1 << 7) 144762306a36Sopenharmony_ci#define UVC_STREAM_ERR (1 << 6) 144862306a36Sopenharmony_ci#define UVC_STREAM_STI (1 << 5) 144962306a36Sopenharmony_ci#define UVC_STREAM_RES (1 << 4) 145062306a36Sopenharmony_ci#define UVC_STREAM_SCR (1 << 3) 145162306a36Sopenharmony_ci#define UVC_STREAM_PTS (1 << 2) 145262306a36Sopenharmony_ci#define UVC_STREAM_EOF (1 << 1) 145362306a36Sopenharmony_ci#define UVC_STREAM_FID (1 << 0) 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_cistatic void sd_pkt_scan(struct gspca_dev *gspca_dev, 145662306a36Sopenharmony_ci u8 *data, int len) 145762306a36Sopenharmony_ci{ 145862306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 145962306a36Sopenharmony_ci __u32 this_pts; 146062306a36Sopenharmony_ci u16 this_fid; 146162306a36Sopenharmony_ci int remaining_len = len; 146262306a36Sopenharmony_ci int payload_len; 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci payload_len = gspca_dev->cam.bulk ? 2048 : 2040; 146562306a36Sopenharmony_ci do { 146662306a36Sopenharmony_ci len = min(remaining_len, payload_len); 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci /* Payloads are prefixed with a UVC-style header. We 146962306a36Sopenharmony_ci consider a frame to start when the FID toggles, or the PTS 147062306a36Sopenharmony_ci changes. A frame ends when EOF is set, and we've received 147162306a36Sopenharmony_ci the correct number of bytes. */ 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci /* Verify UVC header. Header length is always 12 */ 147462306a36Sopenharmony_ci if (data[0] != 12 || len < 12) { 147562306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_PACK, "bad header\n"); 147662306a36Sopenharmony_ci goto discard; 147762306a36Sopenharmony_ci } 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci /* Check errors */ 148062306a36Sopenharmony_ci if (data[1] & UVC_STREAM_ERR) { 148162306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_PACK, "payload error\n"); 148262306a36Sopenharmony_ci goto discard; 148362306a36Sopenharmony_ci } 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci /* Extract PTS and FID */ 148662306a36Sopenharmony_ci if (!(data[1] & UVC_STREAM_PTS)) { 148762306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_PACK, "PTS not present\n"); 148862306a36Sopenharmony_ci goto discard; 148962306a36Sopenharmony_ci } 149062306a36Sopenharmony_ci this_pts = (data[5] << 24) | (data[4] << 16) 149162306a36Sopenharmony_ci | (data[3] << 8) | data[2]; 149262306a36Sopenharmony_ci this_fid = (data[1] & UVC_STREAM_FID) ? 1 : 0; 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci /* If PTS or FID has changed, start a new frame. */ 149562306a36Sopenharmony_ci if (this_pts != sd->last_pts || this_fid != sd->last_fid) { 149662306a36Sopenharmony_ci if (gspca_dev->last_packet_type == INTER_PACKET) 149762306a36Sopenharmony_ci gspca_frame_add(gspca_dev, LAST_PACKET, 149862306a36Sopenharmony_ci NULL, 0); 149962306a36Sopenharmony_ci sd->last_pts = this_pts; 150062306a36Sopenharmony_ci sd->last_fid = this_fid; 150162306a36Sopenharmony_ci gspca_frame_add(gspca_dev, FIRST_PACKET, 150262306a36Sopenharmony_ci data + 12, len - 12); 150362306a36Sopenharmony_ci /* If this packet is marked as EOF, end the frame */ 150462306a36Sopenharmony_ci } else if (data[1] & UVC_STREAM_EOF) { 150562306a36Sopenharmony_ci sd->last_pts = 0; 150662306a36Sopenharmony_ci if (gspca_dev->pixfmt.pixelformat != V4L2_PIX_FMT_JPEG 150762306a36Sopenharmony_ci && gspca_dev->image_len + len - 12 != 150862306a36Sopenharmony_ci gspca_dev->pixfmt.sizeimage) { 150962306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_PACK, "wrong sized frame\n"); 151062306a36Sopenharmony_ci goto discard; 151162306a36Sopenharmony_ci } 151262306a36Sopenharmony_ci gspca_frame_add(gspca_dev, LAST_PACKET, 151362306a36Sopenharmony_ci data + 12, len - 12); 151462306a36Sopenharmony_ci } else { 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci /* Add the data from this payload */ 151762306a36Sopenharmony_ci gspca_frame_add(gspca_dev, INTER_PACKET, 151862306a36Sopenharmony_ci data + 12, len - 12); 151962306a36Sopenharmony_ci } 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci /* Done this payload */ 152262306a36Sopenharmony_ci goto scan_next; 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_cidiscard: 152562306a36Sopenharmony_ci /* Discard data until a new frame starts. */ 152662306a36Sopenharmony_ci gspca_dev->last_packet_type = DISCARD_PACKET; 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ciscan_next: 152962306a36Sopenharmony_ci remaining_len -= len; 153062306a36Sopenharmony_ci data += len; 153162306a36Sopenharmony_ci } while (remaining_len > 0); 153262306a36Sopenharmony_ci} 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci/* get stream parameters (framerate) */ 153562306a36Sopenharmony_cistatic void sd_get_streamparm(struct gspca_dev *gspca_dev, 153662306a36Sopenharmony_ci struct v4l2_streamparm *parm) 153762306a36Sopenharmony_ci{ 153862306a36Sopenharmony_ci struct v4l2_captureparm *cp = &parm->parm.capture; 153962306a36Sopenharmony_ci struct v4l2_fract *tpf = &cp->timeperframe; 154062306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci tpf->numerator = 1; 154362306a36Sopenharmony_ci tpf->denominator = sd->frame_rate; 154462306a36Sopenharmony_ci} 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci/* set stream parameters (framerate) */ 154762306a36Sopenharmony_cistatic void sd_set_streamparm(struct gspca_dev *gspca_dev, 154862306a36Sopenharmony_ci struct v4l2_streamparm *parm) 154962306a36Sopenharmony_ci{ 155062306a36Sopenharmony_ci struct v4l2_captureparm *cp = &parm->parm.capture; 155162306a36Sopenharmony_ci struct v4l2_fract *tpf = &cp->timeperframe; 155262306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci if (tpf->numerator == 0 || tpf->denominator == 0) 155562306a36Sopenharmony_ci sd->frame_rate = DEFAULT_FRAME_RATE; 155662306a36Sopenharmony_ci else 155762306a36Sopenharmony_ci sd->frame_rate = tpf->denominator / tpf->numerator; 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci if (gspca_dev->streaming) 156062306a36Sopenharmony_ci set_frame_rate(gspca_dev); 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci /* Return the actual framerate */ 156362306a36Sopenharmony_ci tpf->numerator = 1; 156462306a36Sopenharmony_ci tpf->denominator = sd->frame_rate; 156562306a36Sopenharmony_ci} 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci/* sub-driver description */ 156862306a36Sopenharmony_cistatic const struct sd_desc sd_desc = { 156962306a36Sopenharmony_ci .name = MODULE_NAME, 157062306a36Sopenharmony_ci .config = sd_config, 157162306a36Sopenharmony_ci .init = sd_init, 157262306a36Sopenharmony_ci .init_controls = sd_init_controls, 157362306a36Sopenharmony_ci .start = sd_start, 157462306a36Sopenharmony_ci .stopN = sd_stopN, 157562306a36Sopenharmony_ci .pkt_scan = sd_pkt_scan, 157662306a36Sopenharmony_ci .get_streamparm = sd_get_streamparm, 157762306a36Sopenharmony_ci .set_streamparm = sd_set_streamparm, 157862306a36Sopenharmony_ci}; 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci/* -- module initialisation -- */ 158162306a36Sopenharmony_cistatic const struct usb_device_id device_table[] = { 158262306a36Sopenharmony_ci {USB_DEVICE(0x1415, 0x2000)}, 158362306a36Sopenharmony_ci {USB_DEVICE(0x06f8, 0x3002)}, 158462306a36Sopenharmony_ci {} 158562306a36Sopenharmony_ci}; 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, device_table); 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci/* -- device connect -- */ 159062306a36Sopenharmony_cistatic int sd_probe(struct usb_interface *intf, const struct usb_device_id *id) 159162306a36Sopenharmony_ci{ 159262306a36Sopenharmony_ci return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), 159362306a36Sopenharmony_ci THIS_MODULE); 159462306a36Sopenharmony_ci} 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_cistatic struct usb_driver sd_driver = { 159762306a36Sopenharmony_ci .name = MODULE_NAME, 159862306a36Sopenharmony_ci .id_table = device_table, 159962306a36Sopenharmony_ci .probe = sd_probe, 160062306a36Sopenharmony_ci .disconnect = gspca_disconnect, 160162306a36Sopenharmony_ci#ifdef CONFIG_PM 160262306a36Sopenharmony_ci .suspend = gspca_suspend, 160362306a36Sopenharmony_ci .resume = gspca_resume, 160462306a36Sopenharmony_ci .reset_resume = gspca_resume, 160562306a36Sopenharmony_ci#endif 160662306a36Sopenharmony_ci}; 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_cimodule_usb_driver(sd_driver); 1609