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

stv06xx_vv6410.c (6521B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher
      4 *		      Mark Cave-Ayland, Carlo E Prelz, Dick Streefland
      5 * Copyright (c) 2002, 2003 Tuukka Toivonen
      6 * Copyright (c) 2008 Erik Andrén
      7 *
      8 * P/N 861037:      Sensor HDCS1000        ASIC STV0600
      9 * P/N 861050-0010: Sensor HDCS1000        ASIC STV0600
     10 * P/N 861050-0020: Sensor Photobit PB100  ASIC STV0600-1 - QuickCam Express
     11 * P/N 861055:      Sensor ST VV6410       ASIC STV0610   - LEGO cam
     12 * P/N 861075-0040: Sensor HDCS1000        ASIC
     13 * P/N 961179-0700: Sensor ST VV6410       ASIC STV0602   - Dexxa WebCam USB
     14 * P/N 861040-0000: Sensor ST VV6410       ASIC STV0610   - QuickCam Web
     15 */
     16
     17#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     18
     19#include "stv06xx_vv6410.h"
     20
     21static struct v4l2_pix_format vv6410_mode[] = {
     22	{
     23		356,
     24		292,
     25		V4L2_PIX_FMT_SGRBG8,
     26		V4L2_FIELD_NONE,
     27		.sizeimage = 356 * 292,
     28		.bytesperline = 356,
     29		.colorspace = V4L2_COLORSPACE_SRGB,
     30		.priv = 0
     31	}
     32};
     33
     34static int vv6410_s_ctrl(struct v4l2_ctrl *ctrl)
     35{
     36	struct gspca_dev *gspca_dev =
     37		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
     38	int err = -EINVAL;
     39
     40	switch (ctrl->id) {
     41	case V4L2_CID_HFLIP:
     42		if (!gspca_dev->streaming)
     43			return 0;
     44		err = vv6410_set_hflip(gspca_dev, ctrl->val);
     45		break;
     46	case V4L2_CID_VFLIP:
     47		if (!gspca_dev->streaming)
     48			return 0;
     49		err = vv6410_set_vflip(gspca_dev, ctrl->val);
     50		break;
     51	case V4L2_CID_GAIN:
     52		err = vv6410_set_analog_gain(gspca_dev, ctrl->val);
     53		break;
     54	case V4L2_CID_EXPOSURE:
     55		err = vv6410_set_exposure(gspca_dev, ctrl->val);
     56		break;
     57	}
     58	return err;
     59}
     60
     61static const struct v4l2_ctrl_ops vv6410_ctrl_ops = {
     62	.s_ctrl = vv6410_s_ctrl,
     63};
     64
     65static int vv6410_probe(struct sd *sd)
     66{
     67	u16 data;
     68	int err;
     69
     70	err = stv06xx_read_sensor(sd, VV6410_DEVICEH, &data);
     71	if (err < 0)
     72		return -ENODEV;
     73
     74	if (data != 0x19)
     75		return -ENODEV;
     76
     77	pr_info("vv6410 sensor detected\n");
     78
     79	sd->gspca_dev.cam.cam_mode = vv6410_mode;
     80	sd->gspca_dev.cam.nmodes = ARRAY_SIZE(vv6410_mode);
     81	return 0;
     82}
     83
     84static int vv6410_init_controls(struct sd *sd)
     85{
     86	struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
     87
     88	v4l2_ctrl_handler_init(hdl, 2);
     89	/* Disable the hardware VFLIP and HFLIP as we currently lack a
     90	   mechanism to adjust the image offset in such a way that
     91	   we don't need to renegotiate the announced format */
     92	/* v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops, */
     93	/*		V4L2_CID_HFLIP, 0, 1, 1, 0); */
     94	/* v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops, */
     95	/*		V4L2_CID_VFLIP, 0, 1, 1, 0); */
     96	v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops,
     97			V4L2_CID_EXPOSURE, 0, 32768, 1, 20000);
     98	v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops,
     99			V4L2_CID_GAIN, 0, 15, 1, 10);
    100	return hdl->error;
    101}
    102
    103static int vv6410_init(struct sd *sd)
    104{
    105	int err = 0, i;
    106
    107	for (i = 0; i < ARRAY_SIZE(stv_bridge_init); i++)
    108		stv06xx_write_bridge(sd, stv_bridge_init[i].addr, stv_bridge_init[i].data);
    109
    110	err = stv06xx_write_sensor_bytes(sd, (u8 *) vv6410_sensor_init,
    111					 ARRAY_SIZE(vv6410_sensor_init));
    112	return (err < 0) ? err : 0;
    113}
    114
    115static int vv6410_start(struct sd *sd)
    116{
    117	int err;
    118	struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
    119	struct cam *cam = &sd->gspca_dev.cam;
    120	u32 priv = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
    121
    122	if (priv & VV6410_SUBSAMPLE) {
    123		gspca_dbg(gspca_dev, D_CONF, "Enabling subsampling\n");
    124		stv06xx_write_bridge(sd, STV_Y_CTRL, 0x02);
    125		stv06xx_write_bridge(sd, STV_X_CTRL, 0x06);
    126
    127		stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x10);
    128	} else {
    129		stv06xx_write_bridge(sd, STV_Y_CTRL, 0x01);
    130		stv06xx_write_bridge(sd, STV_X_CTRL, 0x0a);
    131		stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x00);
    132
    133	}
    134
    135	/* Turn on LED */
    136	err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_ON);
    137	if (err < 0)
    138		return err;
    139
    140	err = stv06xx_write_sensor(sd, VV6410_SETUP0, 0);
    141	if (err < 0)
    142		return err;
    143
    144	gspca_dbg(gspca_dev, D_STREAM, "Starting stream\n");
    145
    146	return 0;
    147}
    148
    149static int vv6410_stop(struct sd *sd)
    150{
    151	struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
    152	int err;
    153
    154	/* Turn off LED */
    155	err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_OFF);
    156	if (err < 0)
    157		return err;
    158
    159	err = stv06xx_write_sensor(sd, VV6410_SETUP0, VV6410_LOW_POWER_MODE);
    160	if (err < 0)
    161		return err;
    162
    163	gspca_dbg(gspca_dev, D_STREAM, "Halting stream\n");
    164
    165	return 0;
    166}
    167
    168static int vv6410_dump(struct sd *sd)
    169{
    170	u8 i;
    171	int err = 0;
    172
    173	pr_info("Dumping all vv6410 sensor registers\n");
    174	for (i = 0; i < 0xff && !err; i++) {
    175		u16 data;
    176		err = stv06xx_read_sensor(sd, i, &data);
    177		pr_info("Register 0x%x contained 0x%x\n", i, data);
    178	}
    179	return (err < 0) ? err : 0;
    180}
    181
    182static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
    183{
    184	int err;
    185	u16 i2c_data;
    186	struct sd *sd = (struct sd *) gspca_dev;
    187
    188	err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
    189	if (err < 0)
    190		return err;
    191
    192	if (val)
    193		i2c_data |= VV6410_HFLIP;
    194	else
    195		i2c_data &= ~VV6410_HFLIP;
    196
    197	gspca_dbg(gspca_dev, D_CONF, "Set horizontal flip to %d\n", val);
    198	err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data);
    199
    200	return (err < 0) ? err : 0;
    201}
    202
    203static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
    204{
    205	int err;
    206	u16 i2c_data;
    207	struct sd *sd = (struct sd *) gspca_dev;
    208
    209	err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
    210	if (err < 0)
    211		return err;
    212
    213	if (val)
    214		i2c_data |= VV6410_VFLIP;
    215	else
    216		i2c_data &= ~VV6410_VFLIP;
    217
    218	gspca_dbg(gspca_dev, D_CONF, "Set vertical flip to %d\n", val);
    219	err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data);
    220
    221	return (err < 0) ? err : 0;
    222}
    223
    224static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val)
    225{
    226	int err;
    227	struct sd *sd = (struct sd *) gspca_dev;
    228
    229	gspca_dbg(gspca_dev, D_CONF, "Set analog gain to %d\n", val);
    230	err = stv06xx_write_sensor(sd, VV6410_ANALOGGAIN, 0xf0 | (val & 0xf));
    231
    232	return (err < 0) ? err : 0;
    233}
    234
    235static int vv6410_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
    236{
    237	int err;
    238	struct sd *sd = (struct sd *) gspca_dev;
    239	unsigned int fine, coarse;
    240
    241	val = (val * val >> 14) + val / 4;
    242
    243	fine = val % VV6410_CIF_LINELENGTH;
    244	coarse = min(512, val / VV6410_CIF_LINELENGTH);
    245
    246	gspca_dbg(gspca_dev, D_CONF, "Set coarse exposure to %d, fine exposure to %d\n",
    247		  coarse, fine);
    248
    249	err = stv06xx_write_sensor(sd, VV6410_FINEH, fine >> 8);
    250	if (err < 0)
    251		goto out;
    252
    253	err = stv06xx_write_sensor(sd, VV6410_FINEL, fine & 0xff);
    254	if (err < 0)
    255		goto out;
    256
    257	err = stv06xx_write_sensor(sd, VV6410_COARSEH, coarse >> 8);
    258	if (err < 0)
    259		goto out;
    260
    261	err = stv06xx_write_sensor(sd, VV6410_COARSEL, coarse & 0xff);
    262
    263out:
    264	return err;
    265}