18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for the s5k4aa sensor 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2008 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_s5k4aa.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic const unsigned char preinit_s5k4aa[][4] = { 208c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, 218c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, 228c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, 238c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, 248c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, 258c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00}, 268c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00}, 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, 298c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00}, 308c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00}, 318c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00}, 328c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00}, 338c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00}, 348c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, 358c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, 368c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DAT, 0x00, 0x00}, 378c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, 388c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, 398c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, 408c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, 418c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, 428c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, 438c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00}, 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, 468c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, 478c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, 488c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DAT, 0x14, 0x00}, 498c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, 508c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00}, 518c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, 528c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00}, 538c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, 548c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00}, 558c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, 568c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, 578c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00}, 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_PAGE_MAP, 0x00, 0x00} 608c2ecf20Sopenharmony_ci}; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic const unsigned char init_s5k4aa[][4] = { 638c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, 648c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, 658c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, 668c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, 678c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, 688c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00}, 698c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00}, 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, 728c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00}, 738c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00}, 748c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00}, 758c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00}, 768c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00}, 778c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, 788c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, 798c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DAT, 0x00, 0x00}, 808c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, 818c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, 828c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, 838c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, 848c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, 858c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, 868c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00}, 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, 898c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, 908c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, 918c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DAT, 0x14, 0x00}, 928c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, 938c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00}, 948c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, 958c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00}, 968c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, 978c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00}, 988c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, 998c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, 1008c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00}, 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_PAGE_MAP, 0x07, 0x00}, 1038c2ecf20Sopenharmony_ci {SENSOR, 0x36, 0x01, 0x00}, 1048c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_PAGE_MAP, 0x00, 0x00}, 1058c2ecf20Sopenharmony_ci {SENSOR, 0x7b, 0xff, 0x00}, 1068c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, 1078c2ecf20Sopenharmony_ci {SENSOR, 0x0c, 0x05, 0x00}, 1088c2ecf20Sopenharmony_ci {SENSOR, 0x02, 0x0e, 0x00}, 1098c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_READ_MODE, 0xa0, 0x00}, 1108c2ecf20Sopenharmony_ci {SENSOR, 0x37, 0x00, 0x00}, 1118c2ecf20Sopenharmony_ci}; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic const unsigned char VGA_s5k4aa[][4] = { 1148c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, 1158c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, 1168c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, 1178c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00}, 1188c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, 1198c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, 1208c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, 1218c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 1228c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 1238c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 1248c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 1258c2ecf20Sopenharmony_ci /* VSYNC_PARA, VSYNC_PARA : img height 480 = 0x01e0 */ 1268c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00}, 1278c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0, 0x00}, 1288c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 1298c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 1308c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, 1318c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, 1328c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, 1338c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, 1348c2ecf20Sopenharmony_ci /* HSYNC_PARA, HSYNC_PARA : img width 640 = 0x0280 */ 1358c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00}, 1368c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_HSYNC_PARA, 0x80, 0x00}, 1378c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, 1388c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, 1398c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, /* 48 MHz */ 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, 1428c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_READ_MODE, S5K4AA_RM_H_FLIP | S5K4AA_RM_ROW_SKIP_2X 1438c2ecf20Sopenharmony_ci | S5K4AA_RM_COL_SKIP_2X, 0x00}, 1448c2ecf20Sopenharmony_ci /* 0x37 : Fix image stability when light is too bright and improves 1458c2ecf20Sopenharmony_ci * image quality in 640x480, but worsens it in 1280x1024 */ 1468c2ecf20Sopenharmony_ci {SENSOR, 0x37, 0x01, 0x00}, 1478c2ecf20Sopenharmony_ci /* ROWSTART_HI, ROWSTART_LO : 10 + (1024-960)/2 = 42 = 0x002a */ 1488c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00}, 1498c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_ROWSTART_LO, 0x29, 0x00}, 1508c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00}, 1518c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_COLSTART_LO, 0x0c, 0x00}, 1528c2ecf20Sopenharmony_ci /* window_height_hi, window_height_lo : 960 = 0x03c0 */ 1538c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x03, 0x00}, 1548c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0xc0, 0x00}, 1558c2ecf20Sopenharmony_ci /* window_width_hi, window_width_lo : 1280 = 0x0500 */ 1568c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00}, 1578c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x00, 0x00}, 1588c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_H_BLANK_HI__, 0x00, 0x00}, 1598c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_H_BLANK_LO__, 0xa8, 0x00}, /* helps to sync... */ 1608c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_EXPOSURE_HI, 0x01, 0x00}, 1618c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_EXPOSURE_LO, 0x00, 0x00}, 1628c2ecf20Sopenharmony_ci {SENSOR, 0x11, 0x04, 0x00}, 1638c2ecf20Sopenharmony_ci {SENSOR, 0x12, 0xc3, 0x00}, 1648c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, 1658c2ecf20Sopenharmony_ci {SENSOR, 0x02, 0x0e, 0x00}, 1668c2ecf20Sopenharmony_ci}; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic const unsigned char SXGA_s5k4aa[][4] = { 1698c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, 1708c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, 1718c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, 1728c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00}, 1738c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, 1748c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, 1758c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, 1768c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 1778c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 1788c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 1798c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 1808c2ecf20Sopenharmony_ci /* VSYNC_PARA, VSYNC_PARA : img height 1024 = 0x0400 */ 1818c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00}, 1828c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 1838c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 1848c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 1858c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, 1868c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, 1878c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, 1888c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, 1898c2ecf20Sopenharmony_ci /* HSYNC_PARA, HSYNC_PARA : img width 1280 = 0x0500 */ 1908c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00}, 1918c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, 1928c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, 1938c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, 1948c2ecf20Sopenharmony_ci {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, /* 48 MHz */ 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, 1978c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_READ_MODE, S5K4AA_RM_H_FLIP, 0x00}, 1988c2ecf20Sopenharmony_ci {SENSOR, 0x37, 0x01, 0x00}, 1998c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00}, 2008c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_ROWSTART_LO, 0x09, 0x00}, 2018c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00}, 2028c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_COLSTART_LO, 0x0a, 0x00}, 2038c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x04, 0x00}, 2048c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0x00, 0x00}, 2058c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00}, 2068c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x00, 0x00}, 2078c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_H_BLANK_HI__, 0x01, 0x00}, 2088c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_H_BLANK_LO__, 0xa8, 0x00}, 2098c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_EXPOSURE_HI, 0x01, 0x00}, 2108c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_EXPOSURE_LO, 0x00, 0x00}, 2118c2ecf20Sopenharmony_ci {SENSOR, 0x11, 0x04, 0x00}, 2128c2ecf20Sopenharmony_ci {SENSOR, 0x12, 0xc3, 0x00}, 2138c2ecf20Sopenharmony_ci {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, 2148c2ecf20Sopenharmony_ci {SENSOR, 0x02, 0x0e, 0x00}, 2158c2ecf20Sopenharmony_ci}; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic int s5k4aa_s_ctrl(struct v4l2_ctrl *ctrl); 2198c2ecf20Sopenharmony_cistatic void s5k4aa_dump_registers(struct sd *sd); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops s5k4aa_ctrl_ops = { 2228c2ecf20Sopenharmony_ci .s_ctrl = s5k4aa_s_ctrl, 2238c2ecf20Sopenharmony_ci}; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic 2268c2ecf20Sopenharmony_ci const 2278c2ecf20Sopenharmony_ci struct dmi_system_id s5k4aa_vflip_dmi_table[] = { 2288c2ecf20Sopenharmony_ci { 2298c2ecf20Sopenharmony_ci .ident = "BRUNEINIT", 2308c2ecf20Sopenharmony_ci .matches = { 2318c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "BRUNENIT"), 2328c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "BRUNENIT"), 2338c2ecf20Sopenharmony_ci DMI_MATCH(DMI_BOARD_VERSION, "00030D0000000001") 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci }, { 2368c2ecf20Sopenharmony_ci .ident = "Fujitsu-Siemens Amilo Xa 2528", 2378c2ecf20Sopenharmony_ci .matches = { 2388c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 2398c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528") 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci }, { 2428c2ecf20Sopenharmony_ci .ident = "Fujitsu-Siemens Amilo Xi 2428", 2438c2ecf20Sopenharmony_ci .matches = { 2448c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 2458c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2428") 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci }, { 2488c2ecf20Sopenharmony_ci .ident = "Fujitsu-Siemens Amilo Xi 2528", 2498c2ecf20Sopenharmony_ci .matches = { 2508c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 2518c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2528") 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci }, { 2548c2ecf20Sopenharmony_ci .ident = "Fujitsu-Siemens Amilo Xi 2550", 2558c2ecf20Sopenharmony_ci .matches = { 2568c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 2578c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550") 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci }, { 2608c2ecf20Sopenharmony_ci .ident = "Fujitsu-Siemens Amilo Pa 2548", 2618c2ecf20Sopenharmony_ci .matches = { 2628c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 2638c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2548") 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci }, { 2668c2ecf20Sopenharmony_ci .ident = "Fujitsu-Siemens Amilo Pi 2530", 2678c2ecf20Sopenharmony_ci .matches = { 2688c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 2698c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 2530") 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci }, { 2728c2ecf20Sopenharmony_ci .ident = "MSI GX700", 2738c2ecf20Sopenharmony_ci .matches = { 2748c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), 2758c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "GX700"), 2768c2ecf20Sopenharmony_ci DMI_MATCH(DMI_BIOS_DATE, "12/02/2008") 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci }, { 2798c2ecf20Sopenharmony_ci .ident = "MSI GX700", 2808c2ecf20Sopenharmony_ci .matches = { 2818c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), 2828c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "GX700"), 2838c2ecf20Sopenharmony_ci DMI_MATCH(DMI_BIOS_DATE, "07/26/2007") 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci }, { 2868c2ecf20Sopenharmony_ci .ident = "MSI GX700", 2878c2ecf20Sopenharmony_ci .matches = { 2888c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), 2898c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "GX700"), 2908c2ecf20Sopenharmony_ci DMI_MATCH(DMI_BIOS_DATE, "07/19/2007") 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci }, { 2938c2ecf20Sopenharmony_ci .ident = "MSI GX700/GX705/EX700", 2948c2ecf20Sopenharmony_ci .matches = { 2958c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), 2968c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700") 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci }, { 2998c2ecf20Sopenharmony_ci .ident = "MSI L735", 3008c2ecf20Sopenharmony_ci .matches = { 3018c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), 3028c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "MS-1717X") 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci }, { 3058c2ecf20Sopenharmony_ci .ident = "Lenovo Y300", 3068c2ecf20Sopenharmony_ci .matches = { 3078c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "L3000 Y300"), 3088c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "Y300") 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci }, 3118c2ecf20Sopenharmony_ci { } 3128c2ecf20Sopenharmony_ci}; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic struct v4l2_pix_format s5k4aa_modes[] = { 3158c2ecf20Sopenharmony_ci { 3168c2ecf20Sopenharmony_ci 640, 3178c2ecf20Sopenharmony_ci 480, 3188c2ecf20Sopenharmony_ci V4L2_PIX_FMT_SBGGR8, 3198c2ecf20Sopenharmony_ci V4L2_FIELD_NONE, 3208c2ecf20Sopenharmony_ci .sizeimage = 3218c2ecf20Sopenharmony_ci 640 * 480, 3228c2ecf20Sopenharmony_ci .bytesperline = 640, 3238c2ecf20Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 3248c2ecf20Sopenharmony_ci .priv = 0 3258c2ecf20Sopenharmony_ci }, 3268c2ecf20Sopenharmony_ci { 3278c2ecf20Sopenharmony_ci 1280, 3288c2ecf20Sopenharmony_ci 1024, 3298c2ecf20Sopenharmony_ci V4L2_PIX_FMT_SBGGR8, 3308c2ecf20Sopenharmony_ci V4L2_FIELD_NONE, 3318c2ecf20Sopenharmony_ci .sizeimage = 3328c2ecf20Sopenharmony_ci 1280 * 1024, 3338c2ecf20Sopenharmony_ci .bytesperline = 1280, 3348c2ecf20Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 3358c2ecf20Sopenharmony_ci .priv = 0 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci}; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ciint s5k4aa_probe(struct sd *sd) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 3428c2ecf20Sopenharmony_ci const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75}; 3438c2ecf20Sopenharmony_ci struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; 3448c2ecf20Sopenharmony_ci int i, err = 0; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci if (force_sensor) { 3478c2ecf20Sopenharmony_ci if (force_sensor == S5K4AA_SENSOR) { 3488c2ecf20Sopenharmony_ci pr_info("Forcing a %s sensor\n", s5k4aa.name); 3498c2ecf20Sopenharmony_ci goto sensor_found; 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci /* If we want to force another sensor, don't try to probe this 3528c2ecf20Sopenharmony_ci * one */ 3538c2ecf20Sopenharmony_ci return -ENODEV; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_PROBE, "Probing for a s5k4aa sensor\n"); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci /* Preinit the sensor */ 3598c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) { 3608c2ecf20Sopenharmony_ci u8 data[2] = {0x00, 0x00}; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci switch (preinit_s5k4aa[i][0]) { 3638c2ecf20Sopenharmony_ci case BRIDGE: 3648c2ecf20Sopenharmony_ci err = m5602_write_bridge(sd, 3658c2ecf20Sopenharmony_ci preinit_s5k4aa[i][1], 3668c2ecf20Sopenharmony_ci preinit_s5k4aa[i][2]); 3678c2ecf20Sopenharmony_ci break; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci case SENSOR: 3708c2ecf20Sopenharmony_ci data[0] = preinit_s5k4aa[i][2]; 3718c2ecf20Sopenharmony_ci err = m5602_write_sensor(sd, 3728c2ecf20Sopenharmony_ci preinit_s5k4aa[i][1], 3738c2ecf20Sopenharmony_ci data, 1); 3748c2ecf20Sopenharmony_ci break; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci case SENSOR_LONG: 3778c2ecf20Sopenharmony_ci data[0] = preinit_s5k4aa[i][2]; 3788c2ecf20Sopenharmony_ci data[1] = preinit_s5k4aa[i][3]; 3798c2ecf20Sopenharmony_ci err = m5602_write_sensor(sd, 3808c2ecf20Sopenharmony_ci preinit_s5k4aa[i][1], 3818c2ecf20Sopenharmony_ci data, 2); 3828c2ecf20Sopenharmony_ci break; 3838c2ecf20Sopenharmony_ci default: 3848c2ecf20Sopenharmony_ci pr_info("Invalid stream command, exiting init\n"); 3858c2ecf20Sopenharmony_ci return -EINVAL; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* Test some registers, but we don't know their exact meaning yet */ 3908c2ecf20Sopenharmony_ci if (m5602_read_sensor(sd, 0x00, prod_id, 2)) 3918c2ecf20Sopenharmony_ci return -ENODEV; 3928c2ecf20Sopenharmony_ci if (m5602_read_sensor(sd, 0x02, prod_id+2, 2)) 3938c2ecf20Sopenharmony_ci return -ENODEV; 3948c2ecf20Sopenharmony_ci if (m5602_read_sensor(sd, 0x04, prod_id+4, 2)) 3958c2ecf20Sopenharmony_ci return -ENODEV; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (memcmp(prod_id, expected_prod_id, sizeof(prod_id))) 3988c2ecf20Sopenharmony_ci return -ENODEV; 3998c2ecf20Sopenharmony_ci else 4008c2ecf20Sopenharmony_ci pr_info("Detected a s5k4aa sensor\n"); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cisensor_found: 4038c2ecf20Sopenharmony_ci sd->gspca_dev.cam.cam_mode = s5k4aa_modes; 4048c2ecf20Sopenharmony_ci sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci return 0; 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ciint s5k4aa_start(struct sd *sd) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci int i, err = 0; 4128c2ecf20Sopenharmony_ci u8 data[2]; 4138c2ecf20Sopenharmony_ci struct cam *cam = &sd->gspca_dev.cam; 4148c2ecf20Sopenharmony_ci struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) { 4178c2ecf20Sopenharmony_ci case 1280: 4188c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_CONF, "Configuring camera for SXGA mode\n"); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) { 4218c2ecf20Sopenharmony_ci switch (SXGA_s5k4aa[i][0]) { 4228c2ecf20Sopenharmony_ci case BRIDGE: 4238c2ecf20Sopenharmony_ci err = m5602_write_bridge(sd, 4248c2ecf20Sopenharmony_ci SXGA_s5k4aa[i][1], 4258c2ecf20Sopenharmony_ci SXGA_s5k4aa[i][2]); 4268c2ecf20Sopenharmony_ci break; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci case SENSOR: 4298c2ecf20Sopenharmony_ci data[0] = SXGA_s5k4aa[i][2]; 4308c2ecf20Sopenharmony_ci err = m5602_write_sensor(sd, 4318c2ecf20Sopenharmony_ci SXGA_s5k4aa[i][1], 4328c2ecf20Sopenharmony_ci data, 1); 4338c2ecf20Sopenharmony_ci break; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci case SENSOR_LONG: 4368c2ecf20Sopenharmony_ci data[0] = SXGA_s5k4aa[i][2]; 4378c2ecf20Sopenharmony_ci data[1] = SXGA_s5k4aa[i][3]; 4388c2ecf20Sopenharmony_ci err = m5602_write_sensor(sd, 4398c2ecf20Sopenharmony_ci SXGA_s5k4aa[i][1], 4408c2ecf20Sopenharmony_ci data, 2); 4418c2ecf20Sopenharmony_ci break; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci default: 4448c2ecf20Sopenharmony_ci pr_err("Invalid stream command, exiting init\n"); 4458c2ecf20Sopenharmony_ci return -EINVAL; 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci break; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci case 640: 4518c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_CONF, "Configuring camera for VGA mode\n"); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) { 4548c2ecf20Sopenharmony_ci switch (VGA_s5k4aa[i][0]) { 4558c2ecf20Sopenharmony_ci case BRIDGE: 4568c2ecf20Sopenharmony_ci err = m5602_write_bridge(sd, 4578c2ecf20Sopenharmony_ci VGA_s5k4aa[i][1], 4588c2ecf20Sopenharmony_ci VGA_s5k4aa[i][2]); 4598c2ecf20Sopenharmony_ci break; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci case SENSOR: 4628c2ecf20Sopenharmony_ci data[0] = VGA_s5k4aa[i][2]; 4638c2ecf20Sopenharmony_ci err = m5602_write_sensor(sd, 4648c2ecf20Sopenharmony_ci VGA_s5k4aa[i][1], 4658c2ecf20Sopenharmony_ci data, 1); 4668c2ecf20Sopenharmony_ci break; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci case SENSOR_LONG: 4698c2ecf20Sopenharmony_ci data[0] = VGA_s5k4aa[i][2]; 4708c2ecf20Sopenharmony_ci data[1] = VGA_s5k4aa[i][3]; 4718c2ecf20Sopenharmony_ci err = m5602_write_sensor(sd, 4728c2ecf20Sopenharmony_ci VGA_s5k4aa[i][1], 4738c2ecf20Sopenharmony_ci data, 2); 4748c2ecf20Sopenharmony_ci break; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci default: 4778c2ecf20Sopenharmony_ci pr_err("Invalid stream command, exiting init\n"); 4788c2ecf20Sopenharmony_ci return -EINVAL; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci break; 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci if (err < 0) 4848c2ecf20Sopenharmony_ci return err; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci return 0; 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ciint s5k4aa_init(struct sd *sd) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci int i, err = 0; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) { 4948c2ecf20Sopenharmony_ci u8 data[2] = {0x00, 0x00}; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci switch (init_s5k4aa[i][0]) { 4978c2ecf20Sopenharmony_ci case BRIDGE: 4988c2ecf20Sopenharmony_ci err = m5602_write_bridge(sd, 4998c2ecf20Sopenharmony_ci init_s5k4aa[i][1], 5008c2ecf20Sopenharmony_ci init_s5k4aa[i][2]); 5018c2ecf20Sopenharmony_ci break; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci case SENSOR: 5048c2ecf20Sopenharmony_ci data[0] = init_s5k4aa[i][2]; 5058c2ecf20Sopenharmony_ci err = m5602_write_sensor(sd, 5068c2ecf20Sopenharmony_ci init_s5k4aa[i][1], data, 1); 5078c2ecf20Sopenharmony_ci break; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci case SENSOR_LONG: 5108c2ecf20Sopenharmony_ci data[0] = init_s5k4aa[i][2]; 5118c2ecf20Sopenharmony_ci data[1] = init_s5k4aa[i][3]; 5128c2ecf20Sopenharmony_ci err = m5602_write_sensor(sd, 5138c2ecf20Sopenharmony_ci init_s5k4aa[i][1], data, 2); 5148c2ecf20Sopenharmony_ci break; 5158c2ecf20Sopenharmony_ci default: 5168c2ecf20Sopenharmony_ci pr_info("Invalid stream command, exiting init\n"); 5178c2ecf20Sopenharmony_ci return -EINVAL; 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci if (dump_sensor) 5228c2ecf20Sopenharmony_ci s5k4aa_dump_registers(sd); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci return err; 5258c2ecf20Sopenharmony_ci} 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ciint s5k4aa_init_controls(struct sd *sd) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci sd->gspca_dev.vdev.ctrl_handler = hdl; 5328c2ecf20Sopenharmony_ci v4l2_ctrl_handler_init(hdl, 6); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_BRIGHTNESS, 5358c2ecf20Sopenharmony_ci 0, 0x1f, 1, S5K4AA_DEFAULT_BRIGHTNESS); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_EXPOSURE, 5388c2ecf20Sopenharmony_ci 13, 0xfff, 1, 0x100); 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_GAIN, 5418c2ecf20Sopenharmony_ci 0, 127, 1, S5K4AA_DEFAULT_GAIN); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_SHARPNESS, 5448c2ecf20Sopenharmony_ci 0, 1, 1, 1); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci sd->hflip = v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_HFLIP, 5478c2ecf20Sopenharmony_ci 0, 1, 1, 0); 5488c2ecf20Sopenharmony_ci sd->vflip = v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_VFLIP, 5498c2ecf20Sopenharmony_ci 0, 1, 1, 0); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci if (hdl->error) { 5528c2ecf20Sopenharmony_ci pr_err("Could not initialize controls\n"); 5538c2ecf20Sopenharmony_ci return hdl->error; 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci v4l2_ctrl_cluster(2, &sd->hflip); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci return 0; 5598c2ecf20Sopenharmony_ci} 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_cistatic int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 5648c2ecf20Sopenharmony_ci u8 data = S5K4AA_PAGE_MAP_2; 5658c2ecf20Sopenharmony_ci int err; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_CONF, "Set exposure to %d\n", val); 5688c2ecf20Sopenharmony_ci err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); 5698c2ecf20Sopenharmony_ci if (err < 0) 5708c2ecf20Sopenharmony_ci return err; 5718c2ecf20Sopenharmony_ci data = (val >> 8) & 0xff; 5728c2ecf20Sopenharmony_ci err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1); 5738c2ecf20Sopenharmony_ci if (err < 0) 5748c2ecf20Sopenharmony_ci return err; 5758c2ecf20Sopenharmony_ci data = val & 0xff; 5768c2ecf20Sopenharmony_ci err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci return err; 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_cistatic int s5k4aa_set_hvflip(struct gspca_dev *gspca_dev) 5828c2ecf20Sopenharmony_ci{ 5838c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 5848c2ecf20Sopenharmony_ci u8 data = S5K4AA_PAGE_MAP_2; 5858c2ecf20Sopenharmony_ci int err; 5868c2ecf20Sopenharmony_ci int hflip = sd->hflip->val; 5878c2ecf20Sopenharmony_ci int vflip = sd->vflip->val; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_CONF, "Set hvflip %d %d\n", hflip, vflip); 5908c2ecf20Sopenharmony_ci err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); 5918c2ecf20Sopenharmony_ci if (err < 0) 5928c2ecf20Sopenharmony_ci return err; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1); 5958c2ecf20Sopenharmony_ci if (err < 0) 5968c2ecf20Sopenharmony_ci return err; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci if (dmi_check_system(s5k4aa_vflip_dmi_table)) { 5998c2ecf20Sopenharmony_ci hflip = !hflip; 6008c2ecf20Sopenharmony_ci vflip = !vflip; 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci data = (data & 0x7f) | (vflip << 7) | (hflip << 6); 6048c2ecf20Sopenharmony_ci err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); 6058c2ecf20Sopenharmony_ci if (err < 0) 6068c2ecf20Sopenharmony_ci return err; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); 6098c2ecf20Sopenharmony_ci if (err < 0) 6108c2ecf20Sopenharmony_ci return err; 6118c2ecf20Sopenharmony_ci if (hflip) 6128c2ecf20Sopenharmony_ci data &= 0xfe; 6138c2ecf20Sopenharmony_ci else 6148c2ecf20Sopenharmony_ci data |= 0x01; 6158c2ecf20Sopenharmony_ci err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); 6168c2ecf20Sopenharmony_ci if (err < 0) 6178c2ecf20Sopenharmony_ci return err; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); 6208c2ecf20Sopenharmony_ci if (err < 0) 6218c2ecf20Sopenharmony_ci return err; 6228c2ecf20Sopenharmony_ci if (vflip) 6238c2ecf20Sopenharmony_ci data &= 0xfe; 6248c2ecf20Sopenharmony_ci else 6258c2ecf20Sopenharmony_ci data |= 0x01; 6268c2ecf20Sopenharmony_ci err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); 6278c2ecf20Sopenharmony_ci if (err < 0) 6288c2ecf20Sopenharmony_ci return err; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci return 0; 6318c2ecf20Sopenharmony_ci} 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_cistatic int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val) 6348c2ecf20Sopenharmony_ci{ 6358c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 6368c2ecf20Sopenharmony_ci u8 data = S5K4AA_PAGE_MAP_2; 6378c2ecf20Sopenharmony_ci int err; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_CONF, "Set gain to %d\n", val); 6408c2ecf20Sopenharmony_ci err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); 6418c2ecf20Sopenharmony_ci if (err < 0) 6428c2ecf20Sopenharmony_ci return err; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci data = val & 0xff; 6458c2ecf20Sopenharmony_ci err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci return err; 6488c2ecf20Sopenharmony_ci} 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_cistatic int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val) 6518c2ecf20Sopenharmony_ci{ 6528c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 6538c2ecf20Sopenharmony_ci u8 data = S5K4AA_PAGE_MAP_2; 6548c2ecf20Sopenharmony_ci int err; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_CONF, "Set brightness to %d\n", val); 6578c2ecf20Sopenharmony_ci err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); 6588c2ecf20Sopenharmony_ci if (err < 0) 6598c2ecf20Sopenharmony_ci return err; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci data = val & 0xff; 6628c2ecf20Sopenharmony_ci return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1); 6638c2ecf20Sopenharmony_ci} 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_cistatic int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val) 6668c2ecf20Sopenharmony_ci{ 6678c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 6688c2ecf20Sopenharmony_ci u8 data = S5K4AA_PAGE_MAP_2; 6698c2ecf20Sopenharmony_ci int err; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_CONF, "Set noise to %d\n", val); 6728c2ecf20Sopenharmony_ci err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); 6738c2ecf20Sopenharmony_ci if (err < 0) 6748c2ecf20Sopenharmony_ci return err; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci data = val & 0x01; 6778c2ecf20Sopenharmony_ci return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1); 6788c2ecf20Sopenharmony_ci} 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_cistatic int s5k4aa_s_ctrl(struct v4l2_ctrl *ctrl) 6818c2ecf20Sopenharmony_ci{ 6828c2ecf20Sopenharmony_ci struct gspca_dev *gspca_dev = 6838c2ecf20Sopenharmony_ci container_of(ctrl->handler, struct gspca_dev, ctrl_handler); 6848c2ecf20Sopenharmony_ci int err; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci if (!gspca_dev->streaming) 6878c2ecf20Sopenharmony_ci return 0; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci switch (ctrl->id) { 6908c2ecf20Sopenharmony_ci case V4L2_CID_BRIGHTNESS: 6918c2ecf20Sopenharmony_ci err = s5k4aa_set_brightness(gspca_dev, ctrl->val); 6928c2ecf20Sopenharmony_ci break; 6938c2ecf20Sopenharmony_ci case V4L2_CID_EXPOSURE: 6948c2ecf20Sopenharmony_ci err = s5k4aa_set_exposure(gspca_dev, ctrl->val); 6958c2ecf20Sopenharmony_ci break; 6968c2ecf20Sopenharmony_ci case V4L2_CID_GAIN: 6978c2ecf20Sopenharmony_ci err = s5k4aa_set_gain(gspca_dev, ctrl->val); 6988c2ecf20Sopenharmony_ci break; 6998c2ecf20Sopenharmony_ci case V4L2_CID_SHARPNESS: 7008c2ecf20Sopenharmony_ci err = s5k4aa_set_noise(gspca_dev, ctrl->val); 7018c2ecf20Sopenharmony_ci break; 7028c2ecf20Sopenharmony_ci case V4L2_CID_HFLIP: 7038c2ecf20Sopenharmony_ci err = s5k4aa_set_hvflip(gspca_dev); 7048c2ecf20Sopenharmony_ci break; 7058c2ecf20Sopenharmony_ci default: 7068c2ecf20Sopenharmony_ci return -EINVAL; 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci return err; 7108c2ecf20Sopenharmony_ci} 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_civoid s5k4aa_disconnect(struct sd *sd) 7138c2ecf20Sopenharmony_ci{ 7148c2ecf20Sopenharmony_ci sd->sensor = NULL; 7158c2ecf20Sopenharmony_ci} 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_cistatic void s5k4aa_dump_registers(struct sd *sd) 7188c2ecf20Sopenharmony_ci{ 7198c2ecf20Sopenharmony_ci int address; 7208c2ecf20Sopenharmony_ci u8 page, old_page; 7218c2ecf20Sopenharmony_ci m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1); 7228c2ecf20Sopenharmony_ci for (page = 0; page < 16; page++) { 7238c2ecf20Sopenharmony_ci m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1); 7248c2ecf20Sopenharmony_ci pr_info("Dumping the s5k4aa register state for page 0x%x\n", 7258c2ecf20Sopenharmony_ci page); 7268c2ecf20Sopenharmony_ci for (address = 0; address <= 0xff; address++) { 7278c2ecf20Sopenharmony_ci u8 value = 0; 7288c2ecf20Sopenharmony_ci m5602_read_sensor(sd, address, &value, 1); 7298c2ecf20Sopenharmony_ci pr_info("register 0x%x contains 0x%x\n", 7308c2ecf20Sopenharmony_ci address, value); 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci pr_info("s5k4aa register state dump complete\n"); 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci for (page = 0; page < 16; page++) { 7368c2ecf20Sopenharmony_ci m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1); 7378c2ecf20Sopenharmony_ci pr_info("Probing for which registers that are read/write for page 0x%x\n", 7388c2ecf20Sopenharmony_ci page); 7398c2ecf20Sopenharmony_ci for (address = 0; address <= 0xff; address++) { 7408c2ecf20Sopenharmony_ci u8 old_value, ctrl_value, test_value = 0xff; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci m5602_read_sensor(sd, address, &old_value, 1); 7438c2ecf20Sopenharmony_ci m5602_write_sensor(sd, address, &test_value, 1); 7448c2ecf20Sopenharmony_ci m5602_read_sensor(sd, address, &ctrl_value, 1); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci if (ctrl_value == test_value) 7478c2ecf20Sopenharmony_ci pr_info("register 0x%x is writeable\n", 7488c2ecf20Sopenharmony_ci address); 7498c2ecf20Sopenharmony_ci else 7508c2ecf20Sopenharmony_ci pr_info("register 0x%x is read only\n", 7518c2ecf20Sopenharmony_ci address); 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci /* Restore original value */ 7548c2ecf20Sopenharmony_ci m5602_write_sensor(sd, address, &old_value, 1); 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci } 7578c2ecf20Sopenharmony_ci pr_info("Read/write register probing complete\n"); 7588c2ecf20Sopenharmony_ci m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1); 7598c2ecf20Sopenharmony_ci} 760