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_ov9650.c (20438B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2
      3/*
      4 * Driver for the ov9650 sensor
      5 *
      6 * Copyright (C) 2008 Erik Andrén
      7 * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
      8 * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
      9 *
     10 * Portions of code to USB interface and ALi driver software,
     11 * Copyright (c) 2006 Willem Duinker
     12 * v4l2 interface modeled after the V4L2 driver
     13 * for SN9C10x PC Camera Controllers
     14 */
     15
     16#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     17
     18#include "m5602_ov9650.h"
     19
     20static int ov9650_s_ctrl(struct v4l2_ctrl *ctrl);
     21static void ov9650_dump_registers(struct sd *sd);
     22
     23static const unsigned char preinit_ov9650[][3] = {
     24	/* [INITCAM] */
     25	{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
     26	{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
     27	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
     28	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
     29	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
     30	{BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
     31
     32	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x08},
     33	{BRIDGE, M5602_XB_GPIO_DIR, 0x05},
     34	{BRIDGE, M5602_XB_GPIO_DAT, 0x04},
     35	{BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
     36	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
     37	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
     38	{BRIDGE, M5602_XB_GPIO_DAT, 0x00},
     39	{BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a},
     40	/* Reset chip */
     41	{SENSOR, OV9650_COM7, OV9650_REGISTER_RESET},
     42	/* Enable double clock */
     43	{SENSOR, OV9650_CLKRC, 0x80},
     44	/* Do something out of spec with the power */
     45	{SENSOR, OV9650_OFON, 0x40}
     46};
     47
     48static const unsigned char init_ov9650[][3] = {
     49	/* [INITCAM] */
     50	{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
     51	{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
     52	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
     53	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
     54	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
     55	{BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
     56
     57	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x08},
     58	{BRIDGE, M5602_XB_GPIO_DIR, 0x05},
     59	{BRIDGE, M5602_XB_GPIO_DAT, 0x04},
     60	{BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
     61	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
     62	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
     63	{BRIDGE, M5602_XB_GPIO_DAT, 0x00},
     64	{BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a},
     65
     66	/* Reset chip */
     67	{SENSOR, OV9650_COM7, OV9650_REGISTER_RESET},
     68	/* One extra reset is needed in order to make the sensor behave
     69	   properly when resuming from ram, could be a timing issue */
     70	{SENSOR, OV9650_COM7, OV9650_REGISTER_RESET},
     71
     72	/* Enable double clock */
     73	{SENSOR, OV9650_CLKRC, 0x80},
     74	/* Do something out of spec with the power */
     75	{SENSOR, OV9650_OFON, 0x40},
     76
     77	/* Set fast AGC/AEC algorithm with unlimited step size */
     78	{SENSOR, OV9650_COM8, OV9650_FAST_AGC_AEC |
     79			      OV9650_AEC_UNLIM_STEP_SIZE},
     80
     81	{SENSOR, OV9650_CHLF, 0x10},
     82	{SENSOR, OV9650_ARBLM, 0xbf},
     83	{SENSOR, OV9650_ACOM38, 0x81},
     84	/* Turn off color matrix coefficient double option */
     85	{SENSOR, OV9650_COM16, 0x00},
     86	/* Enable color matrix for RGB/YUV, Delay Y channel,
     87	set output Y/UV delay to 1 */
     88	{SENSOR, OV9650_COM13, 0x19},
     89	/* Enable digital BLC, Set output mode to U Y V Y */
     90	{SENSOR, OV9650_TSLB, 0x0c},
     91	/* Limit the AGC/AEC stable upper region */
     92	{SENSOR, OV9650_COM24, 0x00},
     93	/* Enable HREF and some out of spec things */
     94	{SENSOR, OV9650_COM12, 0x73},
     95	/* Set all DBLC offset signs to positive and
     96	do some out of spec stuff */
     97	{SENSOR, OV9650_DBLC1, 0xdf},
     98	{SENSOR, OV9650_COM21, 0x06},
     99	{SENSOR, OV9650_RSVD35, 0x91},
    100	/* Necessary, no camera stream without it */
    101	{SENSOR, OV9650_RSVD16, 0x06},
    102	{SENSOR, OV9650_RSVD94, 0x99},
    103	{SENSOR, OV9650_RSVD95, 0x99},
    104	{SENSOR, OV9650_RSVD96, 0x04},
    105	/* Enable full range output */
    106	{SENSOR, OV9650_COM15, 0x0},
    107	/* Enable HREF at optical black, enable ADBLC bias,
    108	enable ADBLC, reset timings at format change */
    109	{SENSOR, OV9650_COM6, 0x4b},
    110	/* Subtract 32 from the B channel bias */
    111	{SENSOR, OV9650_BBIAS, 0xa0},
    112	/* Subtract 32 from the Gb channel bias */
    113	{SENSOR, OV9650_GbBIAS, 0xa0},
    114	/* Do not bypass the analog BLC and to some out of spec stuff */
    115	{SENSOR, OV9650_Gr_COM, 0x00},
    116	/* Subtract 32 from the R channel bias */
    117	{SENSOR, OV9650_RBIAS, 0xa0},
    118	/* Subtract 32 from the R channel bias */
    119	{SENSOR, OV9650_RBIAS, 0x0},
    120	{SENSOR, OV9650_COM26, 0x80},
    121	{SENSOR, OV9650_ACOMA9, 0x98},
    122	/* Set the AGC/AEC stable region upper limit */
    123	{SENSOR, OV9650_AEW, 0x68},
    124	/* Set the AGC/AEC stable region lower limit */
    125	{SENSOR, OV9650_AEB, 0x5c},
    126	/* Set the high and low limit nibbles to 3 */
    127	{SENSOR, OV9650_VPT, 0xc3},
    128	/* Set the Automatic Gain Ceiling (AGC) to 128x,
    129	drop VSYNC at frame drop,
    130	limit exposure timing,
    131	drop frame when the AEC step is larger than the exposure gap */
    132	{SENSOR, OV9650_COM9, 0x6e},
    133	/* Set VSYNC negative, Set RESET to SLHS (slave mode horizontal sync)
    134	and set PWDN to SLVS (slave mode vertical sync) */
    135	{SENSOR, OV9650_COM10, 0x42},
    136	/* Set horizontal column start high to default value */
    137	{SENSOR, OV9650_HSTART, 0x1a}, /* 210 */
    138	/* Set horizontal column end */
    139	{SENSOR, OV9650_HSTOP, 0xbf}, /* 1534 */
    140	/* Complementing register to the two writes above */
    141	{SENSOR, OV9650_HREF, 0xb2},
    142	/* Set vertical row start high bits */
    143	{SENSOR, OV9650_VSTRT, 0x02},
    144	/* Set vertical row end low bits */
    145	{SENSOR, OV9650_VSTOP, 0x7e},
    146	/* Set complementing vertical frame control */
    147	{SENSOR, OV9650_VREF, 0x10},
    148	{SENSOR, OV9650_ADC, 0x04},
    149	{SENSOR, OV9650_HV, 0x40},
    150
    151	/* Enable denoise, and white-pixel erase */
    152	{SENSOR, OV9650_COM22, OV9650_DENOISE_ENABLE |
    153		 OV9650_WHITE_PIXEL_ENABLE |
    154		 OV9650_WHITE_PIXEL_OPTION},
    155
    156	/* Enable VARIOPIXEL */
    157	{SENSOR, OV9650_COM3, OV9650_VARIOPIXEL},
    158	{SENSOR, OV9650_COM4, OV9650_QVGA_VARIOPIXEL},
    159
    160	/* Put the sensor in soft sleep mode */
    161	{SENSOR, OV9650_COM2, OV9650_SOFT_SLEEP | OV9650_OUTPUT_DRIVE_2X},
    162};
    163
    164static const unsigned char res_init_ov9650[][3] = {
    165	{SENSOR, OV9650_COM2, OV9650_OUTPUT_DRIVE_2X},
    166
    167	{BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x82},
    168	{BRIDGE, M5602_XB_LINE_OF_FRAME_L, 0x00},
    169	{BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82},
    170	{BRIDGE, M5602_XB_PIX_OF_LINE_L, 0x00},
    171	{BRIDGE, M5602_XB_SIG_INI, 0x01}
    172};
    173
    174/* Vertically and horizontally flips the image if matched, needed for machines
    175   where the sensor is mounted upside down */
    176static
    177    const
    178	struct dmi_system_id ov9650_flip_dmi_table[] = {
    179	{
    180		.ident = "ASUS A6Ja",
    181		.matches = {
    182			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
    183			DMI_MATCH(DMI_PRODUCT_NAME, "A6J")
    184		}
    185	},
    186	{
    187		.ident = "ASUS A6JC",
    188		.matches = {
    189			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
    190			DMI_MATCH(DMI_PRODUCT_NAME, "A6JC")
    191		}
    192	},
    193	{
    194		.ident = "ASUS A6K",
    195		.matches = {
    196			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
    197			DMI_MATCH(DMI_PRODUCT_NAME, "A6K")
    198		}
    199	},
    200	{
    201		.ident = "ASUS A6Kt",
    202		.matches = {
    203			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
    204			DMI_MATCH(DMI_PRODUCT_NAME, "A6Kt")
    205		}
    206	},
    207	{
    208		.ident = "ASUS A6VA",
    209		.matches = {
    210			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
    211			DMI_MATCH(DMI_PRODUCT_NAME, "A6VA")
    212		}
    213	},
    214	{
    215
    216		.ident = "ASUS A6VC",
    217		.matches = {
    218			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
    219			DMI_MATCH(DMI_PRODUCT_NAME, "A6VC")
    220		}
    221	},
    222	{
    223		.ident = "ASUS A6VM",
    224		.matches = {
    225			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
    226			DMI_MATCH(DMI_PRODUCT_NAME, "A6VM")
    227		}
    228	},
    229	{
    230		.ident = "ASUS A7V",
    231		.matches = {
    232			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
    233			DMI_MATCH(DMI_PRODUCT_NAME, "A7V")
    234		}
    235	},
    236	{
    237		.ident = "Alienware Aurora m9700",
    238		.matches = {
    239			DMI_MATCH(DMI_SYS_VENDOR, "alienware"),
    240			DMI_MATCH(DMI_PRODUCT_NAME, "Aurora m9700")
    241		}
    242	},
    243	{}
    244};
    245
    246static struct v4l2_pix_format ov9650_modes[] = {
    247	{
    248		176,
    249		144,
    250		V4L2_PIX_FMT_SBGGR8,
    251		V4L2_FIELD_NONE,
    252		.sizeimage =
    253			176 * 144,
    254		.bytesperline = 176,
    255		.colorspace = V4L2_COLORSPACE_SRGB,
    256		.priv = 9
    257	}, {
    258		320,
    259		240,
    260		V4L2_PIX_FMT_SBGGR8,
    261		V4L2_FIELD_NONE,
    262		.sizeimage =
    263			320 * 240,
    264		.bytesperline = 320,
    265		.colorspace = V4L2_COLORSPACE_SRGB,
    266		.priv = 8
    267	}, {
    268		352,
    269		288,
    270		V4L2_PIX_FMT_SBGGR8,
    271		V4L2_FIELD_NONE,
    272		.sizeimage =
    273			352 * 288,
    274		.bytesperline = 352,
    275		.colorspace = V4L2_COLORSPACE_SRGB,
    276		.priv = 9
    277	}, {
    278		640,
    279		480,
    280		V4L2_PIX_FMT_SBGGR8,
    281		V4L2_FIELD_NONE,
    282		.sizeimage =
    283			640 * 480,
    284		.bytesperline = 640,
    285		.colorspace = V4L2_COLORSPACE_SRGB,
    286		.priv = 9
    287	}
    288};
    289
    290static const struct v4l2_ctrl_ops ov9650_ctrl_ops = {
    291	.s_ctrl = ov9650_s_ctrl,
    292};
    293
    294int ov9650_probe(struct sd *sd)
    295{
    296	int err = 0;
    297	u8 prod_id = 0, ver_id = 0, i;
    298	struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
    299
    300	if (force_sensor) {
    301		if (force_sensor == OV9650_SENSOR) {
    302			pr_info("Forcing an %s sensor\n", ov9650.name);
    303			goto sensor_found;
    304		}
    305		/* If we want to force another sensor,
    306		   don't try to probe this one */
    307		return -ENODEV;
    308	}
    309
    310	gspca_dbg(gspca_dev, D_PROBE, "Probing for an ov9650 sensor\n");
    311
    312	/* Run the pre-init before probing the sensor */
    313	for (i = 0; i < ARRAY_SIZE(preinit_ov9650) && !err; i++) {
    314		u8 data = preinit_ov9650[i][2];
    315		if (preinit_ov9650[i][0] == SENSOR)
    316			err = m5602_write_sensor(sd,
    317				preinit_ov9650[i][1], &data, 1);
    318		else
    319			err = m5602_write_bridge(sd,
    320				preinit_ov9650[i][1], data);
    321	}
    322
    323	if (err < 0)
    324		return err;
    325
    326	if (m5602_read_sensor(sd, OV9650_PID, &prod_id, 1))
    327		return -ENODEV;
    328
    329	if (m5602_read_sensor(sd, OV9650_VER, &ver_id, 1))
    330		return -ENODEV;
    331
    332	if ((prod_id == 0x96) && (ver_id == 0x52)) {
    333		pr_info("Detected an ov9650 sensor\n");
    334		goto sensor_found;
    335	}
    336	return -ENODEV;
    337
    338sensor_found:
    339	sd->gspca_dev.cam.cam_mode = ov9650_modes;
    340	sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov9650_modes);
    341
    342	return 0;
    343}
    344
    345int ov9650_init(struct sd *sd)
    346{
    347	int i, err = 0;
    348	u8 data;
    349
    350	if (dump_sensor)
    351		ov9650_dump_registers(sd);
    352
    353	for (i = 0; i < ARRAY_SIZE(init_ov9650) && !err; i++) {
    354		data = init_ov9650[i][2];
    355		if (init_ov9650[i][0] == SENSOR)
    356			err = m5602_write_sensor(sd, init_ov9650[i][1],
    357						  &data, 1);
    358		else
    359			err = m5602_write_bridge(sd, init_ov9650[i][1], data);
    360	}
    361
    362	return 0;
    363}
    364
    365int ov9650_init_controls(struct sd *sd)
    366{
    367	struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
    368
    369	sd->gspca_dev.vdev.ctrl_handler = hdl;
    370	v4l2_ctrl_handler_init(hdl, 9);
    371
    372	sd->auto_white_bal = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops,
    373					       V4L2_CID_AUTO_WHITE_BALANCE,
    374					       0, 1, 1, 1);
    375	sd->red_bal = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops,
    376					V4L2_CID_RED_BALANCE, 0, 255, 1,
    377					RED_GAIN_DEFAULT);
    378	sd->blue_bal = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops,
    379					V4L2_CID_BLUE_BALANCE, 0, 255, 1,
    380					BLUE_GAIN_DEFAULT);
    381
    382	sd->autoexpo = v4l2_ctrl_new_std_menu(hdl, &ov9650_ctrl_ops,
    383			  V4L2_CID_EXPOSURE_AUTO, 1, 0, V4L2_EXPOSURE_AUTO);
    384	sd->expo = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, V4L2_CID_EXPOSURE,
    385			  0, 0x1ff, 4, EXPOSURE_DEFAULT);
    386
    387	sd->autogain = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops,
    388					 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
    389	sd->gain = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, V4L2_CID_GAIN, 0,
    390				     0x3ff, 1, GAIN_DEFAULT);
    391
    392	sd->hflip = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, V4L2_CID_HFLIP,
    393				      0, 1, 1, 0);
    394	sd->vflip = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, V4L2_CID_VFLIP,
    395				      0, 1, 1, 0);
    396
    397	if (hdl->error) {
    398		pr_err("Could not initialize controls\n");
    399		return hdl->error;
    400	}
    401
    402	v4l2_ctrl_auto_cluster(3, &sd->auto_white_bal, 0, false);
    403	v4l2_ctrl_auto_cluster(2, &sd->autoexpo, 0, false);
    404	v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, false);
    405	v4l2_ctrl_cluster(2, &sd->hflip);
    406
    407	return 0;
    408}
    409
    410int ov9650_start(struct sd *sd)
    411{
    412	u8 data;
    413	int i, err = 0;
    414	struct cam *cam = &sd->gspca_dev.cam;
    415
    416	int width = cam->cam_mode[sd->gspca_dev.curr_mode].width;
    417	int height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
    418	int ver_offs = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
    419	int hor_offs = OV9650_LEFT_OFFSET;
    420	struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
    421
    422	if ((!dmi_check_system(ov9650_flip_dmi_table) &&
    423		sd->vflip->val) ||
    424		(dmi_check_system(ov9650_flip_dmi_table) &&
    425		!sd->vflip->val))
    426		ver_offs--;
    427
    428	if (width <= 320)
    429		hor_offs /= 2;
    430
    431	/* Synthesize the vsync/hsync setup */
    432	for (i = 0; i < ARRAY_SIZE(res_init_ov9650) && !err; i++) {
    433		if (res_init_ov9650[i][0] == BRIDGE)
    434			err = m5602_write_bridge(sd, res_init_ov9650[i][1],
    435				res_init_ov9650[i][2]);
    436		else if (res_init_ov9650[i][0] == SENSOR) {
    437			data = res_init_ov9650[i][2];
    438			err = m5602_write_sensor(sd,
    439				res_init_ov9650[i][1], &data, 1);
    440		}
    441	}
    442	if (err < 0)
    443		return err;
    444
    445	err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA,
    446				 ((ver_offs >> 8) & 0xff));
    447	if (err < 0)
    448		return err;
    449
    450	err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (ver_offs & 0xff));
    451	if (err < 0)
    452		return err;
    453
    454	err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
    455	if (err < 0)
    456		return err;
    457
    458	err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff);
    459	if (err < 0)
    460		return err;
    461
    462	err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff));
    463	if (err < 0)
    464		return err;
    465
    466	for (i = 0; i < 2 && !err; i++)
    467		err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
    468	if (err < 0)
    469		return err;
    470
    471	err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
    472	if (err < 0)
    473		return err;
    474
    475	err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 2);
    476	if (err < 0)
    477		return err;
    478
    479	err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
    480				 (hor_offs >> 8) & 0xff);
    481	if (err < 0)
    482		return err;
    483
    484	err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, hor_offs & 0xff);
    485	if (err < 0)
    486		return err;
    487
    488	err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
    489				 ((width + hor_offs) >> 8) & 0xff);
    490	if (err < 0)
    491		return err;
    492
    493	err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
    494				 ((width + hor_offs) & 0xff));
    495	if (err < 0)
    496		return err;
    497
    498	err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
    499	if (err < 0)
    500		return err;
    501
    502	switch (width) {
    503	case 640:
    504		gspca_dbg(gspca_dev, D_CONF, "Configuring camera for VGA mode\n");
    505
    506		data = OV9650_VGA_SELECT | OV9650_RGB_SELECT |
    507		       OV9650_RAW_RGB_SELECT;
    508		err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
    509		break;
    510
    511	case 352:
    512		gspca_dbg(gspca_dev, D_CONF, "Configuring camera for CIF mode\n");
    513
    514		data = OV9650_CIF_SELECT | OV9650_RGB_SELECT |
    515				OV9650_RAW_RGB_SELECT;
    516		err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
    517		break;
    518
    519	case 320:
    520		gspca_dbg(gspca_dev, D_CONF, "Configuring camera for QVGA mode\n");
    521
    522		data = OV9650_QVGA_SELECT | OV9650_RGB_SELECT |
    523				OV9650_RAW_RGB_SELECT;
    524		err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
    525		break;
    526
    527	case 176:
    528		gspca_dbg(gspca_dev, D_CONF, "Configuring camera for QCIF mode\n");
    529
    530		data = OV9650_QCIF_SELECT | OV9650_RGB_SELECT |
    531			OV9650_RAW_RGB_SELECT;
    532		err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
    533		break;
    534	}
    535	return err;
    536}
    537
    538int ov9650_stop(struct sd *sd)
    539{
    540	u8 data = OV9650_SOFT_SLEEP | OV9650_OUTPUT_DRIVE_2X;
    541	return m5602_write_sensor(sd, OV9650_COM2, &data, 1);
    542}
    543
    544void ov9650_disconnect(struct sd *sd)
    545{
    546	ov9650_stop(sd);
    547
    548	sd->sensor = NULL;
    549}
    550
    551static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
    552{
    553	struct sd *sd = (struct sd *) gspca_dev;
    554	u8 i2c_data;
    555	int err;
    556
    557	gspca_dbg(gspca_dev, D_CONF, "Set exposure to %d\n", val);
    558
    559	/* The 6 MSBs */
    560	i2c_data = (val >> 10) & 0x3f;
    561	err = m5602_write_sensor(sd, OV9650_AECHM,
    562				  &i2c_data, 1);
    563	if (err < 0)
    564		return err;
    565
    566	/* The 8 middle bits */
    567	i2c_data = (val >> 2) & 0xff;
    568	err = m5602_write_sensor(sd, OV9650_AECH,
    569				  &i2c_data, 1);
    570	if (err < 0)
    571		return err;
    572
    573	/* The 2 LSBs */
    574	i2c_data = val & 0x03;
    575	err = m5602_write_sensor(sd, OV9650_COM1, &i2c_data, 1);
    576	return err;
    577}
    578
    579static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
    580{
    581	int err;
    582	u8 i2c_data;
    583	struct sd *sd = (struct sd *) gspca_dev;
    584
    585	gspca_dbg(gspca_dev, D_CONF, "Setting gain to %d\n", val);
    586
    587	/* The 2 MSB */
    588	/* Read the OV9650_VREF register first to avoid
    589	   corrupting the VREF high and low bits */
    590	err = m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
    591	if (err < 0)
    592		return err;
    593
    594	/* Mask away all uninteresting bits */
    595	i2c_data = ((val & 0x0300) >> 2) |
    596			(i2c_data & 0x3f);
    597	err = m5602_write_sensor(sd, OV9650_VREF, &i2c_data, 1);
    598	if (err < 0)
    599		return err;
    600
    601	/* The 8 LSBs */
    602	i2c_data = val & 0xff;
    603	err = m5602_write_sensor(sd, OV9650_GAIN, &i2c_data, 1);
    604	return err;
    605}
    606
    607static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
    608{
    609	int err;
    610	u8 i2c_data;
    611	struct sd *sd = (struct sd *) gspca_dev;
    612
    613	gspca_dbg(gspca_dev, D_CONF, "Set red gain to %d\n", val);
    614
    615	i2c_data = val & 0xff;
    616	err = m5602_write_sensor(sd, OV9650_RED, &i2c_data, 1);
    617	return err;
    618}
    619
    620static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
    621{
    622	int err;
    623	u8 i2c_data;
    624	struct sd *sd = (struct sd *) gspca_dev;
    625
    626	gspca_dbg(gspca_dev, D_CONF, "Set blue gain to %d\n", val);
    627
    628	i2c_data = val & 0xff;
    629	err = m5602_write_sensor(sd, OV9650_BLUE, &i2c_data, 1);
    630	return err;
    631}
    632
    633static int ov9650_set_hvflip(struct gspca_dev *gspca_dev)
    634{
    635	int err;
    636	u8 i2c_data;
    637	struct sd *sd = (struct sd *) gspca_dev;
    638	int hflip = sd->hflip->val;
    639	int vflip = sd->vflip->val;
    640
    641	gspca_dbg(gspca_dev, D_CONF, "Set hvflip to %d %d\n", hflip, vflip);
    642
    643	if (dmi_check_system(ov9650_flip_dmi_table))
    644		vflip = !vflip;
    645
    646	i2c_data = (hflip << 5) | (vflip << 4);
    647	err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
    648	if (err < 0)
    649		return err;
    650
    651	/* When vflip is toggled we need to readjust the bridge hsync/vsync */
    652	if (gspca_dev->streaming)
    653		err = ov9650_start(sd);
    654
    655	return err;
    656}
    657
    658static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev,
    659				    __s32 val)
    660{
    661	int err;
    662	u8 i2c_data;
    663	struct sd *sd = (struct sd *) gspca_dev;
    664
    665	gspca_dbg(gspca_dev, D_CONF, "Set auto exposure control to %d\n", val);
    666
    667	err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
    668	if (err < 0)
    669		return err;
    670
    671	val = (val == V4L2_EXPOSURE_AUTO);
    672	i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0));
    673
    674	return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
    675}
    676
    677static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
    678					 __s32 val)
    679{
    680	int err;
    681	u8 i2c_data;
    682	struct sd *sd = (struct sd *) gspca_dev;
    683
    684	gspca_dbg(gspca_dev, D_CONF, "Set auto white balance to %d\n", val);
    685
    686	err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
    687	if (err < 0)
    688		return err;
    689
    690	i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1));
    691	err = m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
    692
    693	return err;
    694}
    695
    696static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
    697{
    698	int err;
    699	u8 i2c_data;
    700	struct sd *sd = (struct sd *) gspca_dev;
    701
    702	gspca_dbg(gspca_dev, D_CONF, "Set auto gain control to %d\n", val);
    703
    704	err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
    705	if (err < 0)
    706		return err;
    707
    708	i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2));
    709
    710	return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
    711}
    712
    713static int ov9650_s_ctrl(struct v4l2_ctrl *ctrl)
    714{
    715	struct gspca_dev *gspca_dev =
    716		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
    717	struct sd *sd = (struct sd *) gspca_dev;
    718	int err;
    719
    720	if (!gspca_dev->streaming)
    721		return 0;
    722
    723	switch (ctrl->id) {
    724	case V4L2_CID_AUTO_WHITE_BALANCE:
    725		err = ov9650_set_auto_white_balance(gspca_dev, ctrl->val);
    726		if (err || ctrl->val)
    727			return err;
    728		err = ov9650_set_red_balance(gspca_dev, sd->red_bal->val);
    729		if (err)
    730			return err;
    731		err = ov9650_set_blue_balance(gspca_dev, sd->blue_bal->val);
    732		break;
    733	case V4L2_CID_EXPOSURE_AUTO:
    734		err = ov9650_set_auto_exposure(gspca_dev, ctrl->val);
    735		if (err || ctrl->val == V4L2_EXPOSURE_AUTO)
    736			return err;
    737		err = ov9650_set_exposure(gspca_dev, sd->expo->val);
    738		break;
    739	case V4L2_CID_AUTOGAIN:
    740		err = ov9650_set_auto_gain(gspca_dev, ctrl->val);
    741		if (err || ctrl->val)
    742			return err;
    743		err = ov9650_set_gain(gspca_dev, sd->gain->val);
    744		break;
    745	case V4L2_CID_HFLIP:
    746		err = ov9650_set_hvflip(gspca_dev);
    747		break;
    748	default:
    749		return -EINVAL;
    750	}
    751
    752	return err;
    753}
    754
    755static void ov9650_dump_registers(struct sd *sd)
    756{
    757	int address;
    758	pr_info("Dumping the ov9650 register state\n");
    759	for (address = 0; address < 0xa9; address++) {
    760		u8 value;
    761		m5602_read_sensor(sd, address, &value, 1);
    762		pr_info("register 0x%x contains 0x%x\n", address, value);
    763	}
    764
    765	pr_info("ov9650 register state dump complete\n");
    766
    767	pr_info("Probing for which registers that are read/write\n");
    768	for (address = 0; address < 0xff; address++) {
    769		u8 old_value, ctrl_value;
    770		u8 test_value[2] = {0xff, 0xff};
    771
    772		m5602_read_sensor(sd, address, &old_value, 1);
    773		m5602_write_sensor(sd, address, test_value, 1);
    774		m5602_read_sensor(sd, address, &ctrl_value, 1);
    775
    776		if (ctrl_value == test_value[0])
    777			pr_info("register 0x%x is writeable\n", address);
    778		else
    779			pr_info("register 0x%x is read only\n", address);
    780
    781		/* Restore original value */
    782		m5602_write_sensor(sd, address, &old_value, 1);
    783	}
    784}