18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ov534-ov7xxx gspca driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2008 Antonio Ospite <ospite@studenti.unina.it> 68c2ecf20Sopenharmony_ci * Copyright (C) 2008 Jim Paris <jim@jtan.com> 78c2ecf20Sopenharmony_ci * Copyright (C) 2009 Jean-Francois Moine http://moinejf.free.fr 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Based on a prototype written by Mark Ferrell <majortrips@gmail.com> 108c2ecf20Sopenharmony_ci * USB protocol reverse engineered by Jim Paris <jim@jtan.com> 118c2ecf20Sopenharmony_ci * https://jim.sh/svn/jim/devl/playstation/ps3/eye/test/ 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * PS3 Eye camera enhanced by Richard Kaswy http://kaswy.free.fr 148c2ecf20Sopenharmony_ci * PS3 Eye camera - brightness, contrast, awb, agc, aec controls 158c2ecf20Sopenharmony_ci * added by Max Thrun <bear24rw@gmail.com> 168c2ecf20Sopenharmony_ci * PS3 Eye camera - FPS range extended by Joseph Howse 178c2ecf20Sopenharmony_ci * <josephhowse@nummist.com> https://nummist.com 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define MODULE_NAME "ov534" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include "gspca.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <linux/fixp-arith.h> 278c2ecf20Sopenharmony_ci#include <media/v4l2-ctrls.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define OV534_REG_ADDRESS 0xf1 /* sensor address */ 308c2ecf20Sopenharmony_ci#define OV534_REG_SUBADDR 0xf2 318c2ecf20Sopenharmony_ci#define OV534_REG_WRITE 0xf3 328c2ecf20Sopenharmony_ci#define OV534_REG_READ 0xf4 338c2ecf20Sopenharmony_ci#define OV534_REG_OPERATION 0xf5 348c2ecf20Sopenharmony_ci#define OV534_REG_STATUS 0xf6 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define OV534_OP_WRITE_3 0x37 378c2ecf20Sopenharmony_ci#define OV534_OP_WRITE_2 0x33 388c2ecf20Sopenharmony_ci#define OV534_OP_READ_2 0xf9 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define CTRL_TIMEOUT 500 418c2ecf20Sopenharmony_ci#define DEFAULT_FRAME_RATE 30 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ciMODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>"); 448c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("GSPCA/OV534 USB Camera Driver"); 458c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* specific webcam descriptor */ 488c2ecf20Sopenharmony_cistruct sd { 498c2ecf20Sopenharmony_ci struct gspca_dev gspca_dev; /* !! must be the first item */ 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci struct v4l2_ctrl_handler ctrl_handler; 528c2ecf20Sopenharmony_ci struct v4l2_ctrl *hue; 538c2ecf20Sopenharmony_ci struct v4l2_ctrl *saturation; 548c2ecf20Sopenharmony_ci struct v4l2_ctrl *brightness; 558c2ecf20Sopenharmony_ci struct v4l2_ctrl *contrast; 568c2ecf20Sopenharmony_ci struct { /* gain control cluster */ 578c2ecf20Sopenharmony_ci struct v4l2_ctrl *autogain; 588c2ecf20Sopenharmony_ci struct v4l2_ctrl *gain; 598c2ecf20Sopenharmony_ci }; 608c2ecf20Sopenharmony_ci struct v4l2_ctrl *autowhitebalance; 618c2ecf20Sopenharmony_ci struct { /* exposure control cluster */ 628c2ecf20Sopenharmony_ci struct v4l2_ctrl *autoexposure; 638c2ecf20Sopenharmony_ci struct v4l2_ctrl *exposure; 648c2ecf20Sopenharmony_ci }; 658c2ecf20Sopenharmony_ci struct v4l2_ctrl *sharpness; 668c2ecf20Sopenharmony_ci struct v4l2_ctrl *hflip; 678c2ecf20Sopenharmony_ci struct v4l2_ctrl *vflip; 688c2ecf20Sopenharmony_ci struct v4l2_ctrl *plfreq; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci __u32 last_pts; 718c2ecf20Sopenharmony_ci u16 last_fid; 728c2ecf20Sopenharmony_ci u8 frame_rate; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci u8 sensor; 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_cienum sensors { 778c2ecf20Sopenharmony_ci SENSOR_OV767x, 788c2ecf20Sopenharmony_ci SENSOR_OV772x, 798c2ecf20Sopenharmony_ci NSENSORS 808c2ecf20Sopenharmony_ci}; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic int sd_start(struct gspca_dev *gspca_dev); 838c2ecf20Sopenharmony_cistatic void sd_stopN(struct gspca_dev *gspca_dev); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic const struct v4l2_pix_format ov772x_mode[] = { 878c2ecf20Sopenharmony_ci {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, 888c2ecf20Sopenharmony_ci .bytesperline = 320 * 2, 898c2ecf20Sopenharmony_ci .sizeimage = 320 * 240 * 2, 908c2ecf20Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 918c2ecf20Sopenharmony_ci .priv = 1}, 928c2ecf20Sopenharmony_ci {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, 938c2ecf20Sopenharmony_ci .bytesperline = 640 * 2, 948c2ecf20Sopenharmony_ci .sizeimage = 640 * 480 * 2, 958c2ecf20Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 968c2ecf20Sopenharmony_ci .priv = 0}, 978c2ecf20Sopenharmony_ci {320, 240, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, 988c2ecf20Sopenharmony_ci .bytesperline = 320, 998c2ecf20Sopenharmony_ci .sizeimage = 320 * 240, 1008c2ecf20Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 1018c2ecf20Sopenharmony_ci .priv = 1}, 1028c2ecf20Sopenharmony_ci {640, 480, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, 1038c2ecf20Sopenharmony_ci .bytesperline = 640, 1048c2ecf20Sopenharmony_ci .sizeimage = 640 * 480, 1058c2ecf20Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 1068c2ecf20Sopenharmony_ci .priv = 0}, 1078c2ecf20Sopenharmony_ci}; 1088c2ecf20Sopenharmony_cistatic const struct v4l2_pix_format ov767x_mode[] = { 1098c2ecf20Sopenharmony_ci {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, 1108c2ecf20Sopenharmony_ci .bytesperline = 320, 1118c2ecf20Sopenharmony_ci .sizeimage = 320 * 240 * 3 / 8 + 590, 1128c2ecf20Sopenharmony_ci .colorspace = V4L2_COLORSPACE_JPEG}, 1138c2ecf20Sopenharmony_ci {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, 1148c2ecf20Sopenharmony_ci .bytesperline = 640, 1158c2ecf20Sopenharmony_ci .sizeimage = 640 * 480 * 3 / 8 + 590, 1168c2ecf20Sopenharmony_ci .colorspace = V4L2_COLORSPACE_JPEG}, 1178c2ecf20Sopenharmony_ci}; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic const u8 qvga_rates[] = {187, 150, 137, 125, 100, 75, 60, 50, 37, 30}; 1208c2ecf20Sopenharmony_cistatic const u8 vga_rates[] = {60, 50, 40, 30, 15}; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic const struct framerates ov772x_framerates[] = { 1238c2ecf20Sopenharmony_ci { /* 320x240 */ 1248c2ecf20Sopenharmony_ci .rates = qvga_rates, 1258c2ecf20Sopenharmony_ci .nrates = ARRAY_SIZE(qvga_rates), 1268c2ecf20Sopenharmony_ci }, 1278c2ecf20Sopenharmony_ci { /* 640x480 */ 1288c2ecf20Sopenharmony_ci .rates = vga_rates, 1298c2ecf20Sopenharmony_ci .nrates = ARRAY_SIZE(vga_rates), 1308c2ecf20Sopenharmony_ci }, 1318c2ecf20Sopenharmony_ci { /* 320x240 SGBRG8 */ 1328c2ecf20Sopenharmony_ci .rates = qvga_rates, 1338c2ecf20Sopenharmony_ci .nrates = ARRAY_SIZE(qvga_rates), 1348c2ecf20Sopenharmony_ci }, 1358c2ecf20Sopenharmony_ci { /* 640x480 SGBRG8 */ 1368c2ecf20Sopenharmony_ci .rates = vga_rates, 1378c2ecf20Sopenharmony_ci .nrates = ARRAY_SIZE(vga_rates), 1388c2ecf20Sopenharmony_ci }, 1398c2ecf20Sopenharmony_ci}; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistruct reg_array { 1428c2ecf20Sopenharmony_ci const u8 (*val)[2]; 1438c2ecf20Sopenharmony_ci int len; 1448c2ecf20Sopenharmony_ci}; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic const u8 bridge_init_767x[][2] = { 1478c2ecf20Sopenharmony_ci/* comments from the ms-win file apollo7670.set */ 1488c2ecf20Sopenharmony_ci/* str1 */ 1498c2ecf20Sopenharmony_ci {0xf1, 0x42}, 1508c2ecf20Sopenharmony_ci {0x88, 0xf8}, 1518c2ecf20Sopenharmony_ci {0x89, 0xff}, 1528c2ecf20Sopenharmony_ci {0x76, 0x03}, 1538c2ecf20Sopenharmony_ci {0x92, 0x03}, 1548c2ecf20Sopenharmony_ci {0x95, 0x10}, 1558c2ecf20Sopenharmony_ci {0xe2, 0x00}, 1568c2ecf20Sopenharmony_ci {0xe7, 0x3e}, 1578c2ecf20Sopenharmony_ci {0x8d, 0x1c}, 1588c2ecf20Sopenharmony_ci {0x8e, 0x00}, 1598c2ecf20Sopenharmony_ci {0x8f, 0x00}, 1608c2ecf20Sopenharmony_ci {0x1f, 0x00}, 1618c2ecf20Sopenharmony_ci {0xc3, 0xf9}, 1628c2ecf20Sopenharmony_ci {0x89, 0xff}, 1638c2ecf20Sopenharmony_ci {0x88, 0xf8}, 1648c2ecf20Sopenharmony_ci {0x76, 0x03}, 1658c2ecf20Sopenharmony_ci {0x92, 0x01}, 1668c2ecf20Sopenharmony_ci {0x93, 0x18}, 1678c2ecf20Sopenharmony_ci {0x1c, 0x00}, 1688c2ecf20Sopenharmony_ci {0x1d, 0x48}, 1698c2ecf20Sopenharmony_ci {0x1d, 0x00}, 1708c2ecf20Sopenharmony_ci {0x1d, 0xff}, 1718c2ecf20Sopenharmony_ci {0x1d, 0x02}, 1728c2ecf20Sopenharmony_ci {0x1d, 0x58}, 1738c2ecf20Sopenharmony_ci {0x1d, 0x00}, 1748c2ecf20Sopenharmony_ci {0x1c, 0x0a}, 1758c2ecf20Sopenharmony_ci {0x1d, 0x0a}, 1768c2ecf20Sopenharmony_ci {0x1d, 0x0e}, 1778c2ecf20Sopenharmony_ci {0xc0, 0x50}, /* HSize 640 */ 1788c2ecf20Sopenharmony_ci {0xc1, 0x3c}, /* VSize 480 */ 1798c2ecf20Sopenharmony_ci {0x34, 0x05}, /* enable Audio Suspend mode */ 1808c2ecf20Sopenharmony_ci {0xc2, 0x0c}, /* Input YUV */ 1818c2ecf20Sopenharmony_ci {0xc3, 0xf9}, /* enable PRE */ 1828c2ecf20Sopenharmony_ci {0x34, 0x05}, /* enable Audio Suspend mode */ 1838c2ecf20Sopenharmony_ci {0xe7, 0x2e}, /* this solves failure of "SuspendResumeTest" */ 1848c2ecf20Sopenharmony_ci {0x31, 0xf9}, /* enable 1.8V Suspend */ 1858c2ecf20Sopenharmony_ci {0x35, 0x02}, /* turn on JPEG */ 1868c2ecf20Sopenharmony_ci {0xd9, 0x10}, 1878c2ecf20Sopenharmony_ci {0x25, 0x42}, /* GPIO[8]:Input */ 1888c2ecf20Sopenharmony_ci {0x94, 0x11}, /* If the default setting is loaded when 1898c2ecf20Sopenharmony_ci * system boots up, this flag is closed here */ 1908c2ecf20Sopenharmony_ci}; 1918c2ecf20Sopenharmony_cistatic const u8 sensor_init_767x[][2] = { 1928c2ecf20Sopenharmony_ci {0x12, 0x80}, 1938c2ecf20Sopenharmony_ci {0x11, 0x03}, 1948c2ecf20Sopenharmony_ci {0x3a, 0x04}, 1958c2ecf20Sopenharmony_ci {0x12, 0x00}, 1968c2ecf20Sopenharmony_ci {0x17, 0x13}, 1978c2ecf20Sopenharmony_ci {0x18, 0x01}, 1988c2ecf20Sopenharmony_ci {0x32, 0xb6}, 1998c2ecf20Sopenharmony_ci {0x19, 0x02}, 2008c2ecf20Sopenharmony_ci {0x1a, 0x7a}, 2018c2ecf20Sopenharmony_ci {0x03, 0x0a}, 2028c2ecf20Sopenharmony_ci {0x0c, 0x00}, 2038c2ecf20Sopenharmony_ci {0x3e, 0x00}, 2048c2ecf20Sopenharmony_ci {0x70, 0x3a}, 2058c2ecf20Sopenharmony_ci {0x71, 0x35}, 2068c2ecf20Sopenharmony_ci {0x72, 0x11}, 2078c2ecf20Sopenharmony_ci {0x73, 0xf0}, 2088c2ecf20Sopenharmony_ci {0xa2, 0x02}, 2098c2ecf20Sopenharmony_ci {0x7a, 0x2a}, /* set Gamma=1.6 below */ 2108c2ecf20Sopenharmony_ci {0x7b, 0x12}, 2118c2ecf20Sopenharmony_ci {0x7c, 0x1d}, 2128c2ecf20Sopenharmony_ci {0x7d, 0x2d}, 2138c2ecf20Sopenharmony_ci {0x7e, 0x45}, 2148c2ecf20Sopenharmony_ci {0x7f, 0x50}, 2158c2ecf20Sopenharmony_ci {0x80, 0x59}, 2168c2ecf20Sopenharmony_ci {0x81, 0x62}, 2178c2ecf20Sopenharmony_ci {0x82, 0x6b}, 2188c2ecf20Sopenharmony_ci {0x83, 0x73}, 2198c2ecf20Sopenharmony_ci {0x84, 0x7b}, 2208c2ecf20Sopenharmony_ci {0x85, 0x8a}, 2218c2ecf20Sopenharmony_ci {0x86, 0x98}, 2228c2ecf20Sopenharmony_ci {0x87, 0xb2}, 2238c2ecf20Sopenharmony_ci {0x88, 0xca}, 2248c2ecf20Sopenharmony_ci {0x89, 0xe0}, 2258c2ecf20Sopenharmony_ci {0x13, 0xe0}, 2268c2ecf20Sopenharmony_ci {0x00, 0x00}, 2278c2ecf20Sopenharmony_ci {0x10, 0x00}, 2288c2ecf20Sopenharmony_ci {0x0d, 0x40}, 2298c2ecf20Sopenharmony_ci {0x14, 0x38}, /* gain max 16x */ 2308c2ecf20Sopenharmony_ci {0xa5, 0x05}, 2318c2ecf20Sopenharmony_ci {0xab, 0x07}, 2328c2ecf20Sopenharmony_ci {0x24, 0x95}, 2338c2ecf20Sopenharmony_ci {0x25, 0x33}, 2348c2ecf20Sopenharmony_ci {0x26, 0xe3}, 2358c2ecf20Sopenharmony_ci {0x9f, 0x78}, 2368c2ecf20Sopenharmony_ci {0xa0, 0x68}, 2378c2ecf20Sopenharmony_ci {0xa1, 0x03}, 2388c2ecf20Sopenharmony_ci {0xa6, 0xd8}, 2398c2ecf20Sopenharmony_ci {0xa7, 0xd8}, 2408c2ecf20Sopenharmony_ci {0xa8, 0xf0}, 2418c2ecf20Sopenharmony_ci {0xa9, 0x90}, 2428c2ecf20Sopenharmony_ci {0xaa, 0x94}, 2438c2ecf20Sopenharmony_ci {0x13, 0xe5}, 2448c2ecf20Sopenharmony_ci {0x0e, 0x61}, 2458c2ecf20Sopenharmony_ci {0x0f, 0x4b}, 2468c2ecf20Sopenharmony_ci {0x16, 0x02}, 2478c2ecf20Sopenharmony_ci {0x21, 0x02}, 2488c2ecf20Sopenharmony_ci {0x22, 0x91}, 2498c2ecf20Sopenharmony_ci {0x29, 0x07}, 2508c2ecf20Sopenharmony_ci {0x33, 0x0b}, 2518c2ecf20Sopenharmony_ci {0x35, 0x0b}, 2528c2ecf20Sopenharmony_ci {0x37, 0x1d}, 2538c2ecf20Sopenharmony_ci {0x38, 0x71}, 2548c2ecf20Sopenharmony_ci {0x39, 0x2a}, 2558c2ecf20Sopenharmony_ci {0x3c, 0x78}, 2568c2ecf20Sopenharmony_ci {0x4d, 0x40}, 2578c2ecf20Sopenharmony_ci {0x4e, 0x20}, 2588c2ecf20Sopenharmony_ci {0x69, 0x00}, 2598c2ecf20Sopenharmony_ci {0x6b, 0x4a}, 2608c2ecf20Sopenharmony_ci {0x74, 0x10}, 2618c2ecf20Sopenharmony_ci {0x8d, 0x4f}, 2628c2ecf20Sopenharmony_ci {0x8e, 0x00}, 2638c2ecf20Sopenharmony_ci {0x8f, 0x00}, 2648c2ecf20Sopenharmony_ci {0x90, 0x00}, 2658c2ecf20Sopenharmony_ci {0x91, 0x00}, 2668c2ecf20Sopenharmony_ci {0x96, 0x00}, 2678c2ecf20Sopenharmony_ci {0x9a, 0x80}, 2688c2ecf20Sopenharmony_ci {0xb0, 0x84}, 2698c2ecf20Sopenharmony_ci {0xb1, 0x0c}, 2708c2ecf20Sopenharmony_ci {0xb2, 0x0e}, 2718c2ecf20Sopenharmony_ci {0xb3, 0x82}, 2728c2ecf20Sopenharmony_ci {0xb8, 0x0a}, 2738c2ecf20Sopenharmony_ci {0x43, 0x0a}, 2748c2ecf20Sopenharmony_ci {0x44, 0xf0}, 2758c2ecf20Sopenharmony_ci {0x45, 0x34}, 2768c2ecf20Sopenharmony_ci {0x46, 0x58}, 2778c2ecf20Sopenharmony_ci {0x47, 0x28}, 2788c2ecf20Sopenharmony_ci {0x48, 0x3a}, 2798c2ecf20Sopenharmony_ci {0x59, 0x88}, 2808c2ecf20Sopenharmony_ci {0x5a, 0x88}, 2818c2ecf20Sopenharmony_ci {0x5b, 0x44}, 2828c2ecf20Sopenharmony_ci {0x5c, 0x67}, 2838c2ecf20Sopenharmony_ci {0x5d, 0x49}, 2848c2ecf20Sopenharmony_ci {0x5e, 0x0e}, 2858c2ecf20Sopenharmony_ci {0x6c, 0x0a}, 2868c2ecf20Sopenharmony_ci {0x6d, 0x55}, 2878c2ecf20Sopenharmony_ci {0x6e, 0x11}, 2888c2ecf20Sopenharmony_ci {0x6f, 0x9f}, 2898c2ecf20Sopenharmony_ci {0x6a, 0x40}, 2908c2ecf20Sopenharmony_ci {0x01, 0x40}, 2918c2ecf20Sopenharmony_ci {0x02, 0x40}, 2928c2ecf20Sopenharmony_ci {0x13, 0xe7}, 2938c2ecf20Sopenharmony_ci {0x4f, 0x80}, 2948c2ecf20Sopenharmony_ci {0x50, 0x80}, 2958c2ecf20Sopenharmony_ci {0x51, 0x00}, 2968c2ecf20Sopenharmony_ci {0x52, 0x22}, 2978c2ecf20Sopenharmony_ci {0x53, 0x5e}, 2988c2ecf20Sopenharmony_ci {0x54, 0x80}, 2998c2ecf20Sopenharmony_ci {0x58, 0x9e}, 3008c2ecf20Sopenharmony_ci {0x41, 0x08}, 3018c2ecf20Sopenharmony_ci {0x3f, 0x00}, 3028c2ecf20Sopenharmony_ci {0x75, 0x04}, 3038c2ecf20Sopenharmony_ci {0x76, 0xe1}, 3048c2ecf20Sopenharmony_ci {0x4c, 0x00}, 3058c2ecf20Sopenharmony_ci {0x77, 0x01}, 3068c2ecf20Sopenharmony_ci {0x3d, 0xc2}, 3078c2ecf20Sopenharmony_ci {0x4b, 0x09}, 3088c2ecf20Sopenharmony_ci {0xc9, 0x60}, 3098c2ecf20Sopenharmony_ci {0x41, 0x38}, /* jfm: auto sharpness + auto de-noise */ 3108c2ecf20Sopenharmony_ci {0x56, 0x40}, 3118c2ecf20Sopenharmony_ci {0x34, 0x11}, 3128c2ecf20Sopenharmony_ci {0x3b, 0xc2}, 3138c2ecf20Sopenharmony_ci {0xa4, 0x8a}, /* Night mode trigger point */ 3148c2ecf20Sopenharmony_ci {0x96, 0x00}, 3158c2ecf20Sopenharmony_ci {0x97, 0x30}, 3168c2ecf20Sopenharmony_ci {0x98, 0x20}, 3178c2ecf20Sopenharmony_ci {0x99, 0x20}, 3188c2ecf20Sopenharmony_ci {0x9a, 0x84}, 3198c2ecf20Sopenharmony_ci {0x9b, 0x29}, 3208c2ecf20Sopenharmony_ci {0x9c, 0x03}, 3218c2ecf20Sopenharmony_ci {0x9d, 0x4c}, 3228c2ecf20Sopenharmony_ci {0x9e, 0x3f}, 3238c2ecf20Sopenharmony_ci {0x78, 0x04}, 3248c2ecf20Sopenharmony_ci {0x79, 0x01}, 3258c2ecf20Sopenharmony_ci {0xc8, 0xf0}, 3268c2ecf20Sopenharmony_ci {0x79, 0x0f}, 3278c2ecf20Sopenharmony_ci {0xc8, 0x00}, 3288c2ecf20Sopenharmony_ci {0x79, 0x10}, 3298c2ecf20Sopenharmony_ci {0xc8, 0x7e}, 3308c2ecf20Sopenharmony_ci {0x79, 0x0a}, 3318c2ecf20Sopenharmony_ci {0xc8, 0x80}, 3328c2ecf20Sopenharmony_ci {0x79, 0x0b}, 3338c2ecf20Sopenharmony_ci {0xc8, 0x01}, 3348c2ecf20Sopenharmony_ci {0x79, 0x0c}, 3358c2ecf20Sopenharmony_ci {0xc8, 0x0f}, 3368c2ecf20Sopenharmony_ci {0x79, 0x0d}, 3378c2ecf20Sopenharmony_ci {0xc8, 0x20}, 3388c2ecf20Sopenharmony_ci {0x79, 0x09}, 3398c2ecf20Sopenharmony_ci {0xc8, 0x80}, 3408c2ecf20Sopenharmony_ci {0x79, 0x02}, 3418c2ecf20Sopenharmony_ci {0xc8, 0xc0}, 3428c2ecf20Sopenharmony_ci {0x79, 0x03}, 3438c2ecf20Sopenharmony_ci {0xc8, 0x20}, 3448c2ecf20Sopenharmony_ci {0x79, 0x26}, 3458c2ecf20Sopenharmony_ci}; 3468c2ecf20Sopenharmony_cistatic const u8 bridge_start_vga_767x[][2] = { 3478c2ecf20Sopenharmony_ci/* str59 JPG */ 3488c2ecf20Sopenharmony_ci {0x94, 0xaa}, 3498c2ecf20Sopenharmony_ci {0xf1, 0x42}, 3508c2ecf20Sopenharmony_ci {0xe5, 0x04}, 3518c2ecf20Sopenharmony_ci {0xc0, 0x50}, 3528c2ecf20Sopenharmony_ci {0xc1, 0x3c}, 3538c2ecf20Sopenharmony_ci {0xc2, 0x0c}, 3548c2ecf20Sopenharmony_ci {0x35, 0x02}, /* turn on JPEG */ 3558c2ecf20Sopenharmony_ci {0xd9, 0x10}, 3568c2ecf20Sopenharmony_ci {0xda, 0x00}, /* for higher clock rate(30fps) */ 3578c2ecf20Sopenharmony_ci {0x34, 0x05}, /* enable Audio Suspend mode */ 3588c2ecf20Sopenharmony_ci {0xc3, 0xf9}, /* enable PRE */ 3598c2ecf20Sopenharmony_ci {0x8c, 0x00}, /* CIF VSize LSB[2:0] */ 3608c2ecf20Sopenharmony_ci {0x8d, 0x1c}, /* output YUV */ 3618c2ecf20Sopenharmony_ci/* {0x34, 0x05}, * enable Audio Suspend mode (?) */ 3628c2ecf20Sopenharmony_ci {0x50, 0x00}, /* H/V divider=0 */ 3638c2ecf20Sopenharmony_ci {0x51, 0xa0}, /* input H=640/4 */ 3648c2ecf20Sopenharmony_ci {0x52, 0x3c}, /* input V=480/4 */ 3658c2ecf20Sopenharmony_ci {0x53, 0x00}, /* offset X=0 */ 3668c2ecf20Sopenharmony_ci {0x54, 0x00}, /* offset Y=0 */ 3678c2ecf20Sopenharmony_ci {0x55, 0x00}, /* H/V size[8]=0 */ 3688c2ecf20Sopenharmony_ci {0x57, 0x00}, /* H-size[9]=0 */ 3698c2ecf20Sopenharmony_ci {0x5c, 0x00}, /* output size[9:8]=0 */ 3708c2ecf20Sopenharmony_ci {0x5a, 0xa0}, /* output H=640/4 */ 3718c2ecf20Sopenharmony_ci {0x5b, 0x78}, /* output V=480/4 */ 3728c2ecf20Sopenharmony_ci {0x1c, 0x0a}, 3738c2ecf20Sopenharmony_ci {0x1d, 0x0a}, 3748c2ecf20Sopenharmony_ci {0x94, 0x11}, 3758c2ecf20Sopenharmony_ci}; 3768c2ecf20Sopenharmony_cistatic const u8 sensor_start_vga_767x[][2] = { 3778c2ecf20Sopenharmony_ci {0x11, 0x01}, 3788c2ecf20Sopenharmony_ci {0x1e, 0x04}, 3798c2ecf20Sopenharmony_ci {0x19, 0x02}, 3808c2ecf20Sopenharmony_ci {0x1a, 0x7a}, 3818c2ecf20Sopenharmony_ci}; 3828c2ecf20Sopenharmony_cistatic const u8 bridge_start_qvga_767x[][2] = { 3838c2ecf20Sopenharmony_ci/* str86 JPG */ 3848c2ecf20Sopenharmony_ci {0x94, 0xaa}, 3858c2ecf20Sopenharmony_ci {0xf1, 0x42}, 3868c2ecf20Sopenharmony_ci {0xe5, 0x04}, 3878c2ecf20Sopenharmony_ci {0xc0, 0x80}, 3888c2ecf20Sopenharmony_ci {0xc1, 0x60}, 3898c2ecf20Sopenharmony_ci {0xc2, 0x0c}, 3908c2ecf20Sopenharmony_ci {0x35, 0x02}, /* turn on JPEG */ 3918c2ecf20Sopenharmony_ci {0xd9, 0x10}, 3928c2ecf20Sopenharmony_ci {0xc0, 0x50}, /* CIF HSize 640 */ 3938c2ecf20Sopenharmony_ci {0xc1, 0x3c}, /* CIF VSize 480 */ 3948c2ecf20Sopenharmony_ci {0x8c, 0x00}, /* CIF VSize LSB[2:0] */ 3958c2ecf20Sopenharmony_ci {0x8d, 0x1c}, /* output YUV */ 3968c2ecf20Sopenharmony_ci {0x34, 0x05}, /* enable Audio Suspend mode */ 3978c2ecf20Sopenharmony_ci {0xc2, 0x4c}, /* output YUV and Enable DCW */ 3988c2ecf20Sopenharmony_ci {0xc3, 0xf9}, /* enable PRE */ 3998c2ecf20Sopenharmony_ci {0x1c, 0x00}, /* indirect addressing */ 4008c2ecf20Sopenharmony_ci {0x1d, 0x48}, /* output YUV422 */ 4018c2ecf20Sopenharmony_ci {0x50, 0x89}, /* H/V divider=/2; plus DCW AVG */ 4028c2ecf20Sopenharmony_ci {0x51, 0xa0}, /* DCW input H=640/4 */ 4038c2ecf20Sopenharmony_ci {0x52, 0x78}, /* DCW input V=480/4 */ 4048c2ecf20Sopenharmony_ci {0x53, 0x00}, /* offset X=0 */ 4058c2ecf20Sopenharmony_ci {0x54, 0x00}, /* offset Y=0 */ 4068c2ecf20Sopenharmony_ci {0x55, 0x00}, /* H/V size[8]=0 */ 4078c2ecf20Sopenharmony_ci {0x57, 0x00}, /* H-size[9]=0 */ 4088c2ecf20Sopenharmony_ci {0x5c, 0x00}, /* DCW output size[9:8]=0 */ 4098c2ecf20Sopenharmony_ci {0x5a, 0x50}, /* DCW output H=320/4 */ 4108c2ecf20Sopenharmony_ci {0x5b, 0x3c}, /* DCW output V=240/4 */ 4118c2ecf20Sopenharmony_ci {0x1c, 0x0a}, 4128c2ecf20Sopenharmony_ci {0x1d, 0x0a}, 4138c2ecf20Sopenharmony_ci {0x94, 0x11}, 4148c2ecf20Sopenharmony_ci}; 4158c2ecf20Sopenharmony_cistatic const u8 sensor_start_qvga_767x[][2] = { 4168c2ecf20Sopenharmony_ci {0x11, 0x01}, 4178c2ecf20Sopenharmony_ci {0x1e, 0x04}, 4188c2ecf20Sopenharmony_ci {0x19, 0x02}, 4198c2ecf20Sopenharmony_ci {0x1a, 0x7a}, 4208c2ecf20Sopenharmony_ci}; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic const u8 bridge_init_772x[][2] = { 4238c2ecf20Sopenharmony_ci { 0x88, 0xf8 }, 4248c2ecf20Sopenharmony_ci { 0x89, 0xff }, 4258c2ecf20Sopenharmony_ci { 0x76, 0x03 }, 4268c2ecf20Sopenharmony_ci { 0x92, 0x01 }, 4278c2ecf20Sopenharmony_ci { 0x93, 0x18 }, 4288c2ecf20Sopenharmony_ci { 0x94, 0x10 }, 4298c2ecf20Sopenharmony_ci { 0x95, 0x10 }, 4308c2ecf20Sopenharmony_ci { 0xe2, 0x00 }, 4318c2ecf20Sopenharmony_ci { 0xe7, 0x3e }, 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci { 0x96, 0x00 }, 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci { 0x97, 0x20 }, 4368c2ecf20Sopenharmony_ci { 0x97, 0x20 }, 4378c2ecf20Sopenharmony_ci { 0x97, 0x20 }, 4388c2ecf20Sopenharmony_ci { 0x97, 0x0a }, 4398c2ecf20Sopenharmony_ci { 0x97, 0x3f }, 4408c2ecf20Sopenharmony_ci { 0x97, 0x4a }, 4418c2ecf20Sopenharmony_ci { 0x97, 0x20 }, 4428c2ecf20Sopenharmony_ci { 0x97, 0x15 }, 4438c2ecf20Sopenharmony_ci { 0x97, 0x0b }, 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci { 0x8e, 0x40 }, 4468c2ecf20Sopenharmony_ci { 0x1f, 0x81 }, 4478c2ecf20Sopenharmony_ci { 0x34, 0x05 }, 4488c2ecf20Sopenharmony_ci { 0xe3, 0x04 }, 4498c2ecf20Sopenharmony_ci { 0x89, 0x00 }, 4508c2ecf20Sopenharmony_ci { 0x76, 0x00 }, 4518c2ecf20Sopenharmony_ci { 0xe7, 0x2e }, 4528c2ecf20Sopenharmony_ci { 0x31, 0xf9 }, 4538c2ecf20Sopenharmony_ci { 0x25, 0x42 }, 4548c2ecf20Sopenharmony_ci { 0x21, 0xf0 }, 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci { 0x1c, 0x0a }, 4578c2ecf20Sopenharmony_ci { 0x1d, 0x08 }, /* turn on UVC header */ 4588c2ecf20Sopenharmony_ci { 0x1d, 0x0e }, /* .. */ 4598c2ecf20Sopenharmony_ci}; 4608c2ecf20Sopenharmony_cistatic const u8 sensor_init_772x[][2] = { 4618c2ecf20Sopenharmony_ci { 0x12, 0x80 }, 4628c2ecf20Sopenharmony_ci { 0x11, 0x01 }, 4638c2ecf20Sopenharmony_ci/*fixme: better have a delay?*/ 4648c2ecf20Sopenharmony_ci { 0x11, 0x01 }, 4658c2ecf20Sopenharmony_ci { 0x11, 0x01 }, 4668c2ecf20Sopenharmony_ci { 0x11, 0x01 }, 4678c2ecf20Sopenharmony_ci { 0x11, 0x01 }, 4688c2ecf20Sopenharmony_ci { 0x11, 0x01 }, 4698c2ecf20Sopenharmony_ci { 0x11, 0x01 }, 4708c2ecf20Sopenharmony_ci { 0x11, 0x01 }, 4718c2ecf20Sopenharmony_ci { 0x11, 0x01 }, 4728c2ecf20Sopenharmony_ci { 0x11, 0x01 }, 4738c2ecf20Sopenharmony_ci { 0x11, 0x01 }, 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci { 0x3d, 0x03 }, 4768c2ecf20Sopenharmony_ci { 0x17, 0x26 }, 4778c2ecf20Sopenharmony_ci { 0x18, 0xa0 }, 4788c2ecf20Sopenharmony_ci { 0x19, 0x07 }, 4798c2ecf20Sopenharmony_ci { 0x1a, 0xf0 }, 4808c2ecf20Sopenharmony_ci { 0x32, 0x00 }, 4818c2ecf20Sopenharmony_ci { 0x29, 0xa0 }, 4828c2ecf20Sopenharmony_ci { 0x2c, 0xf0 }, 4838c2ecf20Sopenharmony_ci { 0x65, 0x20 }, 4848c2ecf20Sopenharmony_ci { 0x11, 0x01 }, 4858c2ecf20Sopenharmony_ci { 0x42, 0x7f }, 4868c2ecf20Sopenharmony_ci { 0x63, 0xaa }, /* AWB - was e0 */ 4878c2ecf20Sopenharmony_ci { 0x64, 0xff }, 4888c2ecf20Sopenharmony_ci { 0x66, 0x00 }, 4898c2ecf20Sopenharmony_ci { 0x13, 0xf0 }, /* com8 */ 4908c2ecf20Sopenharmony_ci { 0x0d, 0x41 }, 4918c2ecf20Sopenharmony_ci { 0x0f, 0xc5 }, 4928c2ecf20Sopenharmony_ci { 0x14, 0x11 }, 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci { 0x22, 0x7f }, 4958c2ecf20Sopenharmony_ci { 0x23, 0x03 }, 4968c2ecf20Sopenharmony_ci { 0x24, 0x40 }, 4978c2ecf20Sopenharmony_ci { 0x25, 0x30 }, 4988c2ecf20Sopenharmony_ci { 0x26, 0xa1 }, 4998c2ecf20Sopenharmony_ci { 0x2a, 0x00 }, 5008c2ecf20Sopenharmony_ci { 0x2b, 0x00 }, 5018c2ecf20Sopenharmony_ci { 0x6b, 0xaa }, 5028c2ecf20Sopenharmony_ci { 0x13, 0xff }, /* AWB */ 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci { 0x90, 0x05 }, 5058c2ecf20Sopenharmony_ci { 0x91, 0x01 }, 5068c2ecf20Sopenharmony_ci { 0x92, 0x03 }, 5078c2ecf20Sopenharmony_ci { 0x93, 0x00 }, 5088c2ecf20Sopenharmony_ci { 0x94, 0x60 }, 5098c2ecf20Sopenharmony_ci { 0x95, 0x3c }, 5108c2ecf20Sopenharmony_ci { 0x96, 0x24 }, 5118c2ecf20Sopenharmony_ci { 0x97, 0x1e }, 5128c2ecf20Sopenharmony_ci { 0x98, 0x62 }, 5138c2ecf20Sopenharmony_ci { 0x99, 0x80 }, 5148c2ecf20Sopenharmony_ci { 0x9a, 0x1e }, 5158c2ecf20Sopenharmony_ci { 0x9b, 0x08 }, 5168c2ecf20Sopenharmony_ci { 0x9c, 0x20 }, 5178c2ecf20Sopenharmony_ci { 0x9e, 0x81 }, 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci { 0xa6, 0x07 }, 5208c2ecf20Sopenharmony_ci { 0x7e, 0x0c }, 5218c2ecf20Sopenharmony_ci { 0x7f, 0x16 }, 5228c2ecf20Sopenharmony_ci { 0x80, 0x2a }, 5238c2ecf20Sopenharmony_ci { 0x81, 0x4e }, 5248c2ecf20Sopenharmony_ci { 0x82, 0x61 }, 5258c2ecf20Sopenharmony_ci { 0x83, 0x6f }, 5268c2ecf20Sopenharmony_ci { 0x84, 0x7b }, 5278c2ecf20Sopenharmony_ci { 0x85, 0x86 }, 5288c2ecf20Sopenharmony_ci { 0x86, 0x8e }, 5298c2ecf20Sopenharmony_ci { 0x87, 0x97 }, 5308c2ecf20Sopenharmony_ci { 0x88, 0xa4 }, 5318c2ecf20Sopenharmony_ci { 0x89, 0xaf }, 5328c2ecf20Sopenharmony_ci { 0x8a, 0xc5 }, 5338c2ecf20Sopenharmony_ci { 0x8b, 0xd7 }, 5348c2ecf20Sopenharmony_ci { 0x8c, 0xe8 }, 5358c2ecf20Sopenharmony_ci { 0x8d, 0x20 }, 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci { 0x2b, 0x00 }, 5388c2ecf20Sopenharmony_ci { 0x22, 0x7f }, 5398c2ecf20Sopenharmony_ci { 0x23, 0x03 }, 5408c2ecf20Sopenharmony_ci { 0x11, 0x01 }, 5418c2ecf20Sopenharmony_ci { 0x64, 0xff }, 5428c2ecf20Sopenharmony_ci { 0x0d, 0x41 }, 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci { 0x14, 0x41 }, 5458c2ecf20Sopenharmony_ci { 0x0e, 0xcd }, 5468c2ecf20Sopenharmony_ci { 0xac, 0xbf }, 5478c2ecf20Sopenharmony_ci { 0x8e, 0x00 }, /* De-noise threshold */ 5488c2ecf20Sopenharmony_ci}; 5498c2ecf20Sopenharmony_cistatic const u8 bridge_start_vga_yuyv_772x[][2] = { 5508c2ecf20Sopenharmony_ci {0x88, 0x00}, 5518c2ecf20Sopenharmony_ci {0x1c, 0x00}, 5528c2ecf20Sopenharmony_ci {0x1d, 0x40}, 5538c2ecf20Sopenharmony_ci {0x1d, 0x02}, 5548c2ecf20Sopenharmony_ci {0x1d, 0x00}, 5558c2ecf20Sopenharmony_ci {0x1d, 0x02}, 5568c2ecf20Sopenharmony_ci {0x1d, 0x58}, 5578c2ecf20Sopenharmony_ci {0x1d, 0x00}, 5588c2ecf20Sopenharmony_ci {0x8d, 0x1c}, 5598c2ecf20Sopenharmony_ci {0x8e, 0x80}, 5608c2ecf20Sopenharmony_ci {0xc0, 0x50}, 5618c2ecf20Sopenharmony_ci {0xc1, 0x3c}, 5628c2ecf20Sopenharmony_ci {0xc2, 0x0c}, 5638c2ecf20Sopenharmony_ci {0xc3, 0x69}, 5648c2ecf20Sopenharmony_ci}; 5658c2ecf20Sopenharmony_cistatic const u8 sensor_start_vga_yuyv_772x[][2] = { 5668c2ecf20Sopenharmony_ci {0x12, 0x00}, 5678c2ecf20Sopenharmony_ci {0x17, 0x26}, 5688c2ecf20Sopenharmony_ci {0x18, 0xa0}, 5698c2ecf20Sopenharmony_ci {0x19, 0x07}, 5708c2ecf20Sopenharmony_ci {0x1a, 0xf0}, 5718c2ecf20Sopenharmony_ci {0x29, 0xa0}, 5728c2ecf20Sopenharmony_ci {0x2c, 0xf0}, 5738c2ecf20Sopenharmony_ci {0x65, 0x20}, 5748c2ecf20Sopenharmony_ci {0x67, 0x00}, 5758c2ecf20Sopenharmony_ci}; 5768c2ecf20Sopenharmony_cistatic const u8 bridge_start_qvga_yuyv_772x[][2] = { 5778c2ecf20Sopenharmony_ci {0x88, 0x00}, 5788c2ecf20Sopenharmony_ci {0x1c, 0x00}, 5798c2ecf20Sopenharmony_ci {0x1d, 0x40}, 5808c2ecf20Sopenharmony_ci {0x1d, 0x02}, 5818c2ecf20Sopenharmony_ci {0x1d, 0x00}, 5828c2ecf20Sopenharmony_ci {0x1d, 0x01}, 5838c2ecf20Sopenharmony_ci {0x1d, 0x4b}, 5848c2ecf20Sopenharmony_ci {0x1d, 0x00}, 5858c2ecf20Sopenharmony_ci {0x8d, 0x1c}, 5868c2ecf20Sopenharmony_ci {0x8e, 0x80}, 5878c2ecf20Sopenharmony_ci {0xc0, 0x28}, 5888c2ecf20Sopenharmony_ci {0xc1, 0x1e}, 5898c2ecf20Sopenharmony_ci {0xc2, 0x0c}, 5908c2ecf20Sopenharmony_ci {0xc3, 0x69}, 5918c2ecf20Sopenharmony_ci}; 5928c2ecf20Sopenharmony_cistatic const u8 sensor_start_qvga_yuyv_772x[][2] = { 5938c2ecf20Sopenharmony_ci {0x12, 0x40}, 5948c2ecf20Sopenharmony_ci {0x17, 0x3f}, 5958c2ecf20Sopenharmony_ci {0x18, 0x50}, 5968c2ecf20Sopenharmony_ci {0x19, 0x03}, 5978c2ecf20Sopenharmony_ci {0x1a, 0x78}, 5988c2ecf20Sopenharmony_ci {0x29, 0x50}, 5998c2ecf20Sopenharmony_ci {0x2c, 0x78}, 6008c2ecf20Sopenharmony_ci {0x65, 0x2f}, 6018c2ecf20Sopenharmony_ci {0x67, 0x00}, 6028c2ecf20Sopenharmony_ci}; 6038c2ecf20Sopenharmony_cistatic const u8 bridge_start_vga_gbrg_772x[][2] = { 6048c2ecf20Sopenharmony_ci {0x88, 0x08}, 6058c2ecf20Sopenharmony_ci {0x1c, 0x00}, 6068c2ecf20Sopenharmony_ci {0x1d, 0x00}, 6078c2ecf20Sopenharmony_ci {0x1d, 0x02}, 6088c2ecf20Sopenharmony_ci {0x1d, 0x00}, 6098c2ecf20Sopenharmony_ci {0x1d, 0x01}, 6108c2ecf20Sopenharmony_ci {0x1d, 0x2c}, 6118c2ecf20Sopenharmony_ci {0x1d, 0x00}, 6128c2ecf20Sopenharmony_ci {0x8d, 0x00}, 6138c2ecf20Sopenharmony_ci {0x8e, 0x00}, 6148c2ecf20Sopenharmony_ci {0xc0, 0x50}, 6158c2ecf20Sopenharmony_ci {0xc1, 0x3c}, 6168c2ecf20Sopenharmony_ci {0xc2, 0x01}, 6178c2ecf20Sopenharmony_ci {0xc3, 0x01}, 6188c2ecf20Sopenharmony_ci}; 6198c2ecf20Sopenharmony_cistatic const u8 sensor_start_vga_gbrg_772x[][2] = { 6208c2ecf20Sopenharmony_ci {0x12, 0x01}, 6218c2ecf20Sopenharmony_ci {0x17, 0x26}, 6228c2ecf20Sopenharmony_ci {0x18, 0xa0}, 6238c2ecf20Sopenharmony_ci {0x19, 0x07}, 6248c2ecf20Sopenharmony_ci {0x1a, 0xf0}, 6258c2ecf20Sopenharmony_ci {0x29, 0xa0}, 6268c2ecf20Sopenharmony_ci {0x2c, 0xf0}, 6278c2ecf20Sopenharmony_ci {0x65, 0x20}, 6288c2ecf20Sopenharmony_ci {0x67, 0x02}, 6298c2ecf20Sopenharmony_ci}; 6308c2ecf20Sopenharmony_cistatic const u8 bridge_start_qvga_gbrg_772x[][2] = { 6318c2ecf20Sopenharmony_ci {0x88, 0x08}, 6328c2ecf20Sopenharmony_ci {0x1c, 0x00}, 6338c2ecf20Sopenharmony_ci {0x1d, 0x00}, 6348c2ecf20Sopenharmony_ci {0x1d, 0x02}, 6358c2ecf20Sopenharmony_ci {0x1d, 0x00}, 6368c2ecf20Sopenharmony_ci {0x1d, 0x00}, 6378c2ecf20Sopenharmony_ci {0x1d, 0x4b}, 6388c2ecf20Sopenharmony_ci {0x1d, 0x00}, 6398c2ecf20Sopenharmony_ci {0x8d, 0x00}, 6408c2ecf20Sopenharmony_ci {0x8e, 0x00}, 6418c2ecf20Sopenharmony_ci {0xc0, 0x28}, 6428c2ecf20Sopenharmony_ci {0xc1, 0x1e}, 6438c2ecf20Sopenharmony_ci {0xc2, 0x01}, 6448c2ecf20Sopenharmony_ci {0xc3, 0x01}, 6458c2ecf20Sopenharmony_ci}; 6468c2ecf20Sopenharmony_cistatic const u8 sensor_start_qvga_gbrg_772x[][2] = { 6478c2ecf20Sopenharmony_ci {0x12, 0x41}, 6488c2ecf20Sopenharmony_ci {0x17, 0x3f}, 6498c2ecf20Sopenharmony_ci {0x18, 0x50}, 6508c2ecf20Sopenharmony_ci {0x19, 0x03}, 6518c2ecf20Sopenharmony_ci {0x1a, 0x78}, 6528c2ecf20Sopenharmony_ci {0x29, 0x50}, 6538c2ecf20Sopenharmony_ci {0x2c, 0x78}, 6548c2ecf20Sopenharmony_ci {0x65, 0x2f}, 6558c2ecf20Sopenharmony_ci {0x67, 0x02}, 6568c2ecf20Sopenharmony_ci}; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cistatic void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci struct usb_device *udev = gspca_dev->dev; 6618c2ecf20Sopenharmony_ci int ret; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci if (gspca_dev->usb_err < 0) 6648c2ecf20Sopenharmony_ci return; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_USBO, "SET 01 0000 %04x %02x\n", reg, val); 6678c2ecf20Sopenharmony_ci gspca_dev->usb_buf[0] = val; 6688c2ecf20Sopenharmony_ci ret = usb_control_msg(udev, 6698c2ecf20Sopenharmony_ci usb_sndctrlpipe(udev, 0), 6708c2ecf20Sopenharmony_ci 0x01, 6718c2ecf20Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 6728c2ecf20Sopenharmony_ci 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT); 6738c2ecf20Sopenharmony_ci if (ret < 0) { 6748c2ecf20Sopenharmony_ci pr_err("write failed %d\n", ret); 6758c2ecf20Sopenharmony_ci gspca_dev->usb_err = ret; 6768c2ecf20Sopenharmony_ci } 6778c2ecf20Sopenharmony_ci} 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_cistatic u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg) 6808c2ecf20Sopenharmony_ci{ 6818c2ecf20Sopenharmony_ci struct usb_device *udev = gspca_dev->dev; 6828c2ecf20Sopenharmony_ci int ret; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci if (gspca_dev->usb_err < 0) 6858c2ecf20Sopenharmony_ci return 0; 6868c2ecf20Sopenharmony_ci ret = usb_control_msg(udev, 6878c2ecf20Sopenharmony_ci usb_rcvctrlpipe(udev, 0), 6888c2ecf20Sopenharmony_ci 0x01, 6898c2ecf20Sopenharmony_ci USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 6908c2ecf20Sopenharmony_ci 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT); 6918c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_USBI, "GET 01 0000 %04x %02x\n", 6928c2ecf20Sopenharmony_ci reg, gspca_dev->usb_buf[0]); 6938c2ecf20Sopenharmony_ci if (ret < 0) { 6948c2ecf20Sopenharmony_ci pr_err("read failed %d\n", ret); 6958c2ecf20Sopenharmony_ci gspca_dev->usb_err = ret; 6968c2ecf20Sopenharmony_ci /* 6978c2ecf20Sopenharmony_ci * Make sure the result is zeroed to avoid uninitialized 6988c2ecf20Sopenharmony_ci * values. 6998c2ecf20Sopenharmony_ci */ 7008c2ecf20Sopenharmony_ci gspca_dev->usb_buf[0] = 0; 7018c2ecf20Sopenharmony_ci } 7028c2ecf20Sopenharmony_ci return gspca_dev->usb_buf[0]; 7038c2ecf20Sopenharmony_ci} 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci/* Two bits control LED: 0x21 bit 7 and 0x23 bit 7. 7068c2ecf20Sopenharmony_ci * (direction and output)? */ 7078c2ecf20Sopenharmony_cistatic void ov534_set_led(struct gspca_dev *gspca_dev, int status) 7088c2ecf20Sopenharmony_ci{ 7098c2ecf20Sopenharmony_ci u8 data; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_CONF, "led status: %d\n", status); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci data = ov534_reg_read(gspca_dev, 0x21); 7148c2ecf20Sopenharmony_ci data |= 0x80; 7158c2ecf20Sopenharmony_ci ov534_reg_write(gspca_dev, 0x21, data); 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci data = ov534_reg_read(gspca_dev, 0x23); 7188c2ecf20Sopenharmony_ci if (status) 7198c2ecf20Sopenharmony_ci data |= 0x80; 7208c2ecf20Sopenharmony_ci else 7218c2ecf20Sopenharmony_ci data &= ~0x80; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci ov534_reg_write(gspca_dev, 0x23, data); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci if (!status) { 7268c2ecf20Sopenharmony_ci data = ov534_reg_read(gspca_dev, 0x21); 7278c2ecf20Sopenharmony_ci data &= ~0x80; 7288c2ecf20Sopenharmony_ci ov534_reg_write(gspca_dev, 0x21, data); 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci} 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_cistatic int sccb_check_status(struct gspca_dev *gspca_dev) 7338c2ecf20Sopenharmony_ci{ 7348c2ecf20Sopenharmony_ci u8 data; 7358c2ecf20Sopenharmony_ci int i; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci for (i = 0; i < 5; i++) { 7388c2ecf20Sopenharmony_ci usleep_range(10000, 20000); 7398c2ecf20Sopenharmony_ci data = ov534_reg_read(gspca_dev, OV534_REG_STATUS); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci switch (data) { 7428c2ecf20Sopenharmony_ci case 0x00: 7438c2ecf20Sopenharmony_ci return 1; 7448c2ecf20Sopenharmony_ci case 0x04: 7458c2ecf20Sopenharmony_ci return 0; 7468c2ecf20Sopenharmony_ci case 0x03: 7478c2ecf20Sopenharmony_ci break; 7488c2ecf20Sopenharmony_ci default: 7498c2ecf20Sopenharmony_ci gspca_err(gspca_dev, "sccb status 0x%02x, attempt %d/5\n", 7508c2ecf20Sopenharmony_ci data, i + 1); 7518c2ecf20Sopenharmony_ci } 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci return 0; 7548c2ecf20Sopenharmony_ci} 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_cistatic void sccb_reg_write(struct gspca_dev *gspca_dev, u8 reg, u8 val) 7578c2ecf20Sopenharmony_ci{ 7588c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_USBO, "sccb write: %02x %02x\n", reg, val); 7598c2ecf20Sopenharmony_ci ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg); 7608c2ecf20Sopenharmony_ci ov534_reg_write(gspca_dev, OV534_REG_WRITE, val); 7618c2ecf20Sopenharmony_ci ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3); 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci if (!sccb_check_status(gspca_dev)) { 7648c2ecf20Sopenharmony_ci pr_err("sccb_reg_write failed\n"); 7658c2ecf20Sopenharmony_ci gspca_dev->usb_err = -EIO; 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci} 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_cistatic u8 sccb_reg_read(struct gspca_dev *gspca_dev, u16 reg) 7708c2ecf20Sopenharmony_ci{ 7718c2ecf20Sopenharmony_ci ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg); 7728c2ecf20Sopenharmony_ci ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_2); 7738c2ecf20Sopenharmony_ci if (!sccb_check_status(gspca_dev)) 7748c2ecf20Sopenharmony_ci pr_err("sccb_reg_read failed 1\n"); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_READ_2); 7778c2ecf20Sopenharmony_ci if (!sccb_check_status(gspca_dev)) 7788c2ecf20Sopenharmony_ci pr_err("sccb_reg_read failed 2\n"); 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci return ov534_reg_read(gspca_dev, OV534_REG_READ); 7818c2ecf20Sopenharmony_ci} 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci/* output a bridge sequence (reg - val) */ 7848c2ecf20Sopenharmony_cistatic void reg_w_array(struct gspca_dev *gspca_dev, 7858c2ecf20Sopenharmony_ci const u8 (*data)[2], int len) 7868c2ecf20Sopenharmony_ci{ 7878c2ecf20Sopenharmony_ci while (--len >= 0) { 7888c2ecf20Sopenharmony_ci ov534_reg_write(gspca_dev, (*data)[0], (*data)[1]); 7898c2ecf20Sopenharmony_ci data++; 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci} 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci/* output a sensor sequence (reg - val) */ 7948c2ecf20Sopenharmony_cistatic void sccb_w_array(struct gspca_dev *gspca_dev, 7958c2ecf20Sopenharmony_ci const u8 (*data)[2], int len) 7968c2ecf20Sopenharmony_ci{ 7978c2ecf20Sopenharmony_ci while (--len >= 0) { 7988c2ecf20Sopenharmony_ci if ((*data)[0] != 0xff) { 7998c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, (*data)[0], (*data)[1]); 8008c2ecf20Sopenharmony_ci } else { 8018c2ecf20Sopenharmony_ci sccb_reg_read(gspca_dev, (*data)[1]); 8028c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0xff, 0x00); 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_ci data++; 8058c2ecf20Sopenharmony_ci } 8068c2ecf20Sopenharmony_ci} 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci/* ov772x specific controls */ 8098c2ecf20Sopenharmony_cistatic void set_frame_rate(struct gspca_dev *gspca_dev) 8108c2ecf20Sopenharmony_ci{ 8118c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 8128c2ecf20Sopenharmony_ci int i; 8138c2ecf20Sopenharmony_ci struct rate_s { 8148c2ecf20Sopenharmony_ci u8 fps; 8158c2ecf20Sopenharmony_ci u8 r11; 8168c2ecf20Sopenharmony_ci u8 r0d; 8178c2ecf20Sopenharmony_ci u8 re5; 8188c2ecf20Sopenharmony_ci }; 8198c2ecf20Sopenharmony_ci const struct rate_s *r; 8208c2ecf20Sopenharmony_ci static const struct rate_s rate_0[] = { /* 640x480 */ 8218c2ecf20Sopenharmony_ci {60, 0x01, 0xc1, 0x04}, 8228c2ecf20Sopenharmony_ci {50, 0x01, 0x41, 0x02}, 8238c2ecf20Sopenharmony_ci {40, 0x02, 0xc1, 0x04}, 8248c2ecf20Sopenharmony_ci {30, 0x04, 0x81, 0x02}, 8258c2ecf20Sopenharmony_ci {15, 0x03, 0x41, 0x04}, 8268c2ecf20Sopenharmony_ci }; 8278c2ecf20Sopenharmony_ci static const struct rate_s rate_1[] = { /* 320x240 */ 8288c2ecf20Sopenharmony_ci/* {205, 0x01, 0xc1, 0x02}, * 205 FPS: video is partly corrupt */ 8298c2ecf20Sopenharmony_ci {187, 0x01, 0x81, 0x02}, /* 187 FPS or below: video is valid */ 8308c2ecf20Sopenharmony_ci {150, 0x01, 0xc1, 0x04}, 8318c2ecf20Sopenharmony_ci {137, 0x02, 0xc1, 0x02}, 8328c2ecf20Sopenharmony_ci {125, 0x02, 0x81, 0x02}, 8338c2ecf20Sopenharmony_ci {100, 0x02, 0xc1, 0x04}, 8348c2ecf20Sopenharmony_ci {75, 0x03, 0xc1, 0x04}, 8358c2ecf20Sopenharmony_ci {60, 0x04, 0xc1, 0x04}, 8368c2ecf20Sopenharmony_ci {50, 0x02, 0x41, 0x04}, 8378c2ecf20Sopenharmony_ci {37, 0x03, 0x41, 0x04}, 8388c2ecf20Sopenharmony_ci {30, 0x04, 0x41, 0x04}, 8398c2ecf20Sopenharmony_ci }; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci if (sd->sensor != SENSOR_OV772x) 8428c2ecf20Sopenharmony_ci return; 8438c2ecf20Sopenharmony_ci if (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv == 0) { 8448c2ecf20Sopenharmony_ci r = rate_0; 8458c2ecf20Sopenharmony_ci i = ARRAY_SIZE(rate_0); 8468c2ecf20Sopenharmony_ci } else { 8478c2ecf20Sopenharmony_ci r = rate_1; 8488c2ecf20Sopenharmony_ci i = ARRAY_SIZE(rate_1); 8498c2ecf20Sopenharmony_ci } 8508c2ecf20Sopenharmony_ci while (--i > 0) { 8518c2ecf20Sopenharmony_ci if (sd->frame_rate >= r->fps) 8528c2ecf20Sopenharmony_ci break; 8538c2ecf20Sopenharmony_ci r++; 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0x11, r->r11); 8578c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0x0d, r->r0d); 8588c2ecf20Sopenharmony_ci ov534_reg_write(gspca_dev, 0xe5, r->re5); 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_PROBE, "frame_rate: %d\n", r->fps); 8618c2ecf20Sopenharmony_ci} 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_cistatic void sethue(struct gspca_dev *gspca_dev, s32 val) 8648c2ecf20Sopenharmony_ci{ 8658c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci if (sd->sensor == SENSOR_OV767x) { 8688c2ecf20Sopenharmony_ci /* TBD */ 8698c2ecf20Sopenharmony_ci } else { 8708c2ecf20Sopenharmony_ci s16 huesin; 8718c2ecf20Sopenharmony_ci s16 huecos; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci /* According to the datasheet the registers expect HUESIN and 8748c2ecf20Sopenharmony_ci * HUECOS to be the result of the trigonometric functions, 8758c2ecf20Sopenharmony_ci * scaled by 0x80. 8768c2ecf20Sopenharmony_ci * 8778c2ecf20Sopenharmony_ci * The 0x7fff here represents the maximum absolute value 8788c2ecf20Sopenharmony_ci * returned byt fixp_sin and fixp_cos, so the scaling will 8798c2ecf20Sopenharmony_ci * consider the result like in the interval [-1.0, 1.0]. 8808c2ecf20Sopenharmony_ci */ 8818c2ecf20Sopenharmony_ci huesin = fixp_sin16(val) * 0x80 / 0x7fff; 8828c2ecf20Sopenharmony_ci huecos = fixp_cos16(val) * 0x80 / 0x7fff; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci if (huesin < 0) { 8858c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0xab, 8868c2ecf20Sopenharmony_ci sccb_reg_read(gspca_dev, 0xab) | 0x2); 8878c2ecf20Sopenharmony_ci huesin = -huesin; 8888c2ecf20Sopenharmony_ci } else { 8898c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0xab, 8908c2ecf20Sopenharmony_ci sccb_reg_read(gspca_dev, 0xab) & ~0x2); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci } 8938c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0xa9, (u8)huecos); 8948c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0xaa, (u8)huesin); 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci} 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_cistatic void setsaturation(struct gspca_dev *gspca_dev, s32 val) 8998c2ecf20Sopenharmony_ci{ 9008c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci if (sd->sensor == SENSOR_OV767x) { 9038c2ecf20Sopenharmony_ci int i; 9048c2ecf20Sopenharmony_ci static u8 color_tb[][6] = { 9058c2ecf20Sopenharmony_ci {0x42, 0x42, 0x00, 0x11, 0x30, 0x41}, 9068c2ecf20Sopenharmony_ci {0x52, 0x52, 0x00, 0x16, 0x3c, 0x52}, 9078c2ecf20Sopenharmony_ci {0x66, 0x66, 0x00, 0x1b, 0x4b, 0x66}, 9088c2ecf20Sopenharmony_ci {0x80, 0x80, 0x00, 0x22, 0x5e, 0x80}, 9098c2ecf20Sopenharmony_ci {0x9a, 0x9a, 0x00, 0x29, 0x71, 0x9a}, 9108c2ecf20Sopenharmony_ci {0xb8, 0xb8, 0x00, 0x31, 0x87, 0xb8}, 9118c2ecf20Sopenharmony_ci {0xdd, 0xdd, 0x00, 0x3b, 0xa2, 0xdd}, 9128c2ecf20Sopenharmony_ci }; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(color_tb[0]); i++) 9158c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0x4f + i, color_tb[val][i]); 9168c2ecf20Sopenharmony_ci } else { 9178c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0xa7, val); /* U saturation */ 9188c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0xa8, val); /* V saturation */ 9198c2ecf20Sopenharmony_ci } 9208c2ecf20Sopenharmony_ci} 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_cistatic void setbrightness(struct gspca_dev *gspca_dev, s32 val) 9238c2ecf20Sopenharmony_ci{ 9248c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci if (sd->sensor == SENSOR_OV767x) { 9278c2ecf20Sopenharmony_ci if (val < 0) 9288c2ecf20Sopenharmony_ci val = 0x80 - val; 9298c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0x55, val); /* bright */ 9308c2ecf20Sopenharmony_ci } else { 9318c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0x9b, val); 9328c2ecf20Sopenharmony_ci } 9338c2ecf20Sopenharmony_ci} 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_cistatic void setcontrast(struct gspca_dev *gspca_dev, s32 val) 9368c2ecf20Sopenharmony_ci{ 9378c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci if (sd->sensor == SENSOR_OV767x) 9408c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0x56, val); /* contras */ 9418c2ecf20Sopenharmony_ci else 9428c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0x9c, val); 9438c2ecf20Sopenharmony_ci} 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_cistatic void setgain(struct gspca_dev *gspca_dev, s32 val) 9468c2ecf20Sopenharmony_ci{ 9478c2ecf20Sopenharmony_ci switch (val & 0x30) { 9488c2ecf20Sopenharmony_ci case 0x00: 9498c2ecf20Sopenharmony_ci val &= 0x0f; 9508c2ecf20Sopenharmony_ci break; 9518c2ecf20Sopenharmony_ci case 0x10: 9528c2ecf20Sopenharmony_ci val &= 0x0f; 9538c2ecf20Sopenharmony_ci val |= 0x30; 9548c2ecf20Sopenharmony_ci break; 9558c2ecf20Sopenharmony_ci case 0x20: 9568c2ecf20Sopenharmony_ci val &= 0x0f; 9578c2ecf20Sopenharmony_ci val |= 0x70; 9588c2ecf20Sopenharmony_ci break; 9598c2ecf20Sopenharmony_ci default: 9608c2ecf20Sopenharmony_ci/* case 0x30: */ 9618c2ecf20Sopenharmony_ci val &= 0x0f; 9628c2ecf20Sopenharmony_ci val |= 0xf0; 9638c2ecf20Sopenharmony_ci break; 9648c2ecf20Sopenharmony_ci } 9658c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0x00, val); 9668c2ecf20Sopenharmony_ci} 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_cistatic s32 getgain(struct gspca_dev *gspca_dev) 9698c2ecf20Sopenharmony_ci{ 9708c2ecf20Sopenharmony_ci return sccb_reg_read(gspca_dev, 0x00); 9718c2ecf20Sopenharmony_ci} 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_cistatic void setexposure(struct gspca_dev *gspca_dev, s32 val) 9748c2ecf20Sopenharmony_ci{ 9758c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci if (sd->sensor == SENSOR_OV767x) { 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci /* set only aec[9:2] */ 9808c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0x10, val); /* aech */ 9818c2ecf20Sopenharmony_ci } else { 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci /* 'val' is one byte and represents half of the exposure value 9848c2ecf20Sopenharmony_ci * we are going to set into registers, a two bytes value: 9858c2ecf20Sopenharmony_ci * 9868c2ecf20Sopenharmony_ci * MSB: ((u16) val << 1) >> 8 == val >> 7 9878c2ecf20Sopenharmony_ci * LSB: ((u16) val << 1) & 0xff == val << 1 9888c2ecf20Sopenharmony_ci */ 9898c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0x08, val >> 7); 9908c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0x10, val << 1); 9918c2ecf20Sopenharmony_ci } 9928c2ecf20Sopenharmony_ci} 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_cistatic s32 getexposure(struct gspca_dev *gspca_dev) 9958c2ecf20Sopenharmony_ci{ 9968c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci if (sd->sensor == SENSOR_OV767x) { 9998c2ecf20Sopenharmony_ci /* get only aec[9:2] */ 10008c2ecf20Sopenharmony_ci return sccb_reg_read(gspca_dev, 0x10); /* aech */ 10018c2ecf20Sopenharmony_ci } else { 10028c2ecf20Sopenharmony_ci u8 hi = sccb_reg_read(gspca_dev, 0x08); 10038c2ecf20Sopenharmony_ci u8 lo = sccb_reg_read(gspca_dev, 0x10); 10048c2ecf20Sopenharmony_ci return (hi << 8 | lo) >> 1; 10058c2ecf20Sopenharmony_ci } 10068c2ecf20Sopenharmony_ci} 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_cistatic void setagc(struct gspca_dev *gspca_dev, s32 val) 10098c2ecf20Sopenharmony_ci{ 10108c2ecf20Sopenharmony_ci if (val) { 10118c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0x13, 10128c2ecf20Sopenharmony_ci sccb_reg_read(gspca_dev, 0x13) | 0x04); 10138c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0x64, 10148c2ecf20Sopenharmony_ci sccb_reg_read(gspca_dev, 0x64) | 0x03); 10158c2ecf20Sopenharmony_ci } else { 10168c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0x13, 10178c2ecf20Sopenharmony_ci sccb_reg_read(gspca_dev, 0x13) & ~0x04); 10188c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0x64, 10198c2ecf20Sopenharmony_ci sccb_reg_read(gspca_dev, 0x64) & ~0x03); 10208c2ecf20Sopenharmony_ci } 10218c2ecf20Sopenharmony_ci} 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_cistatic void setawb(struct gspca_dev *gspca_dev, s32 val) 10248c2ecf20Sopenharmony_ci{ 10258c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci if (val) { 10288c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0x13, 10298c2ecf20Sopenharmony_ci sccb_reg_read(gspca_dev, 0x13) | 0x02); 10308c2ecf20Sopenharmony_ci if (sd->sensor == SENSOR_OV772x) 10318c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0x63, 10328c2ecf20Sopenharmony_ci sccb_reg_read(gspca_dev, 0x63) | 0xc0); 10338c2ecf20Sopenharmony_ci } else { 10348c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0x13, 10358c2ecf20Sopenharmony_ci sccb_reg_read(gspca_dev, 0x13) & ~0x02); 10368c2ecf20Sopenharmony_ci if (sd->sensor == SENSOR_OV772x) 10378c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0x63, 10388c2ecf20Sopenharmony_ci sccb_reg_read(gspca_dev, 0x63) & ~0xc0); 10398c2ecf20Sopenharmony_ci } 10408c2ecf20Sopenharmony_ci} 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_cistatic void setaec(struct gspca_dev *gspca_dev, s32 val) 10438c2ecf20Sopenharmony_ci{ 10448c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 10458c2ecf20Sopenharmony_ci u8 data; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci data = sd->sensor == SENSOR_OV767x ? 10488c2ecf20Sopenharmony_ci 0x05 : /* agc + aec */ 10498c2ecf20Sopenharmony_ci 0x01; /* agc */ 10508c2ecf20Sopenharmony_ci switch (val) { 10518c2ecf20Sopenharmony_ci case V4L2_EXPOSURE_AUTO: 10528c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0x13, 10538c2ecf20Sopenharmony_ci sccb_reg_read(gspca_dev, 0x13) | data); 10548c2ecf20Sopenharmony_ci break; 10558c2ecf20Sopenharmony_ci case V4L2_EXPOSURE_MANUAL: 10568c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0x13, 10578c2ecf20Sopenharmony_ci sccb_reg_read(gspca_dev, 0x13) & ~data); 10588c2ecf20Sopenharmony_ci break; 10598c2ecf20Sopenharmony_ci } 10608c2ecf20Sopenharmony_ci} 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_cistatic void setsharpness(struct gspca_dev *gspca_dev, s32 val) 10638c2ecf20Sopenharmony_ci{ 10648c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0x91, val); /* Auto de-noise threshold */ 10658c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0x8e, val); /* De-noise threshold */ 10668c2ecf20Sopenharmony_ci} 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_cistatic void sethvflip(struct gspca_dev *gspca_dev, s32 hflip, s32 vflip) 10698c2ecf20Sopenharmony_ci{ 10708c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 10718c2ecf20Sopenharmony_ci u8 val; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci if (sd->sensor == SENSOR_OV767x) { 10748c2ecf20Sopenharmony_ci val = sccb_reg_read(gspca_dev, 0x1e); /* mvfp */ 10758c2ecf20Sopenharmony_ci val &= ~0x30; 10768c2ecf20Sopenharmony_ci if (hflip) 10778c2ecf20Sopenharmony_ci val |= 0x20; 10788c2ecf20Sopenharmony_ci if (vflip) 10798c2ecf20Sopenharmony_ci val |= 0x10; 10808c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0x1e, val); 10818c2ecf20Sopenharmony_ci } else { 10828c2ecf20Sopenharmony_ci val = sccb_reg_read(gspca_dev, 0x0c); 10838c2ecf20Sopenharmony_ci val &= ~0xc0; 10848c2ecf20Sopenharmony_ci if (hflip == 0) 10858c2ecf20Sopenharmony_ci val |= 0x40; 10868c2ecf20Sopenharmony_ci if (vflip == 0) 10878c2ecf20Sopenharmony_ci val |= 0x80; 10888c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0x0c, val); 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci} 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_cistatic void setlightfreq(struct gspca_dev *gspca_dev, s32 val) 10938c2ecf20Sopenharmony_ci{ 10948c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci val = val ? 0x9e : 0x00; 10978c2ecf20Sopenharmony_ci if (sd->sensor == SENSOR_OV767x) { 10988c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0x2a, 0x00); 10998c2ecf20Sopenharmony_ci if (val) 11008c2ecf20Sopenharmony_ci val = 0x9d; /* insert dummy to 25fps for 50Hz */ 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0x2b, val); 11038c2ecf20Sopenharmony_ci} 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci/* this function is called at probe time */ 11078c2ecf20Sopenharmony_cistatic int sd_config(struct gspca_dev *gspca_dev, 11088c2ecf20Sopenharmony_ci const struct usb_device_id *id) 11098c2ecf20Sopenharmony_ci{ 11108c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 11118c2ecf20Sopenharmony_ci struct cam *cam; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci cam = &gspca_dev->cam; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci cam->cam_mode = ov772x_mode; 11168c2ecf20Sopenharmony_ci cam->nmodes = ARRAY_SIZE(ov772x_mode); 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci sd->frame_rate = DEFAULT_FRAME_RATE; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci return 0; 11218c2ecf20Sopenharmony_ci} 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_cistatic int ov534_g_volatile_ctrl(struct v4l2_ctrl *ctrl) 11248c2ecf20Sopenharmony_ci{ 11258c2ecf20Sopenharmony_ci struct sd *sd = container_of(ctrl->handler, struct sd, ctrl_handler); 11268c2ecf20Sopenharmony_ci struct gspca_dev *gspca_dev = &sd->gspca_dev; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci switch (ctrl->id) { 11298c2ecf20Sopenharmony_ci case V4L2_CID_AUTOGAIN: 11308c2ecf20Sopenharmony_ci gspca_dev->usb_err = 0; 11318c2ecf20Sopenharmony_ci if (ctrl->val && sd->gain && gspca_dev->streaming) 11328c2ecf20Sopenharmony_ci sd->gain->val = getgain(gspca_dev); 11338c2ecf20Sopenharmony_ci return gspca_dev->usb_err; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci case V4L2_CID_EXPOSURE_AUTO: 11368c2ecf20Sopenharmony_ci gspca_dev->usb_err = 0; 11378c2ecf20Sopenharmony_ci if (ctrl->val == V4L2_EXPOSURE_AUTO && sd->exposure && 11388c2ecf20Sopenharmony_ci gspca_dev->streaming) 11398c2ecf20Sopenharmony_ci sd->exposure->val = getexposure(gspca_dev); 11408c2ecf20Sopenharmony_ci return gspca_dev->usb_err; 11418c2ecf20Sopenharmony_ci } 11428c2ecf20Sopenharmony_ci return -EINVAL; 11438c2ecf20Sopenharmony_ci} 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_cistatic int ov534_s_ctrl(struct v4l2_ctrl *ctrl) 11468c2ecf20Sopenharmony_ci{ 11478c2ecf20Sopenharmony_ci struct sd *sd = container_of(ctrl->handler, struct sd, ctrl_handler); 11488c2ecf20Sopenharmony_ci struct gspca_dev *gspca_dev = &sd->gspca_dev; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci gspca_dev->usb_err = 0; 11518c2ecf20Sopenharmony_ci if (!gspca_dev->streaming) 11528c2ecf20Sopenharmony_ci return 0; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci switch (ctrl->id) { 11558c2ecf20Sopenharmony_ci case V4L2_CID_HUE: 11568c2ecf20Sopenharmony_ci sethue(gspca_dev, ctrl->val); 11578c2ecf20Sopenharmony_ci break; 11588c2ecf20Sopenharmony_ci case V4L2_CID_SATURATION: 11598c2ecf20Sopenharmony_ci setsaturation(gspca_dev, ctrl->val); 11608c2ecf20Sopenharmony_ci break; 11618c2ecf20Sopenharmony_ci case V4L2_CID_BRIGHTNESS: 11628c2ecf20Sopenharmony_ci setbrightness(gspca_dev, ctrl->val); 11638c2ecf20Sopenharmony_ci break; 11648c2ecf20Sopenharmony_ci case V4L2_CID_CONTRAST: 11658c2ecf20Sopenharmony_ci setcontrast(gspca_dev, ctrl->val); 11668c2ecf20Sopenharmony_ci break; 11678c2ecf20Sopenharmony_ci case V4L2_CID_AUTOGAIN: 11688c2ecf20Sopenharmony_ci /* case V4L2_CID_GAIN: */ 11698c2ecf20Sopenharmony_ci setagc(gspca_dev, ctrl->val); 11708c2ecf20Sopenharmony_ci if (!gspca_dev->usb_err && !ctrl->val && sd->gain) 11718c2ecf20Sopenharmony_ci setgain(gspca_dev, sd->gain->val); 11728c2ecf20Sopenharmony_ci break; 11738c2ecf20Sopenharmony_ci case V4L2_CID_AUTO_WHITE_BALANCE: 11748c2ecf20Sopenharmony_ci setawb(gspca_dev, ctrl->val); 11758c2ecf20Sopenharmony_ci break; 11768c2ecf20Sopenharmony_ci case V4L2_CID_EXPOSURE_AUTO: 11778c2ecf20Sopenharmony_ci /* case V4L2_CID_EXPOSURE: */ 11788c2ecf20Sopenharmony_ci setaec(gspca_dev, ctrl->val); 11798c2ecf20Sopenharmony_ci if (!gspca_dev->usb_err && ctrl->val == V4L2_EXPOSURE_MANUAL && 11808c2ecf20Sopenharmony_ci sd->exposure) 11818c2ecf20Sopenharmony_ci setexposure(gspca_dev, sd->exposure->val); 11828c2ecf20Sopenharmony_ci break; 11838c2ecf20Sopenharmony_ci case V4L2_CID_SHARPNESS: 11848c2ecf20Sopenharmony_ci setsharpness(gspca_dev, ctrl->val); 11858c2ecf20Sopenharmony_ci break; 11868c2ecf20Sopenharmony_ci case V4L2_CID_HFLIP: 11878c2ecf20Sopenharmony_ci sethvflip(gspca_dev, ctrl->val, sd->vflip->val); 11888c2ecf20Sopenharmony_ci break; 11898c2ecf20Sopenharmony_ci case V4L2_CID_VFLIP: 11908c2ecf20Sopenharmony_ci sethvflip(gspca_dev, sd->hflip->val, ctrl->val); 11918c2ecf20Sopenharmony_ci break; 11928c2ecf20Sopenharmony_ci case V4L2_CID_POWER_LINE_FREQUENCY: 11938c2ecf20Sopenharmony_ci setlightfreq(gspca_dev, ctrl->val); 11948c2ecf20Sopenharmony_ci break; 11958c2ecf20Sopenharmony_ci } 11968c2ecf20Sopenharmony_ci return gspca_dev->usb_err; 11978c2ecf20Sopenharmony_ci} 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops ov534_ctrl_ops = { 12008c2ecf20Sopenharmony_ci .g_volatile_ctrl = ov534_g_volatile_ctrl, 12018c2ecf20Sopenharmony_ci .s_ctrl = ov534_s_ctrl, 12028c2ecf20Sopenharmony_ci}; 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_cistatic int sd_init_controls(struct gspca_dev *gspca_dev) 12058c2ecf20Sopenharmony_ci{ 12068c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 12078c2ecf20Sopenharmony_ci struct v4l2_ctrl_handler *hdl = &sd->ctrl_handler; 12088c2ecf20Sopenharmony_ci /* parameters with different values between the supported sensors */ 12098c2ecf20Sopenharmony_ci int saturation_min; 12108c2ecf20Sopenharmony_ci int saturation_max; 12118c2ecf20Sopenharmony_ci int saturation_def; 12128c2ecf20Sopenharmony_ci int brightness_min; 12138c2ecf20Sopenharmony_ci int brightness_max; 12148c2ecf20Sopenharmony_ci int brightness_def; 12158c2ecf20Sopenharmony_ci int contrast_max; 12168c2ecf20Sopenharmony_ci int contrast_def; 12178c2ecf20Sopenharmony_ci int exposure_min; 12188c2ecf20Sopenharmony_ci int exposure_max; 12198c2ecf20Sopenharmony_ci int exposure_def; 12208c2ecf20Sopenharmony_ci int hflip_def; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci if (sd->sensor == SENSOR_OV767x) { 12238c2ecf20Sopenharmony_ci saturation_min = 0, 12248c2ecf20Sopenharmony_ci saturation_max = 6, 12258c2ecf20Sopenharmony_ci saturation_def = 3, 12268c2ecf20Sopenharmony_ci brightness_min = -127; 12278c2ecf20Sopenharmony_ci brightness_max = 127; 12288c2ecf20Sopenharmony_ci brightness_def = 0; 12298c2ecf20Sopenharmony_ci contrast_max = 0x80; 12308c2ecf20Sopenharmony_ci contrast_def = 0x40; 12318c2ecf20Sopenharmony_ci exposure_min = 0x08; 12328c2ecf20Sopenharmony_ci exposure_max = 0x60; 12338c2ecf20Sopenharmony_ci exposure_def = 0x13; 12348c2ecf20Sopenharmony_ci hflip_def = 1; 12358c2ecf20Sopenharmony_ci } else { 12368c2ecf20Sopenharmony_ci saturation_min = 0, 12378c2ecf20Sopenharmony_ci saturation_max = 255, 12388c2ecf20Sopenharmony_ci saturation_def = 64, 12398c2ecf20Sopenharmony_ci brightness_min = 0; 12408c2ecf20Sopenharmony_ci brightness_max = 255; 12418c2ecf20Sopenharmony_ci brightness_def = 0; 12428c2ecf20Sopenharmony_ci contrast_max = 255; 12438c2ecf20Sopenharmony_ci contrast_def = 32; 12448c2ecf20Sopenharmony_ci exposure_min = 0; 12458c2ecf20Sopenharmony_ci exposure_max = 255; 12468c2ecf20Sopenharmony_ci exposure_def = 120; 12478c2ecf20Sopenharmony_ci hflip_def = 0; 12488c2ecf20Sopenharmony_ci } 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci gspca_dev->vdev.ctrl_handler = hdl; 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci v4l2_ctrl_handler_init(hdl, 13); 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci if (sd->sensor == SENSOR_OV772x) 12558c2ecf20Sopenharmony_ci sd->hue = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, 12568c2ecf20Sopenharmony_ci V4L2_CID_HUE, -90, 90, 1, 0); 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci sd->saturation = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, 12598c2ecf20Sopenharmony_ci V4L2_CID_SATURATION, saturation_min, saturation_max, 1, 12608c2ecf20Sopenharmony_ci saturation_def); 12618c2ecf20Sopenharmony_ci sd->brightness = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, 12628c2ecf20Sopenharmony_ci V4L2_CID_BRIGHTNESS, brightness_min, brightness_max, 1, 12638c2ecf20Sopenharmony_ci brightness_def); 12648c2ecf20Sopenharmony_ci sd->contrast = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, 12658c2ecf20Sopenharmony_ci V4L2_CID_CONTRAST, 0, contrast_max, 1, contrast_def); 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci if (sd->sensor == SENSOR_OV772x) { 12688c2ecf20Sopenharmony_ci sd->autogain = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, 12698c2ecf20Sopenharmony_ci V4L2_CID_AUTOGAIN, 0, 1, 1, 1); 12708c2ecf20Sopenharmony_ci sd->gain = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, 12718c2ecf20Sopenharmony_ci V4L2_CID_GAIN, 0, 63, 1, 20); 12728c2ecf20Sopenharmony_ci } 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci sd->autoexposure = v4l2_ctrl_new_std_menu(hdl, &ov534_ctrl_ops, 12758c2ecf20Sopenharmony_ci V4L2_CID_EXPOSURE_AUTO, 12768c2ecf20Sopenharmony_ci V4L2_EXPOSURE_MANUAL, 0, 12778c2ecf20Sopenharmony_ci V4L2_EXPOSURE_AUTO); 12788c2ecf20Sopenharmony_ci sd->exposure = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, 12798c2ecf20Sopenharmony_ci V4L2_CID_EXPOSURE, exposure_min, exposure_max, 1, 12808c2ecf20Sopenharmony_ci exposure_def); 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci sd->autowhitebalance = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, 12838c2ecf20Sopenharmony_ci V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci if (sd->sensor == SENSOR_OV772x) 12868c2ecf20Sopenharmony_ci sd->sharpness = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, 12878c2ecf20Sopenharmony_ci V4L2_CID_SHARPNESS, 0, 63, 1, 0); 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci sd->hflip = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, 12908c2ecf20Sopenharmony_ci V4L2_CID_HFLIP, 0, 1, 1, hflip_def); 12918c2ecf20Sopenharmony_ci sd->vflip = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, 12928c2ecf20Sopenharmony_ci V4L2_CID_VFLIP, 0, 1, 1, 0); 12938c2ecf20Sopenharmony_ci sd->plfreq = v4l2_ctrl_new_std_menu(hdl, &ov534_ctrl_ops, 12948c2ecf20Sopenharmony_ci V4L2_CID_POWER_LINE_FREQUENCY, 12958c2ecf20Sopenharmony_ci V4L2_CID_POWER_LINE_FREQUENCY_50HZ, 0, 12968c2ecf20Sopenharmony_ci V4L2_CID_POWER_LINE_FREQUENCY_DISABLED); 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci if (hdl->error) { 12998c2ecf20Sopenharmony_ci pr_err("Could not initialize controls\n"); 13008c2ecf20Sopenharmony_ci return hdl->error; 13018c2ecf20Sopenharmony_ci } 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci if (sd->sensor == SENSOR_OV772x) 13048c2ecf20Sopenharmony_ci v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, true); 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci v4l2_ctrl_auto_cluster(2, &sd->autoexposure, V4L2_EXPOSURE_MANUAL, 13078c2ecf20Sopenharmony_ci true); 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci return 0; 13108c2ecf20Sopenharmony_ci} 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci/* this function is called at probe and resume time */ 13138c2ecf20Sopenharmony_cistatic int sd_init(struct gspca_dev *gspca_dev) 13148c2ecf20Sopenharmony_ci{ 13158c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 13168c2ecf20Sopenharmony_ci u16 sensor_id; 13178c2ecf20Sopenharmony_ci static const struct reg_array bridge_init[NSENSORS] = { 13188c2ecf20Sopenharmony_ci [SENSOR_OV767x] = {bridge_init_767x, ARRAY_SIZE(bridge_init_767x)}, 13198c2ecf20Sopenharmony_ci [SENSOR_OV772x] = {bridge_init_772x, ARRAY_SIZE(bridge_init_772x)}, 13208c2ecf20Sopenharmony_ci }; 13218c2ecf20Sopenharmony_ci static const struct reg_array sensor_init[NSENSORS] = { 13228c2ecf20Sopenharmony_ci [SENSOR_OV767x] = {sensor_init_767x, ARRAY_SIZE(sensor_init_767x)}, 13238c2ecf20Sopenharmony_ci [SENSOR_OV772x] = {sensor_init_772x, ARRAY_SIZE(sensor_init_772x)}, 13248c2ecf20Sopenharmony_ci }; 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci /* reset bridge */ 13278c2ecf20Sopenharmony_ci ov534_reg_write(gspca_dev, 0xe7, 0x3a); 13288c2ecf20Sopenharmony_ci ov534_reg_write(gspca_dev, 0xe0, 0x08); 13298c2ecf20Sopenharmony_ci msleep(100); 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci /* initialize the sensor address */ 13328c2ecf20Sopenharmony_ci ov534_reg_write(gspca_dev, OV534_REG_ADDRESS, 0x42); 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci /* reset sensor */ 13358c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0x12, 0x80); 13368c2ecf20Sopenharmony_ci usleep_range(10000, 20000); 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci /* probe the sensor */ 13398c2ecf20Sopenharmony_ci sccb_reg_read(gspca_dev, 0x0a); 13408c2ecf20Sopenharmony_ci sensor_id = sccb_reg_read(gspca_dev, 0x0a) << 8; 13418c2ecf20Sopenharmony_ci sccb_reg_read(gspca_dev, 0x0b); 13428c2ecf20Sopenharmony_ci sensor_id |= sccb_reg_read(gspca_dev, 0x0b); 13438c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_PROBE, "Sensor ID: %04x\n", sensor_id); 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci if ((sensor_id & 0xfff0) == 0x7670) { 13468c2ecf20Sopenharmony_ci sd->sensor = SENSOR_OV767x; 13478c2ecf20Sopenharmony_ci gspca_dev->cam.cam_mode = ov767x_mode; 13488c2ecf20Sopenharmony_ci gspca_dev->cam.nmodes = ARRAY_SIZE(ov767x_mode); 13498c2ecf20Sopenharmony_ci } else { 13508c2ecf20Sopenharmony_ci sd->sensor = SENSOR_OV772x; 13518c2ecf20Sopenharmony_ci gspca_dev->cam.bulk = 1; 13528c2ecf20Sopenharmony_ci gspca_dev->cam.bulk_size = 16384; 13538c2ecf20Sopenharmony_ci gspca_dev->cam.bulk_nurbs = 2; 13548c2ecf20Sopenharmony_ci gspca_dev->cam.mode_framerates = ov772x_framerates; 13558c2ecf20Sopenharmony_ci } 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci /* initialize */ 13588c2ecf20Sopenharmony_ci reg_w_array(gspca_dev, bridge_init[sd->sensor].val, 13598c2ecf20Sopenharmony_ci bridge_init[sd->sensor].len); 13608c2ecf20Sopenharmony_ci ov534_set_led(gspca_dev, 1); 13618c2ecf20Sopenharmony_ci sccb_w_array(gspca_dev, sensor_init[sd->sensor].val, 13628c2ecf20Sopenharmony_ci sensor_init[sd->sensor].len); 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci sd_stopN(gspca_dev); 13658c2ecf20Sopenharmony_ci/* set_frame_rate(gspca_dev); */ 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci return gspca_dev->usb_err; 13688c2ecf20Sopenharmony_ci} 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_cistatic int sd_start(struct gspca_dev *gspca_dev) 13718c2ecf20Sopenharmony_ci{ 13728c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 13738c2ecf20Sopenharmony_ci int mode; 13748c2ecf20Sopenharmony_ci static const struct reg_array bridge_start[NSENSORS][4] = { 13758c2ecf20Sopenharmony_ci [SENSOR_OV767x] = {{bridge_start_qvga_767x, 13768c2ecf20Sopenharmony_ci ARRAY_SIZE(bridge_start_qvga_767x)}, 13778c2ecf20Sopenharmony_ci {bridge_start_vga_767x, 13788c2ecf20Sopenharmony_ci ARRAY_SIZE(bridge_start_vga_767x)}}, 13798c2ecf20Sopenharmony_ci [SENSOR_OV772x] = {{bridge_start_qvga_yuyv_772x, 13808c2ecf20Sopenharmony_ci ARRAY_SIZE(bridge_start_qvga_yuyv_772x)}, 13818c2ecf20Sopenharmony_ci {bridge_start_vga_yuyv_772x, 13828c2ecf20Sopenharmony_ci ARRAY_SIZE(bridge_start_vga_yuyv_772x)}, 13838c2ecf20Sopenharmony_ci {bridge_start_qvga_gbrg_772x, 13848c2ecf20Sopenharmony_ci ARRAY_SIZE(bridge_start_qvga_gbrg_772x)}, 13858c2ecf20Sopenharmony_ci {bridge_start_vga_gbrg_772x, 13868c2ecf20Sopenharmony_ci ARRAY_SIZE(bridge_start_vga_gbrg_772x)} }, 13878c2ecf20Sopenharmony_ci }; 13888c2ecf20Sopenharmony_ci static const struct reg_array sensor_start[NSENSORS][4] = { 13898c2ecf20Sopenharmony_ci [SENSOR_OV767x] = {{sensor_start_qvga_767x, 13908c2ecf20Sopenharmony_ci ARRAY_SIZE(sensor_start_qvga_767x)}, 13918c2ecf20Sopenharmony_ci {sensor_start_vga_767x, 13928c2ecf20Sopenharmony_ci ARRAY_SIZE(sensor_start_vga_767x)}}, 13938c2ecf20Sopenharmony_ci [SENSOR_OV772x] = {{sensor_start_qvga_yuyv_772x, 13948c2ecf20Sopenharmony_ci ARRAY_SIZE(sensor_start_qvga_yuyv_772x)}, 13958c2ecf20Sopenharmony_ci {sensor_start_vga_yuyv_772x, 13968c2ecf20Sopenharmony_ci ARRAY_SIZE(sensor_start_vga_yuyv_772x)}, 13978c2ecf20Sopenharmony_ci {sensor_start_qvga_gbrg_772x, 13988c2ecf20Sopenharmony_ci ARRAY_SIZE(sensor_start_qvga_gbrg_772x)}, 13998c2ecf20Sopenharmony_ci {sensor_start_vga_gbrg_772x, 14008c2ecf20Sopenharmony_ci ARRAY_SIZE(sensor_start_vga_gbrg_772x)} }, 14018c2ecf20Sopenharmony_ci }; 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci /* (from ms-win trace) */ 14048c2ecf20Sopenharmony_ci if (sd->sensor == SENSOR_OV767x) 14058c2ecf20Sopenharmony_ci sccb_reg_write(gspca_dev, 0x1e, 0x04); 14068c2ecf20Sopenharmony_ci /* black sun enable ? */ 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci mode = gspca_dev->curr_mode; /* 0: 320x240, 1: 640x480 */ 14098c2ecf20Sopenharmony_ci reg_w_array(gspca_dev, bridge_start[sd->sensor][mode].val, 14108c2ecf20Sopenharmony_ci bridge_start[sd->sensor][mode].len); 14118c2ecf20Sopenharmony_ci sccb_w_array(gspca_dev, sensor_start[sd->sensor][mode].val, 14128c2ecf20Sopenharmony_ci sensor_start[sd->sensor][mode].len); 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci set_frame_rate(gspca_dev); 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci if (sd->hue) 14178c2ecf20Sopenharmony_ci sethue(gspca_dev, v4l2_ctrl_g_ctrl(sd->hue)); 14188c2ecf20Sopenharmony_ci setsaturation(gspca_dev, v4l2_ctrl_g_ctrl(sd->saturation)); 14198c2ecf20Sopenharmony_ci if (sd->autogain) 14208c2ecf20Sopenharmony_ci setagc(gspca_dev, v4l2_ctrl_g_ctrl(sd->autogain)); 14218c2ecf20Sopenharmony_ci setawb(gspca_dev, v4l2_ctrl_g_ctrl(sd->autowhitebalance)); 14228c2ecf20Sopenharmony_ci setaec(gspca_dev, v4l2_ctrl_g_ctrl(sd->autoexposure)); 14238c2ecf20Sopenharmony_ci if (sd->gain) 14248c2ecf20Sopenharmony_ci setgain(gspca_dev, v4l2_ctrl_g_ctrl(sd->gain)); 14258c2ecf20Sopenharmony_ci setexposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure)); 14268c2ecf20Sopenharmony_ci setbrightness(gspca_dev, v4l2_ctrl_g_ctrl(sd->brightness)); 14278c2ecf20Sopenharmony_ci setcontrast(gspca_dev, v4l2_ctrl_g_ctrl(sd->contrast)); 14288c2ecf20Sopenharmony_ci if (sd->sharpness) 14298c2ecf20Sopenharmony_ci setsharpness(gspca_dev, v4l2_ctrl_g_ctrl(sd->sharpness)); 14308c2ecf20Sopenharmony_ci sethvflip(gspca_dev, v4l2_ctrl_g_ctrl(sd->hflip), 14318c2ecf20Sopenharmony_ci v4l2_ctrl_g_ctrl(sd->vflip)); 14328c2ecf20Sopenharmony_ci setlightfreq(gspca_dev, v4l2_ctrl_g_ctrl(sd->plfreq)); 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci ov534_set_led(gspca_dev, 1); 14358c2ecf20Sopenharmony_ci ov534_reg_write(gspca_dev, 0xe0, 0x00); 14368c2ecf20Sopenharmony_ci return gspca_dev->usb_err; 14378c2ecf20Sopenharmony_ci} 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_cistatic void sd_stopN(struct gspca_dev *gspca_dev) 14408c2ecf20Sopenharmony_ci{ 14418c2ecf20Sopenharmony_ci ov534_reg_write(gspca_dev, 0xe0, 0x09); 14428c2ecf20Sopenharmony_ci ov534_set_led(gspca_dev, 0); 14438c2ecf20Sopenharmony_ci} 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */ 14468c2ecf20Sopenharmony_ci#define UVC_STREAM_EOH (1 << 7) 14478c2ecf20Sopenharmony_ci#define UVC_STREAM_ERR (1 << 6) 14488c2ecf20Sopenharmony_ci#define UVC_STREAM_STI (1 << 5) 14498c2ecf20Sopenharmony_ci#define UVC_STREAM_RES (1 << 4) 14508c2ecf20Sopenharmony_ci#define UVC_STREAM_SCR (1 << 3) 14518c2ecf20Sopenharmony_ci#define UVC_STREAM_PTS (1 << 2) 14528c2ecf20Sopenharmony_ci#define UVC_STREAM_EOF (1 << 1) 14538c2ecf20Sopenharmony_ci#define UVC_STREAM_FID (1 << 0) 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_cistatic void sd_pkt_scan(struct gspca_dev *gspca_dev, 14568c2ecf20Sopenharmony_ci u8 *data, int len) 14578c2ecf20Sopenharmony_ci{ 14588c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 14598c2ecf20Sopenharmony_ci __u32 this_pts; 14608c2ecf20Sopenharmony_ci u16 this_fid; 14618c2ecf20Sopenharmony_ci int remaining_len = len; 14628c2ecf20Sopenharmony_ci int payload_len; 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci payload_len = gspca_dev->cam.bulk ? 2048 : 2040; 14658c2ecf20Sopenharmony_ci do { 14668c2ecf20Sopenharmony_ci len = min(remaining_len, payload_len); 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci /* Payloads are prefixed with a UVC-style header. We 14698c2ecf20Sopenharmony_ci consider a frame to start when the FID toggles, or the PTS 14708c2ecf20Sopenharmony_ci changes. A frame ends when EOF is set, and we've received 14718c2ecf20Sopenharmony_ci the correct number of bytes. */ 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci /* Verify UVC header. Header length is always 12 */ 14748c2ecf20Sopenharmony_ci if (data[0] != 12 || len < 12) { 14758c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_PACK, "bad header\n"); 14768c2ecf20Sopenharmony_ci goto discard; 14778c2ecf20Sopenharmony_ci } 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci /* Check errors */ 14808c2ecf20Sopenharmony_ci if (data[1] & UVC_STREAM_ERR) { 14818c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_PACK, "payload error\n"); 14828c2ecf20Sopenharmony_ci goto discard; 14838c2ecf20Sopenharmony_ci } 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci /* Extract PTS and FID */ 14868c2ecf20Sopenharmony_ci if (!(data[1] & UVC_STREAM_PTS)) { 14878c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_PACK, "PTS not present\n"); 14888c2ecf20Sopenharmony_ci goto discard; 14898c2ecf20Sopenharmony_ci } 14908c2ecf20Sopenharmony_ci this_pts = (data[5] << 24) | (data[4] << 16) 14918c2ecf20Sopenharmony_ci | (data[3] << 8) | data[2]; 14928c2ecf20Sopenharmony_ci this_fid = (data[1] & UVC_STREAM_FID) ? 1 : 0; 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci /* If PTS or FID has changed, start a new frame. */ 14958c2ecf20Sopenharmony_ci if (this_pts != sd->last_pts || this_fid != sd->last_fid) { 14968c2ecf20Sopenharmony_ci if (gspca_dev->last_packet_type == INTER_PACKET) 14978c2ecf20Sopenharmony_ci gspca_frame_add(gspca_dev, LAST_PACKET, 14988c2ecf20Sopenharmony_ci NULL, 0); 14998c2ecf20Sopenharmony_ci sd->last_pts = this_pts; 15008c2ecf20Sopenharmony_ci sd->last_fid = this_fid; 15018c2ecf20Sopenharmony_ci gspca_frame_add(gspca_dev, FIRST_PACKET, 15028c2ecf20Sopenharmony_ci data + 12, len - 12); 15038c2ecf20Sopenharmony_ci /* If this packet is marked as EOF, end the frame */ 15048c2ecf20Sopenharmony_ci } else if (data[1] & UVC_STREAM_EOF) { 15058c2ecf20Sopenharmony_ci sd->last_pts = 0; 15068c2ecf20Sopenharmony_ci if (gspca_dev->pixfmt.pixelformat != V4L2_PIX_FMT_JPEG 15078c2ecf20Sopenharmony_ci && gspca_dev->image_len + len - 12 != 15088c2ecf20Sopenharmony_ci gspca_dev->pixfmt.sizeimage) { 15098c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_PACK, "wrong sized frame\n"); 15108c2ecf20Sopenharmony_ci goto discard; 15118c2ecf20Sopenharmony_ci } 15128c2ecf20Sopenharmony_ci gspca_frame_add(gspca_dev, LAST_PACKET, 15138c2ecf20Sopenharmony_ci data + 12, len - 12); 15148c2ecf20Sopenharmony_ci } else { 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci /* Add the data from this payload */ 15178c2ecf20Sopenharmony_ci gspca_frame_add(gspca_dev, INTER_PACKET, 15188c2ecf20Sopenharmony_ci data + 12, len - 12); 15198c2ecf20Sopenharmony_ci } 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci /* Done this payload */ 15228c2ecf20Sopenharmony_ci goto scan_next; 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_cidiscard: 15258c2ecf20Sopenharmony_ci /* Discard data until a new frame starts. */ 15268c2ecf20Sopenharmony_ci gspca_dev->last_packet_type = DISCARD_PACKET; 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ciscan_next: 15298c2ecf20Sopenharmony_ci remaining_len -= len; 15308c2ecf20Sopenharmony_ci data += len; 15318c2ecf20Sopenharmony_ci } while (remaining_len > 0); 15328c2ecf20Sopenharmony_ci} 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci/* get stream parameters (framerate) */ 15358c2ecf20Sopenharmony_cistatic void sd_get_streamparm(struct gspca_dev *gspca_dev, 15368c2ecf20Sopenharmony_ci struct v4l2_streamparm *parm) 15378c2ecf20Sopenharmony_ci{ 15388c2ecf20Sopenharmony_ci struct v4l2_captureparm *cp = &parm->parm.capture; 15398c2ecf20Sopenharmony_ci struct v4l2_fract *tpf = &cp->timeperframe; 15408c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci tpf->numerator = 1; 15438c2ecf20Sopenharmony_ci tpf->denominator = sd->frame_rate; 15448c2ecf20Sopenharmony_ci} 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci/* set stream parameters (framerate) */ 15478c2ecf20Sopenharmony_cistatic void sd_set_streamparm(struct gspca_dev *gspca_dev, 15488c2ecf20Sopenharmony_ci struct v4l2_streamparm *parm) 15498c2ecf20Sopenharmony_ci{ 15508c2ecf20Sopenharmony_ci struct v4l2_captureparm *cp = &parm->parm.capture; 15518c2ecf20Sopenharmony_ci struct v4l2_fract *tpf = &cp->timeperframe; 15528c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci if (tpf->numerator == 0 || tpf->denominator == 0) 15558c2ecf20Sopenharmony_ci sd->frame_rate = DEFAULT_FRAME_RATE; 15568c2ecf20Sopenharmony_ci else 15578c2ecf20Sopenharmony_ci sd->frame_rate = tpf->denominator / tpf->numerator; 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci if (gspca_dev->streaming) 15608c2ecf20Sopenharmony_ci set_frame_rate(gspca_dev); 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci /* Return the actual framerate */ 15638c2ecf20Sopenharmony_ci tpf->numerator = 1; 15648c2ecf20Sopenharmony_ci tpf->denominator = sd->frame_rate; 15658c2ecf20Sopenharmony_ci} 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci/* sub-driver description */ 15688c2ecf20Sopenharmony_cistatic const struct sd_desc sd_desc = { 15698c2ecf20Sopenharmony_ci .name = MODULE_NAME, 15708c2ecf20Sopenharmony_ci .config = sd_config, 15718c2ecf20Sopenharmony_ci .init = sd_init, 15728c2ecf20Sopenharmony_ci .init_controls = sd_init_controls, 15738c2ecf20Sopenharmony_ci .start = sd_start, 15748c2ecf20Sopenharmony_ci .stopN = sd_stopN, 15758c2ecf20Sopenharmony_ci .pkt_scan = sd_pkt_scan, 15768c2ecf20Sopenharmony_ci .get_streamparm = sd_get_streamparm, 15778c2ecf20Sopenharmony_ci .set_streamparm = sd_set_streamparm, 15788c2ecf20Sopenharmony_ci}; 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci/* -- module initialisation -- */ 15818c2ecf20Sopenharmony_cistatic const struct usb_device_id device_table[] = { 15828c2ecf20Sopenharmony_ci {USB_DEVICE(0x1415, 0x2000)}, 15838c2ecf20Sopenharmony_ci {USB_DEVICE(0x06f8, 0x3002)}, 15848c2ecf20Sopenharmony_ci {} 15858c2ecf20Sopenharmony_ci}; 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, device_table); 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci/* -- device connect -- */ 15908c2ecf20Sopenharmony_cistatic int sd_probe(struct usb_interface *intf, const struct usb_device_id *id) 15918c2ecf20Sopenharmony_ci{ 15928c2ecf20Sopenharmony_ci return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), 15938c2ecf20Sopenharmony_ci THIS_MODULE); 15948c2ecf20Sopenharmony_ci} 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_cistatic struct usb_driver sd_driver = { 15978c2ecf20Sopenharmony_ci .name = MODULE_NAME, 15988c2ecf20Sopenharmony_ci .id_table = device_table, 15998c2ecf20Sopenharmony_ci .probe = sd_probe, 16008c2ecf20Sopenharmony_ci .disconnect = gspca_disconnect, 16018c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 16028c2ecf20Sopenharmony_ci .suspend = gspca_suspend, 16038c2ecf20Sopenharmony_ci .resume = gspca_resume, 16048c2ecf20Sopenharmony_ci .reset_resume = gspca_resume, 16058c2ecf20Sopenharmony_ci#endif 16068c2ecf20Sopenharmony_ci}; 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_cimodule_usb_driver(sd_driver); 1609