cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

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}