Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 05b809c7 authored by Jean-Francois Moine's avatar Jean-Francois Moine Committed by Mauro Carvalho Chehab
Browse files

V4L/DVB (8709): gspca: Fix initialization and controls of sn9x110 - ov7630.

parent 41b46974
Loading
Loading
Loading
Loading
+97 −102
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ struct sd {
#define SENSOR_OV7648 5
#define SENSOR_OV7660 6
	unsigned char i2c_base;
	__u8 regf1;
};

/* V4L2 controls supported by the driver */
@@ -78,7 +79,8 @@ static struct ctrl sd_ctrls[] = {
		.type    = V4L2_CTRL_TYPE_INTEGER,
		.name    = "Brightness",
		.minimum = 0,
		.maximum = 0xffff,
#define BRIGHTNESS_MAX 0xffff
		.maximum = BRIGHTNESS_MAX,
		.step    = 1,
#define BRIGHTNESS_DEF 0x7fff
		.default_value = BRIGHTNESS_DEF,
@@ -92,7 +94,8 @@ static struct ctrl sd_ctrls[] = {
		.type    = V4L2_CTRL_TYPE_INTEGER,
		.name    = "Contrast",
		.minimum = 0,
		.maximum = 127,
#define CONTRAST_MAX 127
		.maximum = CONTRAST_MAX,
		.step    = 1,
#define CONTRAST_DEF 63
		.default_value = CONTRAST_DEF,
@@ -240,27 +243,16 @@ static const __u8 *sn_tb[] = {
	sn_ov7660
};

static const __u8 regsn20[] = {
static const __u8 gamma_def[] = {
	0x00, 0x2d, 0x46, 0x5a, 0x6c, 0x7c, 0x8b, 0x99,
	0xa6, 0xb2, 0xbf, 0xca, 0xd5, 0xe0, 0xeb, 0xf5, 0xff
};
static const __u8 regsn20_sn9c325[] = {
	0x0a, 0x3a, 0x56, 0x6c, 0x7e, 0x8d, 0x9a, 0xa4,
	0xaf, 0xbb, 0xc5, 0xcd, 0xd5, 0xde, 0xe8, 0xed, 0xf5
};

static const __u8 reg84[] = {
	0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe5, 0x0f,
	0xe4, 0x0f, 0x38, 0x00, 0x3e, 0x00, 0xc3, 0x0f,
/*	0x00, 0x00, 0x00, 0x00, 0x00 */
	0xf7, 0x0f, 0x0a, 0x00, 0x00
};
static const __u8 reg84_sn9c325[] = {
	0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe4, 0x0f,
	0xd3, 0x0f, 0x4b, 0x00, 0x48, 0x00, 0xc0, 0x0f,
	0xf8, 0x0f, 0x00, 0x00, 0x00
	0xf7, 0x0f, 0x00, 0x00, 0x00
};

static const __u8 hv7131r_sensor_init[][8] = {
	{0xC1, 0x11, 0x01, 0x08, 0x01, 0x00, 0x00, 0x10},
	{0xB1, 0x11, 0x34, 0x17, 0x7F, 0x00, 0x00, 0x10},
@@ -411,7 +403,7 @@ static const __u8 ov7630_sensor_init[][8] = {
	{0xa1, 0x21, 0x12, 0xc8, 0x00, 0x00, 0x00, 0x10},
/* win: delay 20ms */
	{0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
/* win: loop on 2 wwrite, 1 read */
/* win: i2c_r from 00 to 80 */
	{0xd1, 0x21, 0x03, 0x80, 0x10, 0x20, 0x80, 0x10},
	{0xb1, 0x21, 0x0c, 0x20, 0x20, 0x00, 0x00, 0x10},
	{0xd1, 0x21, 0x11, 0x00, 0x48, 0xc0, 0x00, 0x10},
@@ -446,9 +438,11 @@ static const __u8 ov7630_sensor_init[][8] = {
	{0xa1, 0x21, 0x10, 0x32, 0x00, 0x00, 0x00, 0x10},
	{0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
	{0xb1, 0x21, 0x01, 0x80, 0x80, 0x00, 0x00, 0x10},
/* */
	{0xa1, 0x21, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10},
	{0xa1, 0x21, 0x2a, 0x88, 0x00, 0x00, 0x00, 0x10},
	{0xa1, 0x21, 0x2b, 0x34, 0x00, 0x00, 0x00, 0x10},
/* */
	{0xa1, 0x21, 0x10, 0x83, 0x00, 0x00, 0x00, 0x10},
	{0xb1, 0x21, 0x01, 0x88, 0x70, 0x00, 0x00, 0x10},
	{}
@@ -778,7 +772,7 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
	static const __u8 regd4[] = {0x60, 0x00, 0x00};

	reg_w1(gspca_dev, 0xf1, 0x00);
	reg_w1(gspca_dev, 0x01, 0x00);		/*jfm was sn9c1xx[1] in v1*/
	reg_w1(gspca_dev, 0x01, sn9c1xx[1]);

	/* configure gpio */
	reg_w(gspca_dev, 0x01, &sn9c1xx[1], 2);
@@ -805,6 +799,13 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
		reg_w1(gspca_dev, 0x17, 0x64);
		reg_w1(gspca_dev, 0x01, 0x42);
		break;
/*jfm: from win trace */
	case SENSOR_OV7630:
		reg_w1(gspca_dev, 0x01, 0x61);
		reg_w1(gspca_dev, 0x17, 0xe2);
		reg_w1(gspca_dev, 0x01, 0x60);
		reg_w1(gspca_dev, 0x01, 0x40);
		break;
	case SENSOR_OV7648:
		reg_w1(gspca_dev, 0x01, 0x43);
		reg_w1(gspca_dev, 0x17, 0xae);
@@ -870,9 +871,20 @@ static void ov7630_InitSensor(struct gspca_dev *gspca_dev)
{
	int i = 0;

	i2c_w8(gspca_dev, ov7630_sensor_init[i]);
	i2c_w8(gspca_dev, ov7630_sensor_init[i]);	/* 76 01 */
	i++;
	i2c_w8(gspca_dev, ov7630_sensor_init[i]);	/* 12 c8 (RGB+SRST) */
	i++;
	msleep(20);
	i2c_w8(gspca_dev, ov7630_sensor_init[i]);	/* 12 48 */
	i++;
	i2c_w8(gspca_dev, ov7630_sensor_init[i]);	/* 12 c8 */
	i++;
	msleep(20);
	i2c_w8(gspca_dev, ov7630_sensor_init[i]);	/* 12 48 */
	i++;
/*jfm:win i2c_r from 00 to 80*/

	while (ov7630_sensor_init[i][0]) {
		i2c_w8(gspca_dev, ov7630_sensor_init[i]);
		i++;
@@ -917,6 +929,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
	sd->bridge = id->driver_info >> 16;
	sd->sensor = id->driver_info >> 8;
	sd->i2c_base = id->driver_info;
	sd->regf1 = 0;			/*jfm: was 1 in v1*/

	sd->qindex = 4;			/* set the quantization table */
	sd->brightness = BRIGHTNESS_DEF;
@@ -969,7 +982,7 @@ static int sd_open(struct gspca_dev *gspca_dev)
		break;
	}

	reg_w1(gspca_dev, 0xf1, 0x01);
	reg_w1(gspca_dev, 0xf1, sd->regf1);

	return 0;
}
@@ -1051,6 +1064,28 @@ static unsigned int setexposure(struct gspca_dev *gspca_dev,
	return expo;
}

/* this function is used for sensors o76xx only */
static void setbrightcont(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *) gspca_dev;
	unsigned val;
	__u8 reg84_full[13];

	memset(reg84_full, 0, sizeof reg84_full);
	val = sd->contrast * 0x20 / CONTRAST_MAX + 0x10;	/* 10..30 */
	reg84_full[2] = val;
	reg84_full[0] = (val + 1) / 2;
	reg84_full[4] = (val + 1) / 5;
	if (val > BRIGHTNESS_DEF)
		val = (sd->brightness - BRIGHTNESS_DEF) * 0x20
			/ BRIGHTNESS_MAX;
	else
		val = 0;
	reg84_full[10] = val;			/* 00..1f */
	reg_w(gspca_dev, 0x84, reg84_full, sizeof reg84_full);
}

/* sensor != ov76xx */
static void setbrightness(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *) gspca_dev;
@@ -1082,6 +1117,7 @@ static void setbrightness(struct gspca_dev *gspca_dev)
	reg_w1(gspca_dev, 0x96, k2);
}

/* sensor != ov76xx */
static void setcontrast(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *) gspca_dev;
@@ -1175,24 +1211,11 @@ static void sd_start(struct gspca_dev *gspca_dev)
	reg_w1(gspca_dev, 0x07, sn9c1xx[7]);
	reg_w1(gspca_dev, 0x06, sn9c1xx[6]);
	reg_w1(gspca_dev, 0x14, sn9c1xx[0x14]);
	switch (sd->bridge) {
	case BRIDGE_SN9C325:
		reg_w(gspca_dev, 0x20, regsn20_sn9c325,
				sizeof regsn20_sn9c325);
		for (i = 0; i < 8; i++)
			reg_w(gspca_dev, 0x84, reg84_sn9c325,
					sizeof reg84_sn9c325);
		reg_w1(gspca_dev, 0x9a, 0x0a);
		reg_w1(gspca_dev, 0x99, 0x60);
		break;
	default:
		reg_w(gspca_dev, 0x20, regsn20, sizeof regsn20);
	reg_w(gspca_dev, 0x20, gamma_def, sizeof gamma_def);
	for (i = 0; i < 8; i++)
		reg_w(gspca_dev, 0x84, reg84, sizeof reg84);
		reg_w1(gspca_dev, 0x9a, 0x08);
		reg_w1(gspca_dev, 0x99, 0x59);
		break;
	}

	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
	if (mode)
@@ -1272,8 +1295,18 @@ static void sd_start(struct gspca_dev *gspca_dev)

	reg_w1(gspca_dev, 0x17, reg17);
	reg_w1(gspca_dev, 0x01, reg1);
	switch (sd->sensor) {
	case SENSOR_HV7131R:
	case SENSOR_MI0360:
	case SENSOR_MO4000:
	case SENSOR_OM6802:
		setbrightness(gspca_dev);
		setcontrast(gspca_dev);
		break;
	default:			/* OV76xx */
		setbrightcont(gspca_dev);
		break;
	}
	setautogain(gspca_dev);
}

@@ -1311,7 +1344,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
	reg_w1(gspca_dev, 0x17, sn9c1xx[0x17]);
	reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
	reg_w1(gspca_dev, 0x01, data);
	reg_w1(gspca_dev, 0xf1, 0x01);
	reg_w1(gspca_dev, 0xf1, sd->regf1);
}

static void sd_stop0(struct gspca_dev *gspca_dev)
@@ -1409,72 +1442,24 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
}

static unsigned int getexposure(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *) gspca_dev;
	__u8 hexpo, mexpo, lexpo;

	switch (sd->sensor) {
	case SENSOR_HV7131R:
		/* read sensor exposure */
		i2c_r5(gspca_dev, 0x25);
		return (gspca_dev->usb_buf[0] << 16)
			| (gspca_dev->usb_buf[1] << 8)
			| gspca_dev->usb_buf[2];
	case SENSOR_MI0360:
		/* read sensor exposure */
		i2c_r5(gspca_dev, 0x09);
		return (gspca_dev->usb_buf[0] << 8)
			| gspca_dev->usb_buf[1];
	default:
/*	case SENSOR_MO4000: */
		i2c_r5(gspca_dev, 0x0e);
		hexpo = 0;		/* gspca_dev->usb_buf[1] & 0x07; */
		mexpo = 0x40;		/* gspca_dev->usb_buf[2] & 0xff; */
		lexpo = (gspca_dev->usb_buf[1] & 0x30) >> 4;
		PDEBUG(D_CONF, "exposure %d",
			(hexpo << 10) | (mexpo << 2) | lexpo);
		return (hexpo << 10) | (mexpo << 2) | lexpo;
#if 0
/*jfm: not called*/
/*	case SENSOR_OV7648:		* jfm: is it ok for 7648? */
/*	case SENSOR_OV7660: */
		/* read sensor exposure */
		i2c_r5(gspca_dev, 0x04);
		hexpo = gspca_dev->usb_buf[3] & 0x2f;
		lexpo = gspca_dev->usb_buf[0] & 0x02;
		i2c_r5(gspca_dev, 0x08);
		mexpo = gspca_dev->usb_buf[2];
		return (hexpo << 10) | (mexpo << 2) | lexpo;
#endif
	}
	/* not reached */
}

static void getbrightness(struct gspca_dev *gspca_dev)
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
{
	struct sd *sd = (struct sd *) gspca_dev;

	/* hardcoded registers seem not readable */
	sd->brightness = val;
	if (gspca_dev->streaming) {
		switch (sd->sensor) {
		case SENSOR_HV7131R:
		sd->brightness = getexposure(gspca_dev) >> 4;
		break;
		case SENSOR_MI0360:
		case SENSOR_MO4000:
		case SENSOR_OM6802:
		sd->brightness = getexposure(gspca_dev) << 4;
			setbrightness(gspca_dev);
			break;
		default:			/* OV76xx */
			setbrightcont(gspca_dev);
			break;
		}
	}

static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
{
	struct sd *sd = (struct sd *) gspca_dev;

	sd->brightness = val;
	if (gspca_dev->streaming)
		setbrightness(gspca_dev);
	return 0;
}

@@ -1482,7 +1467,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
{
	struct sd *sd = (struct sd *) gspca_dev;

	getbrightness(gspca_dev);
	*val = sd->brightness;
	return 0;
}
@@ -1492,8 +1476,19 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
	struct sd *sd = (struct sd *) gspca_dev;

	sd->contrast = val;
	if (gspca_dev->streaming)
	if (gspca_dev->streaming) {
		switch (sd->sensor) {
		case SENSOR_HV7131R:
		case SENSOR_MI0360:
		case SENSOR_MO4000:
		case SENSOR_OM6802:
			setcontrast(gspca_dev);
			break;
		default:			/* OV76xx */
			setbrightcont(gspca_dev);
			break;
		}
	}
	return 0;
}