m5602_s5k4aa.c (21266B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Driver for the s5k4aa sensor 4 * 5 * Copyright (C) 2008 Erik Andrén 6 * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. 7 * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br> 8 * 9 * Portions of code to USB interface and ALi driver software, 10 * Copyright (c) 2006 Willem Duinker 11 * v4l2 interface modeled after the V4L2 driver 12 * for SN9C10x PC Camera Controllers 13 */ 14 15#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 16 17#include "m5602_s5k4aa.h" 18 19static const unsigned char preinit_s5k4aa[][4] = { 20 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, 21 {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, 22 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, 23 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, 24 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, 25 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00}, 26 {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00}, 27 28 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, 29 {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00}, 30 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00}, 31 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00}, 32 {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00}, 33 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00}, 34 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, 35 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, 36 {BRIDGE, M5602_XB_GPIO_DAT, 0x00, 0x00}, 37 {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, 38 {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, 39 {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, 40 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, 41 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, 42 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, 43 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00}, 44 45 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, 46 {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, 47 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, 48 {BRIDGE, M5602_XB_GPIO_DAT, 0x14, 0x00}, 49 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, 50 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00}, 51 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, 52 {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00}, 53 {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, 54 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00}, 55 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, 56 {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, 57 {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00}, 58 59 {SENSOR, S5K4AA_PAGE_MAP, 0x00, 0x00} 60}; 61 62static const unsigned char init_s5k4aa[][4] = { 63 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, 64 {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, 65 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, 66 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, 67 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, 68 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00}, 69 {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00}, 70 71 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, 72 {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00}, 73 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00}, 74 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00}, 75 {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00}, 76 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00}, 77 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, 78 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, 79 {BRIDGE, M5602_XB_GPIO_DAT, 0x00, 0x00}, 80 {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, 81 {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, 82 {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, 83 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, 84 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, 85 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, 86 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00}, 87 88 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, 89 {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, 90 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, 91 {BRIDGE, M5602_XB_GPIO_DAT, 0x14, 0x00}, 92 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, 93 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00}, 94 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, 95 {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00}, 96 {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, 97 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00}, 98 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, 99 {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, 100 {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00}, 101 102 {SENSOR, S5K4AA_PAGE_MAP, 0x07, 0x00}, 103 {SENSOR, 0x36, 0x01, 0x00}, 104 {SENSOR, S5K4AA_PAGE_MAP, 0x00, 0x00}, 105 {SENSOR, 0x7b, 0xff, 0x00}, 106 {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, 107 {SENSOR, 0x0c, 0x05, 0x00}, 108 {SENSOR, 0x02, 0x0e, 0x00}, 109 {SENSOR, S5K4AA_READ_MODE, 0xa0, 0x00}, 110 {SENSOR, 0x37, 0x00, 0x00}, 111}; 112 113static const unsigned char VGA_s5k4aa[][4] = { 114 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, 115 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, 116 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, 117 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00}, 118 {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, 119 {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, 120 {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, 121 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 122 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 123 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 124 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 125 /* VSYNC_PARA, VSYNC_PARA : img height 480 = 0x01e0 */ 126 {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00}, 127 {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0, 0x00}, 128 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 129 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 130 {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, 131 {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, 132 {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, 133 {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, 134 /* HSYNC_PARA, HSYNC_PARA : img width 640 = 0x0280 */ 135 {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00}, 136 {BRIDGE, M5602_XB_HSYNC_PARA, 0x80, 0x00}, 137 {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, 138 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, 139 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, /* 48 MHz */ 140 141 {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, 142 {SENSOR, S5K4AA_READ_MODE, S5K4AA_RM_H_FLIP | S5K4AA_RM_ROW_SKIP_2X 143 | S5K4AA_RM_COL_SKIP_2X, 0x00}, 144 /* 0x37 : Fix image stability when light is too bright and improves 145 * image quality in 640x480, but worsens it in 1280x1024 */ 146 {SENSOR, 0x37, 0x01, 0x00}, 147 /* ROWSTART_HI, ROWSTART_LO : 10 + (1024-960)/2 = 42 = 0x002a */ 148 {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00}, 149 {SENSOR, S5K4AA_ROWSTART_LO, 0x29, 0x00}, 150 {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00}, 151 {SENSOR, S5K4AA_COLSTART_LO, 0x0c, 0x00}, 152 /* window_height_hi, window_height_lo : 960 = 0x03c0 */ 153 {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x03, 0x00}, 154 {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0xc0, 0x00}, 155 /* window_width_hi, window_width_lo : 1280 = 0x0500 */ 156 {SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00}, 157 {SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x00, 0x00}, 158 {SENSOR, S5K4AA_H_BLANK_HI__, 0x00, 0x00}, 159 {SENSOR, S5K4AA_H_BLANK_LO__, 0xa8, 0x00}, /* helps to sync... */ 160 {SENSOR, S5K4AA_EXPOSURE_HI, 0x01, 0x00}, 161 {SENSOR, S5K4AA_EXPOSURE_LO, 0x00, 0x00}, 162 {SENSOR, 0x11, 0x04, 0x00}, 163 {SENSOR, 0x12, 0xc3, 0x00}, 164 {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, 165 {SENSOR, 0x02, 0x0e, 0x00}, 166}; 167 168static const unsigned char SXGA_s5k4aa[][4] = { 169 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, 170 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, 171 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, 172 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00}, 173 {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, 174 {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, 175 {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, 176 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 177 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 178 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 179 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 180 /* VSYNC_PARA, VSYNC_PARA : img height 1024 = 0x0400 */ 181 {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00}, 182 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 183 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 184 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 185 {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, 186 {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, 187 {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, 188 {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, 189 /* HSYNC_PARA, HSYNC_PARA : img width 1280 = 0x0500 */ 190 {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00}, 191 {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, 192 {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, 193 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, 194 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, /* 48 MHz */ 195 196 {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, 197 {SENSOR, S5K4AA_READ_MODE, S5K4AA_RM_H_FLIP, 0x00}, 198 {SENSOR, 0x37, 0x01, 0x00}, 199 {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00}, 200 {SENSOR, S5K4AA_ROWSTART_LO, 0x09, 0x00}, 201 {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00}, 202 {SENSOR, S5K4AA_COLSTART_LO, 0x0a, 0x00}, 203 {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x04, 0x00}, 204 {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0x00, 0x00}, 205 {SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00}, 206 {SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x00, 0x00}, 207 {SENSOR, S5K4AA_H_BLANK_HI__, 0x01, 0x00}, 208 {SENSOR, S5K4AA_H_BLANK_LO__, 0xa8, 0x00}, 209 {SENSOR, S5K4AA_EXPOSURE_HI, 0x01, 0x00}, 210 {SENSOR, S5K4AA_EXPOSURE_LO, 0x00, 0x00}, 211 {SENSOR, 0x11, 0x04, 0x00}, 212 {SENSOR, 0x12, 0xc3, 0x00}, 213 {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, 214 {SENSOR, 0x02, 0x0e, 0x00}, 215}; 216 217 218static int s5k4aa_s_ctrl(struct v4l2_ctrl *ctrl); 219static void s5k4aa_dump_registers(struct sd *sd); 220 221static const struct v4l2_ctrl_ops s5k4aa_ctrl_ops = { 222 .s_ctrl = s5k4aa_s_ctrl, 223}; 224 225static 226 const 227 struct dmi_system_id s5k4aa_vflip_dmi_table[] = { 228 { 229 .ident = "BRUNEINIT", 230 .matches = { 231 DMI_MATCH(DMI_SYS_VENDOR, "BRUNENIT"), 232 DMI_MATCH(DMI_PRODUCT_NAME, "BRUNENIT"), 233 DMI_MATCH(DMI_BOARD_VERSION, "00030D0000000001") 234 } 235 }, { 236 .ident = "Fujitsu-Siemens Amilo Xa 2528", 237 .matches = { 238 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 239 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528") 240 } 241 }, { 242 .ident = "Fujitsu-Siemens Amilo Xi 2428", 243 .matches = { 244 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 245 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2428") 246 } 247 }, { 248 .ident = "Fujitsu-Siemens Amilo Xi 2528", 249 .matches = { 250 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 251 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2528") 252 } 253 }, { 254 .ident = "Fujitsu-Siemens Amilo Xi 2550", 255 .matches = { 256 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 257 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550") 258 } 259 }, { 260 .ident = "Fujitsu-Siemens Amilo Pa 2548", 261 .matches = { 262 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 263 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2548") 264 } 265 }, { 266 .ident = "Fujitsu-Siemens Amilo Pi 2530", 267 .matches = { 268 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 269 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 2530") 270 } 271 }, { 272 .ident = "MSI GX700", 273 .matches = { 274 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), 275 DMI_MATCH(DMI_PRODUCT_NAME, "GX700"), 276 DMI_MATCH(DMI_BIOS_DATE, "12/02/2008") 277 } 278 }, { 279 .ident = "MSI GX700", 280 .matches = { 281 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), 282 DMI_MATCH(DMI_PRODUCT_NAME, "GX700"), 283 DMI_MATCH(DMI_BIOS_DATE, "07/26/2007") 284 } 285 }, { 286 .ident = "MSI GX700", 287 .matches = { 288 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), 289 DMI_MATCH(DMI_PRODUCT_NAME, "GX700"), 290 DMI_MATCH(DMI_BIOS_DATE, "07/19/2007") 291 } 292 }, { 293 .ident = "MSI GX700/GX705/EX700", 294 .matches = { 295 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), 296 DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700") 297 } 298 }, { 299 .ident = "MSI L735", 300 .matches = { 301 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), 302 DMI_MATCH(DMI_PRODUCT_NAME, "MS-1717X") 303 } 304 }, { 305 .ident = "Lenovo Y300", 306 .matches = { 307 DMI_MATCH(DMI_SYS_VENDOR, "L3000 Y300"), 308 DMI_MATCH(DMI_PRODUCT_NAME, "Y300") 309 } 310 }, 311 { } 312}; 313 314static struct v4l2_pix_format s5k4aa_modes[] = { 315 { 316 640, 317 480, 318 V4L2_PIX_FMT_SBGGR8, 319 V4L2_FIELD_NONE, 320 .sizeimage = 321 640 * 480, 322 .bytesperline = 640, 323 .colorspace = V4L2_COLORSPACE_SRGB, 324 .priv = 0 325 }, 326 { 327 1280, 328 1024, 329 V4L2_PIX_FMT_SBGGR8, 330 V4L2_FIELD_NONE, 331 .sizeimage = 332 1280 * 1024, 333 .bytesperline = 1280, 334 .colorspace = V4L2_COLORSPACE_SRGB, 335 .priv = 0 336 } 337}; 338 339int s5k4aa_probe(struct sd *sd) 340{ 341 u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 342 const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75}; 343 struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; 344 int i, err = 0; 345 346 if (force_sensor) { 347 if (force_sensor == S5K4AA_SENSOR) { 348 pr_info("Forcing a %s sensor\n", s5k4aa.name); 349 goto sensor_found; 350 } 351 /* If we want to force another sensor, don't try to probe this 352 * one */ 353 return -ENODEV; 354 } 355 356 gspca_dbg(gspca_dev, D_PROBE, "Probing for a s5k4aa sensor\n"); 357 358 /* Preinit the sensor */ 359 for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) { 360 u8 data[2] = {0x00, 0x00}; 361 362 switch (preinit_s5k4aa[i][0]) { 363 case BRIDGE: 364 err = m5602_write_bridge(sd, 365 preinit_s5k4aa[i][1], 366 preinit_s5k4aa[i][2]); 367 break; 368 369 case SENSOR: 370 data[0] = preinit_s5k4aa[i][2]; 371 err = m5602_write_sensor(sd, 372 preinit_s5k4aa[i][1], 373 data, 1); 374 break; 375 376 case SENSOR_LONG: 377 data[0] = preinit_s5k4aa[i][2]; 378 data[1] = preinit_s5k4aa[i][3]; 379 err = m5602_write_sensor(sd, 380 preinit_s5k4aa[i][1], 381 data, 2); 382 break; 383 default: 384 pr_info("Invalid stream command, exiting init\n"); 385 return -EINVAL; 386 } 387 } 388 389 /* Test some registers, but we don't know their exact meaning yet */ 390 if (m5602_read_sensor(sd, 0x00, prod_id, 2)) 391 return -ENODEV; 392 if (m5602_read_sensor(sd, 0x02, prod_id+2, 2)) 393 return -ENODEV; 394 if (m5602_read_sensor(sd, 0x04, prod_id+4, 2)) 395 return -ENODEV; 396 397 if (memcmp(prod_id, expected_prod_id, sizeof(prod_id))) 398 return -ENODEV; 399 else 400 pr_info("Detected a s5k4aa sensor\n"); 401 402sensor_found: 403 sd->gspca_dev.cam.cam_mode = s5k4aa_modes; 404 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes); 405 406 return 0; 407} 408 409int s5k4aa_start(struct sd *sd) 410{ 411 int i, err = 0; 412 u8 data[2]; 413 struct cam *cam = &sd->gspca_dev.cam; 414 struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; 415 416 switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) { 417 case 1280: 418 gspca_dbg(gspca_dev, D_CONF, "Configuring camera for SXGA mode\n"); 419 420 for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) { 421 switch (SXGA_s5k4aa[i][0]) { 422 case BRIDGE: 423 err = m5602_write_bridge(sd, 424 SXGA_s5k4aa[i][1], 425 SXGA_s5k4aa[i][2]); 426 break; 427 428 case SENSOR: 429 data[0] = SXGA_s5k4aa[i][2]; 430 err = m5602_write_sensor(sd, 431 SXGA_s5k4aa[i][1], 432 data, 1); 433 break; 434 435 case SENSOR_LONG: 436 data[0] = SXGA_s5k4aa[i][2]; 437 data[1] = SXGA_s5k4aa[i][3]; 438 err = m5602_write_sensor(sd, 439 SXGA_s5k4aa[i][1], 440 data, 2); 441 break; 442 443 default: 444 pr_err("Invalid stream command, exiting init\n"); 445 return -EINVAL; 446 } 447 } 448 break; 449 450 case 640: 451 gspca_dbg(gspca_dev, D_CONF, "Configuring camera for VGA mode\n"); 452 453 for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) { 454 switch (VGA_s5k4aa[i][0]) { 455 case BRIDGE: 456 err = m5602_write_bridge(sd, 457 VGA_s5k4aa[i][1], 458 VGA_s5k4aa[i][2]); 459 break; 460 461 case SENSOR: 462 data[0] = VGA_s5k4aa[i][2]; 463 err = m5602_write_sensor(sd, 464 VGA_s5k4aa[i][1], 465 data, 1); 466 break; 467 468 case SENSOR_LONG: 469 data[0] = VGA_s5k4aa[i][2]; 470 data[1] = VGA_s5k4aa[i][3]; 471 err = m5602_write_sensor(sd, 472 VGA_s5k4aa[i][1], 473 data, 2); 474 break; 475 476 default: 477 pr_err("Invalid stream command, exiting init\n"); 478 return -EINVAL; 479 } 480 } 481 break; 482 } 483 if (err < 0) 484 return err; 485 486 return 0; 487} 488 489int s5k4aa_init(struct sd *sd) 490{ 491 int i, err = 0; 492 493 for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) { 494 u8 data[2] = {0x00, 0x00}; 495 496 switch (init_s5k4aa[i][0]) { 497 case BRIDGE: 498 err = m5602_write_bridge(sd, 499 init_s5k4aa[i][1], 500 init_s5k4aa[i][2]); 501 break; 502 503 case SENSOR: 504 data[0] = init_s5k4aa[i][2]; 505 err = m5602_write_sensor(sd, 506 init_s5k4aa[i][1], data, 1); 507 break; 508 509 case SENSOR_LONG: 510 data[0] = init_s5k4aa[i][2]; 511 data[1] = init_s5k4aa[i][3]; 512 err = m5602_write_sensor(sd, 513 init_s5k4aa[i][1], data, 2); 514 break; 515 default: 516 pr_info("Invalid stream command, exiting init\n"); 517 return -EINVAL; 518 } 519 } 520 521 if (dump_sensor) 522 s5k4aa_dump_registers(sd); 523 524 return err; 525} 526 527int s5k4aa_init_controls(struct sd *sd) 528{ 529 struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler; 530 531 sd->gspca_dev.vdev.ctrl_handler = hdl; 532 v4l2_ctrl_handler_init(hdl, 6); 533 534 v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_BRIGHTNESS, 535 0, 0x1f, 1, S5K4AA_DEFAULT_BRIGHTNESS); 536 537 v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_EXPOSURE, 538 13, 0xfff, 1, 0x100); 539 540 v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_GAIN, 541 0, 127, 1, S5K4AA_DEFAULT_GAIN); 542 543 v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_SHARPNESS, 544 0, 1, 1, 1); 545 546 sd->hflip = v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_HFLIP, 547 0, 1, 1, 0); 548 sd->vflip = v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_VFLIP, 549 0, 1, 1, 0); 550 551 if (hdl->error) { 552 pr_err("Could not initialize controls\n"); 553 return hdl->error; 554 } 555 556 v4l2_ctrl_cluster(2, &sd->hflip); 557 558 return 0; 559} 560 561static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val) 562{ 563 struct sd *sd = (struct sd *) gspca_dev; 564 u8 data = S5K4AA_PAGE_MAP_2; 565 int err; 566 567 gspca_dbg(gspca_dev, D_CONF, "Set exposure to %d\n", val); 568 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); 569 if (err < 0) 570 return err; 571 data = (val >> 8) & 0xff; 572 err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1); 573 if (err < 0) 574 return err; 575 data = val & 0xff; 576 err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1); 577 578 return err; 579} 580 581static int s5k4aa_set_hvflip(struct gspca_dev *gspca_dev) 582{ 583 struct sd *sd = (struct sd *) gspca_dev; 584 u8 data = S5K4AA_PAGE_MAP_2; 585 int err; 586 int hflip = sd->hflip->val; 587 int vflip = sd->vflip->val; 588 589 gspca_dbg(gspca_dev, D_CONF, "Set hvflip %d %d\n", hflip, vflip); 590 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); 591 if (err < 0) 592 return err; 593 594 err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1); 595 if (err < 0) 596 return err; 597 598 if (dmi_check_system(s5k4aa_vflip_dmi_table)) { 599 hflip = !hflip; 600 vflip = !vflip; 601 } 602 603 data = (data & 0x7f) | (vflip << 7) | (hflip << 6); 604 err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); 605 if (err < 0) 606 return err; 607 608 err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); 609 if (err < 0) 610 return err; 611 if (hflip) 612 data &= 0xfe; 613 else 614 data |= 0x01; 615 err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); 616 if (err < 0) 617 return err; 618 619 err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); 620 if (err < 0) 621 return err; 622 if (vflip) 623 data &= 0xfe; 624 else 625 data |= 0x01; 626 err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); 627 if (err < 0) 628 return err; 629 630 return 0; 631} 632 633static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val) 634{ 635 struct sd *sd = (struct sd *) gspca_dev; 636 u8 data = S5K4AA_PAGE_MAP_2; 637 int err; 638 639 gspca_dbg(gspca_dev, D_CONF, "Set gain to %d\n", val); 640 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); 641 if (err < 0) 642 return err; 643 644 data = val & 0xff; 645 err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1); 646 647 return err; 648} 649 650static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val) 651{ 652 struct sd *sd = (struct sd *) gspca_dev; 653 u8 data = S5K4AA_PAGE_MAP_2; 654 int err; 655 656 gspca_dbg(gspca_dev, D_CONF, "Set brightness to %d\n", val); 657 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); 658 if (err < 0) 659 return err; 660 661 data = val & 0xff; 662 return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1); 663} 664 665static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val) 666{ 667 struct sd *sd = (struct sd *) gspca_dev; 668 u8 data = S5K4AA_PAGE_MAP_2; 669 int err; 670 671 gspca_dbg(gspca_dev, D_CONF, "Set noise to %d\n", val); 672 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); 673 if (err < 0) 674 return err; 675 676 data = val & 0x01; 677 return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1); 678} 679 680static int s5k4aa_s_ctrl(struct v4l2_ctrl *ctrl) 681{ 682 struct gspca_dev *gspca_dev = 683 container_of(ctrl->handler, struct gspca_dev, ctrl_handler); 684 int err; 685 686 if (!gspca_dev->streaming) 687 return 0; 688 689 switch (ctrl->id) { 690 case V4L2_CID_BRIGHTNESS: 691 err = s5k4aa_set_brightness(gspca_dev, ctrl->val); 692 break; 693 case V4L2_CID_EXPOSURE: 694 err = s5k4aa_set_exposure(gspca_dev, ctrl->val); 695 break; 696 case V4L2_CID_GAIN: 697 err = s5k4aa_set_gain(gspca_dev, ctrl->val); 698 break; 699 case V4L2_CID_SHARPNESS: 700 err = s5k4aa_set_noise(gspca_dev, ctrl->val); 701 break; 702 case V4L2_CID_HFLIP: 703 err = s5k4aa_set_hvflip(gspca_dev); 704 break; 705 default: 706 return -EINVAL; 707 } 708 709 return err; 710} 711 712void s5k4aa_disconnect(struct sd *sd) 713{ 714 sd->sensor = NULL; 715} 716 717static void s5k4aa_dump_registers(struct sd *sd) 718{ 719 int address; 720 u8 page, old_page; 721 m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1); 722 for (page = 0; page < 16; page++) { 723 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1); 724 pr_info("Dumping the s5k4aa register state for page 0x%x\n", 725 page); 726 for (address = 0; address <= 0xff; address++) { 727 u8 value = 0; 728 m5602_read_sensor(sd, address, &value, 1); 729 pr_info("register 0x%x contains 0x%x\n", 730 address, value); 731 } 732 } 733 pr_info("s5k4aa register state dump complete\n"); 734 735 for (page = 0; page < 16; page++) { 736 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1); 737 pr_info("Probing for which registers that are read/write for page 0x%x\n", 738 page); 739 for (address = 0; address <= 0xff; address++) { 740 u8 old_value, ctrl_value, test_value = 0xff; 741 742 m5602_read_sensor(sd, address, &old_value, 1); 743 m5602_write_sensor(sd, address, &test_value, 1); 744 m5602_read_sensor(sd, address, &ctrl_value, 1); 745 746 if (ctrl_value == test_value) 747 pr_info("register 0x%x is writeable\n", 748 address); 749 else 750 pr_info("register 0x%x is read only\n", 751 address); 752 753 /* Restore original value */ 754 m5602_write_sensor(sd, address, &old_value, 1); 755 } 756 } 757 pr_info("Read/write register probing complete\n"); 758 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1); 759}