Commit 480b55c2 authored by Luca Risolia's avatar Luca Risolia Committed by Mauro Carvalho Chehab
Browse files

V4L/DVB (5585): SN9C1xx driver updates



* Default color improvements to the OV7660
@ Fix sn9c102_write_reg()
@ Fix sn9c102_i2c_try_raw_read()
@ Fix MI-0343
+ Add support for pair MI0360+SN9C120
+ Add more USB ids

Signed-off-by: default avatarLuca Risolia <luca.risolia@studio.unibo.it>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent b3785596
Loading
Loading
Loading
Loading
+10 −8
Original line number Diff line number Diff line
@@ -355,6 +355,9 @@ devices assembling the SN9C1xx PC camera controllers:

Vendor ID  Product ID
---------  ----------
0x0458     0x7025
0x045e     0x00f5
0x045e     0x00f7
0x0471     0x0327
0x0471     0x0328
0x0c45     0x6001
@@ -432,7 +435,7 @@ Image sensor / SN9C1xx bridge | SN9C10[12] SN9C103 SN9C105 SN9C120
HV7131D    Hynix Semiconductor     | Yes         No       No       No
HV7131R    Hynix Semiconductor     | No          Yes      Yes      Yes
MI-0343    Micron Technology       | Yes         No       No       No
MI-0360    Micron Technology       | No          Yes      No       No
MI-0360    Micron Technology       | No          Yes      Yes      Yes
OV7630     OmniVision Technologies | Yes         Yes      No       No
OV7660     OmniVision Technologies | No          No       Yes      Yes
PAS106B    PixArt Imaging          | Yes         No       No       No
@@ -478,13 +481,12 @@ scaling factor is restored to 1.
This driver supports two different video formats: the first one is the "8-bit
Sequential Bayer" format and can be used to obtain uncompressed video data
from the device through the current I/O method, while the second one provides
"raw" compressed video data (without frame headers not related to the
compressed data). The compression quality may vary from 0 to 1 and can be
selected or queried thanks to the VIDIOC_S_JPEGCOMP and VIDIOC_G_JPEGCOMP V4L2
ioctl's. For maximum flexibility, both the default active video format and the
default compression quality depend on how the image sensor being used is
initialized (as described in the documentation of the API for the image sensors
supplied by this driver).
either "raw" compressed video data (without frame headers not related to the
compressed data) or standard JPEG (with frame headers). The compression quality
may vary from 0 to 1 and can be selected or queried thanks to the
VIDIOC_S_JPEGCOMP and VIDIOC_G_JPEGCOMP V4L2 ioctl's. For maximum flexibility,
both the default active video format and the default compression quality
depend on how the image sensor being used is initialized.


11. Video frame formats [1]
+1 −1
Original line number Diff line number Diff line
@@ -141,7 +141,7 @@ sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id)

void
sn9c102_attach_sensor(struct sn9c102_device* cam,
		      struct sn9c102_sensor* sensor)
		      const struct sn9c102_sensor* sensor)
{
	memcpy(&cam->sensor, sensor, sizeof(struct sn9c102_sensor));
}
+43 −48
Original line number Diff line number Diff line
@@ -48,8 +48,8 @@
#define SN9C102_MODULE_AUTHOR   "(C) 2004-2007 Luca Risolia"
#define SN9C102_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
#define SN9C102_MODULE_LICENSE  "GPL"
#define SN9C102_MODULE_VERSION  "1:1.39"
#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 39)
#define SN9C102_MODULE_VERSION  "1:1.44"
#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 44)

/*****************************************************************************/

@@ -209,38 +209,41 @@ static void sn9c102_queue_unusedframes(struct sn9c102_device* cam)
}

/*****************************************************************************/

