18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for the ov7660 sensor 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2009 Erik Andrén 68c2ecf20Sopenharmony_ci * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. 78c2ecf20Sopenharmony_ci * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Portions of code to USB interface and ALi driver software, 108c2ecf20Sopenharmony_ci * Copyright (c) 2006 Willem Duinker 118c2ecf20Sopenharmony_ci * v4l2 interface modeled after the V4L2 driver 128c2ecf20Sopenharmony_ci * for SN9C10x PC Camera Controllers 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "m5602_ov7660.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic int ov7660_s_ctrl(struct v4l2_ctrl *ctrl); 208c2ecf20Sopenharmony_cistatic void ov7660_dump_registers(struct sd *sd); 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic const unsigned char preinit_ov7660[][4] = { 238c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02}, 248c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0}, 258c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, 268c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, 278c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, 288c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d}, 298c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00}, 308c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DIR, 0x03}, 318c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DIR, 0x03}, 328c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, 338c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci {SENSOR, OV7660_OFON, 0x0c}, 368c2ecf20Sopenharmony_ci {SENSOR, OV7660_COM2, 0x11}, 378c2ecf20Sopenharmony_ci {SENSOR, OV7660_COM7, 0x05}, 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DIR, 0x01}, 408c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, 418c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, 428c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, 438c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00}, 448c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08}, 458c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, 468c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, 478c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, 488c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, 498c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, 508c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, 518c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, 528c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, 538c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_EN_L, 0x00} 548c2ecf20Sopenharmony_ci}; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic const unsigned char init_ov7660[][4] = { 578c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02}, 588c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0}, 598c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, 608c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, 618c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, 628c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d}, 638c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00}, 648c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DIR, 0x01}, 658c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DIR, 0x01}, 668c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, 678c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, 688c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, 698c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, 708c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, 718c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, 728c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, 738c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_EN_L, 0x00}, 748c2ecf20Sopenharmony_ci {SENSOR, OV7660_COM7, 0x80}, 758c2ecf20Sopenharmony_ci {SENSOR, OV7660_CLKRC, 0x80}, 768c2ecf20Sopenharmony_ci {SENSOR, OV7660_COM9, 0x4c}, 778c2ecf20Sopenharmony_ci {SENSOR, OV7660_OFON, 0x43}, 788c2ecf20Sopenharmony_ci {SENSOR, OV7660_COM12, 0x28}, 798c2ecf20Sopenharmony_ci {SENSOR, OV7660_COM8, 0x00}, 808c2ecf20Sopenharmony_ci {SENSOR, OV7660_COM10, 0x40}, 818c2ecf20Sopenharmony_ci {SENSOR, OV7660_HSTART, 0x0c}, 828c2ecf20Sopenharmony_ci {SENSOR, OV7660_HSTOP, 0x61}, 838c2ecf20Sopenharmony_ci {SENSOR, OV7660_HREF, 0xa4}, 848c2ecf20Sopenharmony_ci {SENSOR, OV7660_PSHFT, 0x0b}, 858c2ecf20Sopenharmony_ci {SENSOR, OV7660_VSTART, 0x01}, 868c2ecf20Sopenharmony_ci {SENSOR, OV7660_VSTOP, 0x7a}, 878c2ecf20Sopenharmony_ci {SENSOR, OV7660_VSTOP, 0x00}, 888c2ecf20Sopenharmony_ci {SENSOR, OV7660_COM7, 0x05}, 898c2ecf20Sopenharmony_ci {SENSOR, OV7660_COM6, 0x42}, 908c2ecf20Sopenharmony_ci {SENSOR, OV7660_BBIAS, 0x94}, 918c2ecf20Sopenharmony_ci {SENSOR, OV7660_GbBIAS, 0x94}, 928c2ecf20Sopenharmony_ci {SENSOR, OV7660_RSVD29, 0x94}, 938c2ecf20Sopenharmony_ci {SENSOR, OV7660_RBIAS, 0x94}, 948c2ecf20Sopenharmony_ci {SENSOR, OV7660_COM1, 0x00}, 958c2ecf20Sopenharmony_ci {SENSOR, OV7660_AECH, 0x00}, 968c2ecf20Sopenharmony_ci {SENSOR, OV7660_AECHH, 0x00}, 978c2ecf20Sopenharmony_ci {SENSOR, OV7660_ADC, 0x05}, 988c2ecf20Sopenharmony_ci {SENSOR, OV7660_COM13, 0x00}, 998c2ecf20Sopenharmony_ci {SENSOR, OV7660_RSVDA1, 0x23}, 1008c2ecf20Sopenharmony_ci {SENSOR, OV7660_TSLB, 0x0d}, 1018c2ecf20Sopenharmony_ci {SENSOR, OV7660_HV, 0x80}, 1028c2ecf20Sopenharmony_ci {SENSOR, OV7660_LCC1, 0x00}, 1038c2ecf20Sopenharmony_ci {SENSOR, OV7660_LCC2, 0x00}, 1048c2ecf20Sopenharmony_ci {SENSOR, OV7660_LCC3, 0x10}, 1058c2ecf20Sopenharmony_ci {SENSOR, OV7660_LCC4, 0x40}, 1068c2ecf20Sopenharmony_ci {SENSOR, OV7660_LCC5, 0x01}, 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci {SENSOR, OV7660_AECH, 0x20}, 1098c2ecf20Sopenharmony_ci {SENSOR, OV7660_COM1, 0x00}, 1108c2ecf20Sopenharmony_ci {SENSOR, OV7660_OFON, 0x0c}, 1118c2ecf20Sopenharmony_ci {SENSOR, OV7660_COM2, 0x11}, 1128c2ecf20Sopenharmony_ci {SENSOR, OV7660_COM7, 0x05}, 1138c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DIR, 0x01}, 1148c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, 1158c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, 1168c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, 1178c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00}, 1188c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08}, 1198c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, 1208c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, 1218c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, 1228c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, 1238c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, 1248c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, 1258c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, 1268c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, 1278c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_EN_L, 0x00}, 1288c2ecf20Sopenharmony_ci {SENSOR, OV7660_AECH, 0x5f}, 1298c2ecf20Sopenharmony_ci {SENSOR, OV7660_COM1, 0x03}, 1308c2ecf20Sopenharmony_ci {SENSOR, OV7660_OFON, 0x0c}, 1318c2ecf20Sopenharmony_ci {SENSOR, OV7660_COM2, 0x11}, 1328c2ecf20Sopenharmony_ci {SENSOR, OV7660_COM7, 0x05}, 1338c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DIR, 0x01}, 1348c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, 1358c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, 1368c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, 1378c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00}, 1388c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08}, 1398c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, 1408c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, 1418c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, 1428c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, 1438c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, 1448c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, 1458c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, 1468c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, 1478c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_EN_L, 0x00}, 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06}, 1508c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, 1518c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, 1528c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, 1538c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81}, 1548c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82}, 1558c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SIG_INI, 0x01}, 1568c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, 1578c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_VSYNC_PARA, 0x08}, 1588c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, 1598c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, 1608c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_VSYNC_PARA, 0x01}, 1618c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_VSYNC_PARA, 0xec}, 1628c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, 1638c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, 1648c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SIG_INI, 0x00}, 1658c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SIG_INI, 0x02}, 1668c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_HSYNC_PARA, 0x00}, 1678c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_HSYNC_PARA, 0x27}, 1688c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_HSYNC_PARA, 0x02}, 1698c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_HSYNC_PARA, 0xa7}, 1708c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SIG_INI, 0x00}, 1718c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, 1728c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, 1738c2ecf20Sopenharmony_ci}; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic struct v4l2_pix_format ov7660_modes[] = { 1768c2ecf20Sopenharmony_ci { 1778c2ecf20Sopenharmony_ci 640, 1788c2ecf20Sopenharmony_ci 480, 1798c2ecf20Sopenharmony_ci V4L2_PIX_FMT_SBGGR8, 1808c2ecf20Sopenharmony_ci V4L2_FIELD_NONE, 1818c2ecf20Sopenharmony_ci .sizeimage = 1828c2ecf20Sopenharmony_ci 640 * 480, 1838c2ecf20Sopenharmony_ci .bytesperline = 640, 1848c2ecf20Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 1858c2ecf20Sopenharmony_ci .priv = 0 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci}; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops ov7660_ctrl_ops = { 1908c2ecf20Sopenharmony_ci .s_ctrl = ov7660_s_ctrl, 1918c2ecf20Sopenharmony_ci}; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ciint ov7660_probe(struct sd *sd) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci int err = 0, i; 1968c2ecf20Sopenharmony_ci u8 prod_id = 0, ver_id = 0; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (force_sensor) { 1998c2ecf20Sopenharmony_ci if (force_sensor == OV7660_SENSOR) { 2008c2ecf20Sopenharmony_ci pr_info("Forcing an %s sensor\n", ov7660.name); 2018c2ecf20Sopenharmony_ci goto sensor_found; 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci /* If we want to force another sensor, 2048c2ecf20Sopenharmony_ci don't try to probe this one */ 2058c2ecf20Sopenharmony_ci return -ENODEV; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci /* Do the preinit */ 2098c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(preinit_ov7660) && !err; i++) { 2108c2ecf20Sopenharmony_ci u8 data[2]; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (preinit_ov7660[i][0] == BRIDGE) { 2138c2ecf20Sopenharmony_ci err = m5602_write_bridge(sd, 2148c2ecf20Sopenharmony_ci preinit_ov7660[i][1], 2158c2ecf20Sopenharmony_ci preinit_ov7660[i][2]); 2168c2ecf20Sopenharmony_ci } else { 2178c2ecf20Sopenharmony_ci data[0] = preinit_ov7660[i][2]; 2188c2ecf20Sopenharmony_ci err = m5602_write_sensor(sd, 2198c2ecf20Sopenharmony_ci preinit_ov7660[i][1], data, 1); 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci if (err < 0) 2238c2ecf20Sopenharmony_ci return err; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (m5602_read_sensor(sd, OV7660_PID, &prod_id, 1)) 2268c2ecf20Sopenharmony_ci return -ENODEV; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (m5602_read_sensor(sd, OV7660_VER, &ver_id, 1)) 2298c2ecf20Sopenharmony_ci return -ENODEV; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci pr_info("Sensor reported 0x%x%x\n", prod_id, ver_id); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci if ((prod_id == 0x76) && (ver_id == 0x60)) { 2348c2ecf20Sopenharmony_ci pr_info("Detected a ov7660 sensor\n"); 2358c2ecf20Sopenharmony_ci goto sensor_found; 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci return -ENODEV; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cisensor_found: 2408c2ecf20Sopenharmony_ci sd->gspca_dev.cam.cam_mode = ov7660_modes; 2418c2ecf20Sopenharmony_ci sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov7660_modes); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci return 0; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ciint ov7660_init(struct sd *sd) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci int i, err; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci /* Init the sensor */ 2518c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(init_ov7660); i++) { 2528c2ecf20Sopenharmony_ci u8 data[2]; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci if (init_ov7660[i][0] == BRIDGE) { 2558c2ecf20Sopenharmony_ci err = m5602_write_bridge(sd, 2568c2ecf20Sopenharmony_ci init_ov7660[i][1], 2578c2ecf20Sopenharmony_ci init_ov7660[i][2]); 2588c2ecf20Sopenharmony_ci } else { 2598c2ecf20Sopenharmony_ci data[0] = init_ov7660[i][2]; 2608c2ecf20Sopenharmony_ci err = m5602_write_sensor(sd, 2618c2ecf20Sopenharmony_ci init_ov7660[i][1], data, 1); 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci if (err < 0) 2648c2ecf20Sopenharmony_ci return err; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (dump_sensor) 2688c2ecf20Sopenharmony_ci ov7660_dump_registers(sd); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci return 0; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ciint ov7660_init_controls(struct sd *sd) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci sd->gspca_dev.vdev.ctrl_handler = hdl; 2788c2ecf20Sopenharmony_ci v4l2_ctrl_handler_init(hdl, 6); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE, 2818c2ecf20Sopenharmony_ci 0, 1, 1, 1); 2828c2ecf20Sopenharmony_ci v4l2_ctrl_new_std_menu(hdl, &ov7660_ctrl_ops, 2838c2ecf20Sopenharmony_ci V4L2_CID_EXPOSURE_AUTO, 1, 0, V4L2_EXPOSURE_AUTO); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci sd->autogain = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, 2868c2ecf20Sopenharmony_ci V4L2_CID_AUTOGAIN, 0, 1, 1, 1); 2878c2ecf20Sopenharmony_ci sd->gain = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_GAIN, 0, 2888c2ecf20Sopenharmony_ci 255, 1, OV7660_DEFAULT_GAIN); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci sd->hflip = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_HFLIP, 2918c2ecf20Sopenharmony_ci 0, 1, 1, 0); 2928c2ecf20Sopenharmony_ci sd->vflip = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_VFLIP, 2938c2ecf20Sopenharmony_ci 0, 1, 1, 0); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci if (hdl->error) { 2968c2ecf20Sopenharmony_ci pr_err("Could not initialize controls\n"); 2978c2ecf20Sopenharmony_ci return hdl->error; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, false); 3018c2ecf20Sopenharmony_ci v4l2_ctrl_cluster(2, &sd->hflip); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci return 0; 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ciint ov7660_start(struct sd *sd) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci return 0; 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ciint ov7660_stop(struct sd *sd) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci return 0; 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_civoid ov7660_disconnect(struct sd *sd) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci ov7660_stop(sd); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci sd->sensor = NULL; 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci int err; 3268c2ecf20Sopenharmony_ci u8 i2c_data = val; 3278c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_CONF, "Setting gain to %d\n", val); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci err = m5602_write_sensor(sd, OV7660_GAIN, &i2c_data, 1); 3328c2ecf20Sopenharmony_ci return err; 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev, 3368c2ecf20Sopenharmony_ci __s32 val) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci int err; 3398c2ecf20Sopenharmony_ci u8 i2c_data; 3408c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_CONF, "Set auto white balance to %d\n", val); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1); 3458c2ecf20Sopenharmony_ci if (err < 0) 3468c2ecf20Sopenharmony_ci return err; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1)); 3498c2ecf20Sopenharmony_ci err = m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci return err; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci int err; 3578c2ecf20Sopenharmony_ci u8 i2c_data; 3588c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_CONF, "Set auto gain control to %d\n", val); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1); 3638c2ecf20Sopenharmony_ci if (err < 0) 3648c2ecf20Sopenharmony_ci return err; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2)); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1); 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev, 3728c2ecf20Sopenharmony_ci __s32 val) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci int err; 3758c2ecf20Sopenharmony_ci u8 i2c_data; 3768c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_CONF, "Set auto exposure control to %d\n", val); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1); 3818c2ecf20Sopenharmony_ci if (err < 0) 3828c2ecf20Sopenharmony_ci return err; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci val = (val == V4L2_EXPOSURE_AUTO); 3858c2ecf20Sopenharmony_ci i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0)); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1); 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic int ov7660_set_hvflip(struct gspca_dev *gspca_dev) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci int err; 3938c2ecf20Sopenharmony_ci u8 i2c_data; 3948c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_CONF, "Set hvflip to %d, %d\n", 3978c2ecf20Sopenharmony_ci sd->hflip->val, sd->vflip->val); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci i2c_data = (sd->hflip->val << 5) | (sd->vflip->val << 4); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci return err; 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic int ov7660_s_ctrl(struct v4l2_ctrl *ctrl) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci struct gspca_dev *gspca_dev = 4098c2ecf20Sopenharmony_ci container_of(ctrl->handler, struct gspca_dev, ctrl_handler); 4108c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 4118c2ecf20Sopenharmony_ci int err; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (!gspca_dev->streaming) 4148c2ecf20Sopenharmony_ci return 0; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci switch (ctrl->id) { 4178c2ecf20Sopenharmony_ci case V4L2_CID_AUTO_WHITE_BALANCE: 4188c2ecf20Sopenharmony_ci err = ov7660_set_auto_white_balance(gspca_dev, ctrl->val); 4198c2ecf20Sopenharmony_ci break; 4208c2ecf20Sopenharmony_ci case V4L2_CID_EXPOSURE_AUTO: 4218c2ecf20Sopenharmony_ci err = ov7660_set_auto_exposure(gspca_dev, ctrl->val); 4228c2ecf20Sopenharmony_ci break; 4238c2ecf20Sopenharmony_ci case V4L2_CID_AUTOGAIN: 4248c2ecf20Sopenharmony_ci err = ov7660_set_auto_gain(gspca_dev, ctrl->val); 4258c2ecf20Sopenharmony_ci if (err || ctrl->val) 4268c2ecf20Sopenharmony_ci return err; 4278c2ecf20Sopenharmony_ci err = ov7660_set_gain(gspca_dev, sd->gain->val); 4288c2ecf20Sopenharmony_ci break; 4298c2ecf20Sopenharmony_ci case V4L2_CID_HFLIP: 4308c2ecf20Sopenharmony_ci err = ov7660_set_hvflip(gspca_dev); 4318c2ecf20Sopenharmony_ci break; 4328c2ecf20Sopenharmony_ci default: 4338c2ecf20Sopenharmony_ci return -EINVAL; 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci return err; 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic void ov7660_dump_registers(struct sd *sd) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci int address; 4428c2ecf20Sopenharmony_ci pr_info("Dumping the ov7660 register state\n"); 4438c2ecf20Sopenharmony_ci for (address = 0; address < 0xa9; address++) { 4448c2ecf20Sopenharmony_ci u8 value; 4458c2ecf20Sopenharmony_ci m5602_read_sensor(sd, address, &value, 1); 4468c2ecf20Sopenharmony_ci pr_info("register 0x%x contains 0x%x\n", address, value); 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci pr_info("ov7660 register state dump complete\n"); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci pr_info("Probing for which registers that are read/write\n"); 4528c2ecf20Sopenharmony_ci for (address = 0; address < 0xff; address++) { 4538c2ecf20Sopenharmony_ci u8 old_value, ctrl_value; 4548c2ecf20Sopenharmony_ci u8 test_value[2] = {0xff, 0xff}; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci m5602_read_sensor(sd, address, &old_value, 1); 4578c2ecf20Sopenharmony_ci m5602_write_sensor(sd, address, test_value, 1); 4588c2ecf20Sopenharmony_ci m5602_read_sensor(sd, address, &ctrl_value, 1); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci if (ctrl_value == test_value[0]) 4618c2ecf20Sopenharmony_ci pr_info("register 0x%x is writeable\n", address); 4628c2ecf20Sopenharmony_ci else 4638c2ecf20Sopenharmony_ci pr_info("register 0x%x is read only\n", address); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci /* Restore original value */ 4668c2ecf20Sopenharmony_ci m5602_write_sensor(sd, address, &old_value, 1); 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci} 469