/*
 * Write a sequence of count value/register pairs.  Returns -1 after the
 * first failed write, or 0 for no errors.
   Write a sequence of count value/register pairs. Returns -1 after the first
   failed write, or 0 for no errors.
*/
int sn9c102_write_regs(struct sn9c102_device* cam, const u8 valreg[][2],
		       int count)
{
	struct usb_device* udev = cam->usbdev;
	u8* value = cam->control_buffer;  /* Needed for DMA'able memory */
	u8* buff = cam->control_buffer;
	int i, res;

	for (i = 0; i < count; i++) {
		u8 index = valreg[i][1];

		/*
		 * index is a u8, so it must be <256 and can't be out of range.
		 * If we put in a check anyway, gcc annoys us with a warning
		 * that our check is useless.  People get all uppity when they
		 * see warnings in the kernel compile.
		   index is a u8, so it must be <256 and can't be out of range.
		   If we put in a check anyway, gcc annoys us with a warning
		   hat our check is useless. People get all uppity when they
		   see warnings in the kernel compile.
		*/

		*value = valreg[i][0];
		res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
				      0x08, 0x41, index, 0,
				      value, 1, SN9C102_CTRL_TIMEOUT);
		*buff = valreg[i][0];

		res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08,
				      0x41, index, 0, buff, 1,
				      SN9C102_CTRL_TIMEOUT);

		if (res < 0) {
			DBG(3, "Failed to write a register (value 0x%02X, "
			       "index 0x%02X, error %d)", *value, index, res);
			       "index 0x%02X, error %d)", *buff, index, res);
			return -1;
		}

		cam->reg[index] = *value;
		cam->reg[index] = *buff;
	}

	return 0;
@@ -272,8 +275,8 @@ int sn9c102_write_reg(struct sn9c102_device* cam, u8 value, u16 index)
}


/* NOTE: reading some registers always returns 0 */
static int sn9c102_read_reg(struct sn9c102_device* cam, u16 index)
/* NOTE: with the SN9C10[123] reading some registers always returns 0 */
int sn9c102_read_reg(struct sn9c102_device* cam, u16 index)
{
	struct usb_device* udev = cam->usbdev;
	u8* buff = cam->control_buffer;
@@ -299,7 +302,8 @@ int sn9c102_pread_reg(struct sn9c102_device* cam, u16 index)


static int
sn9c102_i2c_wait(struct sn9c102_device* cam, struct sn9c102_sensor* sensor)
sn9c102_i2c_wait(struct sn9c102_device* cam,
		 const struct sn9c102_sensor* sensor)
{
	int i, r;

@@ -320,7 +324,7 @@ sn9c102_i2c_wait(struct sn9c102_device* cam, struct sn9c102_sensor* sensor)

static int
sn9c102_i2c_detect_read_error(struct sn9c102_device* cam,
			      struct sn9c102_sensor* sensor)
			      const struct sn9c102_sensor* sensor)
{
	int r , err = 0;

@@ -342,7 +346,7 @@ sn9c102_i2c_detect_read_error(struct sn9c102_device* cam,

static int
sn9c102_i2c_detect_write_error(struct sn9c102_device* cam,
			       struct sn9c102_sensor* sensor)
			       const struct sn9c102_sensor* sensor)
{
	int r;
	r = sn9c102_read_reg(cam, 0x08);
@@ -352,12 +356,12 @@ sn9c102_i2c_detect_write_error(struct sn9c102_device* cam,

int
sn9c102_i2c_try_raw_read(struct sn9c102_device* cam,
			 struct sn9c102_sensor* sensor, u8 data0, u8 data1,
			 u8 n, u8 buffer[])
			 const struct sn9c102_sensor* sensor, u8 data0,
			 u8 data1, u8 n, u8 buffer[])
{
	struct usb_device* udev = cam->usbdev;
	u8* data = cam->control_buffer;
	int err = 0, res;
	int i = 0, err = 0, res;

	/* Write cycle */
	data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) |
@@ -402,7 +406,8 @@ sn9c102_i2c_try_raw_read(struct sn9c102_device* cam,
	}

	if (buffer)
		memcpy(buffer, data, sizeof(buffer));
		for (i = 0; i < n && i < 5; i++)
			buffer[n-i-1] = data[4-i];

	return (int)data[4];
}
@@ -410,7 +415,7 @@ sn9c102_i2c_try_raw_read(struct sn9c102_device* cam,

int
sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
			  struct sn9c102_sensor* sensor, u8 n, u8 data0,
			  const struct sn9c102_sensor* sensor, u8 n, u8 data0,
			  u8 data1, u8 data2, u8 data3, u8 data4, u8 data5)
{
	struct usb_device* udev = cam->usbdev;
@@ -449,7 +454,7 @@ sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,

int
sn9c102_i2c_try_read(struct sn9c102_device* cam,
		     struct sn9c102_sensor* sensor, u8 address)
		     const struct sn9c102_sensor* sensor, u8 address)
{
	return sn9c102_i2c_try_raw_read(cam, sensor, sensor->i2c_slave_id,
					address, 1, NULL);
@@ -458,7 +463,7 @@ sn9c102_i2c_try_read(struct sn9c102_device* cam,

int
sn9c102_i2c_try_write(struct sn9c102_device* cam,
		      struct sn9c102_sensor* sensor, u8 address, u8 value)
		      const struct sn9c102_sensor* sensor, u8 address, u8 value)
{
	return sn9c102_i2c_try_raw_write(cam, sensor, 3,
					 sensor->i2c_slave_id, address,
@@ -657,16 +662,6 @@ sn9c102_write_jpegheader(struct sn9c102_device* cam, struct sn9c102_frame_t* f)
}


static void
sn9c102_write_eoimarker(struct sn9c102_device* cam, struct sn9c102_frame_t* f)
{
	static const u8 eoi_marker[2] = {0xff, 0xd9};

	memcpy(f->bufmem + f->buf.bytesused, eoi_marker, sizeof(eoi_marker));
	f->buf.bytesused += sizeof(eoi_marker);
}


static void sn9c102_urb_complete(struct urb *urb)
{
	struct sn9c102_device* cam = urb->context;
@@ -3251,7 +3246,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
		break;
	}

	for  (i = 0; sn9c102_sensor_table[i]; i++) {
	for  (i = 0; i < ARRAY_SIZE(sn9c102_sensor_table); i++) {
		err = sn9c102_sensor_table[i](cam);
		if (!err)
			break;
@@ -3262,7 +3257,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
		DBG(3, "Support for %s maintained by %s",
		    cam->sensor.name, cam->sensor.maintainer);
	} else {
		DBG(1, "No supported image sensor detected");
		DBG(1, "No supported image sensor detected for this bridge");
		err = -ENODEV;
		goto fail;
	}
+3 −1
Original line number Diff line number Diff line
@@ -86,6 +86,8 @@ static const struct usb_device_id sn9c102_id_table[] = {
	{ SN9C102_USB_DEVICE(0x0c45, 0x60bc, BRIDGE_SN9C103), },
	{ SN9C102_USB_DEVICE(0x0c45, 0x60be, BRIDGE_SN9C103), },
	/* SN9C105 */
	{ SN9C102_USB_DEVICE(0x045e, 0x00f5, BRIDGE_SN9C105), },
	{ SN9C102_USB_DEVICE(0x045e, 0x00f7, BRIDGE_SN9C105), },
	{ SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), },
	{ SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), },
	{ SN9C102_USB_DEVICE(0x0c45, 0x60c0, BRIDGE_SN9C105), },
@@ -100,6 +102,7 @@ static const struct usb_device_id sn9c102_id_table[] = {
	{ SN9C102_USB_DEVICE(0x0c45, 0x60fc, BRIDGE_SN9C105), },
	{ SN9C102_USB_DEVICE(0x0c45, 0x60fe, BRIDGE_SN9C105), },
	/* SN9C120 */
	{ SN9C102_USB_DEVICE(0x0458, 0x7025, BRIDGE_SN9C120), },
	{ SN9C102_USB_DEVICE(0x0c45, 0x6102, BRIDGE_SN9C120), },
	{ SN9C102_USB_DEVICE(0x0c45, 0x6108, BRIDGE_SN9C120), },
	{ SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), },
@@ -148,7 +151,6 @@ static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = {
	&sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */
	&sn9c102_probe_tas5110d, /* detection based on USB pid/vid */
	&sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */
	NULL,
};

#endif /* _SN9C102_DEVTABLE_H_ */
+2 −4
Original line number Diff line number Diff line
@@ -144,7 +144,7 @@ static int hv7131d_set_pix_format(struct sn9c102_device* cam,
}


static struct sn9c102_sensor hv7131d = {
static const struct sn9c102_sensor hv7131d = {
	.name = "HV7131D",
	.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
	.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
@@ -248,12 +248,10 @@ int sn9c102_probe_hv7131d(struct sn9c102_device* cam)

	err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01},
				       {0x28, 0x17});
	if (err)
		return -EIO;

	r0 = sn9c102_i2c_try_read(cam, &hv7131d, 0x00);
	r1 = sn9c102_i2c_try_read(cam, &hv7131d, 0x01);
	if (r0 < 0 || r1 < 0)
	if (err || r0 < 0 || r1 < 0)
		return -EIO;

	if (r0 != 0x00 || r1 != 0x04)
Loading