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

Commit c67ec53f authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab
Browse files

V4L/DVB (7615): em28xx: Provide the proper support for switching between analog/digital



Before this patch,  HVR900/HVR950 were incorreclty going back to analog. The
result is that only digital were working.

This patch provides the proper setup for analog/digital and tuner callback.
It also properly resets analog into a sane state at open().

Thanks to Steven Toth <stoth@linuxtv.org> and Michael Krufky <mkrufky@linuxtv.org>
for helping to set the proper parameters to GPO/GPIO em2883 ports.

Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent 82ac4f87
Loading
Loading
Loading
Loading
+34 −47
Original line number Diff line number Diff line
@@ -436,19 +436,25 @@ MODULE_DEVICE_TABLE(usb, em28xx_id_table);

/* Board Hauppauge WinTV HVR 900 analog */
struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = {
	{  -1,		-1,     6},
	{EM28XX_R08_GPIO,	0x2d,  10},
	{EM28XX_R08_GPIO,	0x3d,   5},
	{  -1,		-1,    -1},
	{EM28XX_R08_GPIO,	0x2d,	~EM_GPIO_4,	10},
	{0x05,			0xff,	0x10,		10},
	{  -1,			-1,	-1,		-1},
};

/* Board Hauppauge WinTV HVR 900 digital */
struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = {
	{  -1,		-1,     6},
	{EM28XX_R08_GPIO,	0x2e,   6},
	{EM28XX_R08_GPIO,	0x3e,   6},
	{EM2880_R04_GPO,	0x04,  10},
	{EM2880_R04_GPO,	0x0c,  10},
	{ -1,    -1,  -1},
	{EM28XX_R08_GPIO,	0x2e,	~EM_GPIO_4,	10},
	{EM2880_R04_GPO,	0x04,	0x0f,		10},
	{EM2880_R04_GPO,	0x0c,	0x0f,		10},
	{ -1,			-1,	-1,		-1},
};

/* Board Hauppauge WinTV HVR 900 tuner_callback */
struct em28xx_reg_seq hauppauge_wintv_hvr_900_tuner_callback[] = {
	{EM28XX_R08_GPIO,	EM_GPIO_4,	EM_GPIO_4,	10},
	{EM28XX_R08_GPIO,	0,		EM_GPIO_4,	10},
	{EM28XX_R08_GPIO,	EM_GPIO_4,	EM_GPIO_4,	10},
	{  -1,			-1,		-1,		-1},
};

/*
@@ -469,7 +475,6 @@ int em28xx_tuner_callback(void *ptr, int command, int arg)
{
	int rc = 0;
	struct em28xx *dev = ptr;
	struct em28xx_reg_seq *gpio;

	if (dev->tuner_type != TUNER_XC2028)
		return 0;
@@ -478,32 +483,10 @@ int em28xx_tuner_callback(void *ptr, int command, int arg)
		return 0;

	if (dev->mode == EM28XX_ANALOG_MODE)
		gpio = dev->analog_gpio;
		rc = em28xx_gpio_set(dev, dev->tun_analog_gpio);
	else
		gpio = dev->digital_gpio;

	/* djh - Not sure if these are still required */
	dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1);
	if (dev->mode == EM28XX_ANALOG_MODE)
		dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1);
	else
		dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x37", 1);
	msleep(6);

	if (!gpio)
		return rc;

	/* Send GPIO reset sequences specified at board entry */
	while (gpio->sleep >= 0) {
		if (gpio->reg >= 0)
			rc = dev->em28xx_write_regs(dev,
						    gpio->reg,
						    &gpio->val, 1);
		if (gpio->sleep > 0)
			msleep(gpio->sleep);
		rc = em28xx_gpio_set(dev, dev->tun_digital_gpio);

		gpio++;
	}
	return rc;
}
EXPORT_SYMBOL_GPL(em28xx_tuner_callback);
@@ -527,6 +510,10 @@ void em28xx_pre_card_setup(struct em28xx *dev)
{
	int rc;

	rc = em28xx_read_reg(dev, EM2880_R04_GPO);
	if (rc >= 0)
		dev->reg_gpo = rc;

	dev->wait_after_write = 5;
	rc = em28xx_read_reg(dev, EM28XX_R0A_CHIPID);
	if (rc > 0) {
@@ -549,22 +536,22 @@ void em28xx_pre_card_setup(struct em28xx *dev)
	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
		em28xx_write_regs(dev, EM28XX_R0F_XCLK,    "\x27", 1);
		em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
		em28xx_write_regs(dev, 0x08, "\xff", 1);
		em28xx_write_regs(dev, 0x04, "\x00", 1);
		msleep(100);
		em28xx_write_regs(dev, 0x04, "\x08", 1);
		msleep(100);
		em28xx_write_regs(dev, 0x08, "\xff", 1);
		msleep(50);
		em28xx_write_regs(dev, 0x08, "\x2d", 1);
		msleep(50);
		em28xx_write_regs(dev, 0x08, "\x3d", 1);

		/* Sets GPO/GPIO sequences for this device */
		dev->analog_gpio      = hauppauge_wintv_hvr_900_analog;
		dev->digital_gpio     = hauppauge_wintv_hvr_900_digital;
		dev->tun_analog_gpio  = hauppauge_wintv_hvr_900_tuner_callback;
		dev->tun_digital_gpio = hauppauge_wintv_hvr_900_tuner_callback;

		break;
	}

	em28xx_gpio_set(dev, dev->tun_analog_gpio);
	em28xx_set_mode(dev, EM28XX_ANALOG_MODE);

	/* Unlock device */
	em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
}

void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
+83 −7
Original line number Diff line number Diff line
@@ -134,7 +134,10 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
	unsigned char *bufs;

	if (dev->state & DEV_DISCONNECTED)
		return(-ENODEV);
		return -ENODEV;

	if (len < 1)
		return -EINVAL;

	bufs = kmalloc(len, GFP_KERNEL);

@@ -162,7 +165,23 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,

int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len)
{
	return em28xx_write_regs_req(dev, USB_REQ_GET_STATUS, reg, buf, len);
	int rc;

	rc = em28xx_write_regs_req(dev, USB_REQ_GET_STATUS, reg, buf, len);

	/* Stores GPO/GPIO values at the cache, if changed
	   Only write values should be stored, since input on a GPIO
	   register will return the input bits.
	   Not sure what happens on reading GPO register.
	 */
	if (rc >= 0) {
		if (reg == EM2880_R04_GPO)
			dev->reg_gpo = buf[0];
		else if (reg == EM28XX_R08_GPIO)
			dev->reg_gpio = buf[0];
	}

	return rc;
}

/*
@@ -176,12 +195,19 @@ static int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
	int oldval;
	u8 newval;

	/* Uses cache for gpo/gpio registers */
	if (reg == EM2880_R04_GPO)
		oldval = dev->reg_gpo;
	else if (reg == EM28XX_R08_GPIO)
		oldval = dev->reg_gpio;
	else
		oldval = em28xx_read_reg(dev, reg);

	if (oldval < 0)
		return oldval;

	newval = (((u8) oldval) & ~bitmask) | (val & bitmask);

	return em28xx_write_regs(dev, reg, &newval, 1);
}

@@ -472,6 +498,57 @@ int em28xx_set_alternate(struct em28xx *dev)
	return 0;
}

int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio)
{
	int rc = 0;

	if (!gpio)
		return rc;

	dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1);
	if (dev->mode == EM28XX_ANALOG_MODE)
		dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1);
	else
		dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x37", 1);
	msleep(6);

	/* Send GPIO reset sequences specified at board entry */
	while (gpio->sleep >= 0) {
		if (gpio->reg >= 0) {
			rc = em28xx_write_reg_bits(dev,
						   gpio->reg,
						   gpio->val,
						   gpio->mask);
			if (rc < 0)
				return rc;
		}
		if (gpio->sleep > 0)
			msleep(gpio->sleep);

		gpio++;
	}
	return rc;
}

int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode)
{
	if (dev->mode == set_mode)
		return 0;

	if (set_mode == EM28XX_MODE_UNDEFINED) {
		dev->mode = set_mode;
		return 0;
	}

	dev->mode = set_mode;

	if (dev->mode == EM28XX_DIGITAL_MODE)
		return em28xx_gpio_set(dev, dev->digital_gpio);
	else
		return em28xx_gpio_set(dev, dev->analog_gpio);
}
EXPORT_SYMBOL_GPL(em28xx_set_mode);

/* ------------------------------------------------------------------
	URB control
   ------------------------------------------------------------------*/
@@ -548,8 +625,7 @@ EXPORT_SYMBOL_GPL(em28xx_uninit_isoc);
 */
int em28xx_init_isoc(struct em28xx *dev, int max_packets,
		     int num_bufs, int max_pkt_size,
		     int (*isoc_copy) (struct em28xx *dev, struct urb *urb),
		     int cap_type)
		     int (*isoc_copy) (struct em28xx *dev, struct urb *urb))
{
	struct em28xx_dmaqueue *dma_q = &dev->vidq;
	int i;
@@ -612,7 +688,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
			should also be using 'desc.bInterval'
		 */
		pipe = usb_rcvisocpipe(dev->udev,
			cap_type == EM28XX_ANALOG_CAPTURE ? 0x82 : 0x84);
			dev->mode == EM28XX_ANALOG_MODE ? 0x82 : 0x84);

		usb_fill_int_urb(urb, dev->udev, pipe,
				 dev->isoc_ctl.transfer_buffer[i], sb_size,
@@ -632,7 +708,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,

	init_waitqueue_head(&dma_q->wq);

	em28xx_capture_start(dev, cap_type);
	em28xx_capture_start(dev, 1);

	/* submit urbs and enables IRQ */
	for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+11 −9
Original line number Diff line number Diff line
@@ -137,14 +137,17 @@ static inline int dvb_isoc_copy(struct em28xx *dev, struct urb *urb)

static int start_streaming(struct em28xx_dvb *dvb)
{
	int rc;
	struct em28xx *dev = dvb->adapter.priv;

	usb_set_interface(dev->udev, 0, 1);
	dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1);
	rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
	if (rc < 0)
		return rc;

	return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS,
				EM28XX_DVB_NUM_BUFS, EM28XX_DVB_MAX_PACKETSIZE,
				dvb_isoc_copy, EM28XX_DIGITAL_CAPTURE);
				dvb_isoc_copy);
}

static int stop_streaming(struct em28xx_dvb *dvb)
@@ -152,6 +155,9 @@ static int stop_streaming(struct em28xx_dvb *dvb)
	struct em28xx *dev = dvb->adapter.priv;

	em28xx_uninit_isoc(dev);

	em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);

	return 0;
}

@@ -368,13 +374,10 @@ static int dvb_init(struct em28xx *dev)
	}
	dev->dvb = dvb;

	em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
	/* init frontend */
	switch (dev->model) {
	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
		/* Enable lgdt330x */
		dev->mode = EM28XX_DIGITAL_MODE;
		em28xx_tuner_callback(dev, XC2028_TUNER_RESET, 0);

		dvb->frontend = dvb_attach(lgdt330x_attach,
					   &em2880_lgdt3303_dev,
					   &dev->i2c_adap);
@@ -384,9 +387,6 @@ static int dvb_init(struct em28xx *dev)
		}
		break;
	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
		/* Enable zl10353 */
		dev->mode = EM28XX_DIGITAL_MODE;
		em28xx_tuner_callback(dev, XC2028_TUNER_RESET, 0);
		dvb->frontend = dvb_attach(zl10353_attach,
					   &em28xx_zl10353_with_xc3028,
					   &dev->i2c_adap);
@@ -415,10 +415,12 @@ static int dvb_init(struct em28xx *dev)
	if (result < 0)
		goto out_free;

	em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
	printk(KERN_INFO "Successfully loaded em28xx-dvb\n");
	return 0;

out_free:
	em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
	kfree(dvb);
	dev->dvb = NULL;
	return result;
+10 −2
Original line number Diff line number Diff line
@@ -461,7 +461,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
	if (urb_init) {
		rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS,
				      EM28XX_NUM_BUFS, dev->max_pkt_size,
				      em28xx_isoc_copy, EM28XX_ANALOG_CAPTURE);
				      em28xx_isoc_copy);
		if (rc < 0)
			goto fail;
	}
@@ -1534,8 +1534,8 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
	em28xx_videodbg("open minor=%d type=%s users=%d\n",
				minor, v4l2_type_names[fh_type], dev->users);

	fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);

	fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
	if (!fh) {
		em28xx_errdev("em28xx-video.c: Out of memory?!\n");
		return -ENOMEM;
@@ -1552,9 +1552,15 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
		dev->hscale = 0;
		dev->vscale = 0;

		em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
		em28xx_set_alternate(dev);
		em28xx_resolution_set(dev);

		/* Needed, since GPIO might have disabled power of
		   some i2c device
		 */
		em28xx_config_i2c(dev);

	}
	if (fh->radio) {
		em28xx_videodbg("video_open: setting radio device\n");
@@ -1568,6 +1574,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
			sizeof(struct em28xx_buffer), fh);

	mutex_unlock(&dev->lock);

	return errCode;
}

@@ -1647,6 +1654,7 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp)

		/* do this before setting alternate! */
		em28xx_uninit_isoc(dev);
		em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);

		/* set alternate 0 */
		dev->alt = 0;
+12 −10
Original line number Diff line number Diff line
@@ -110,6 +110,7 @@
#define EM2800_I2C_WRITE_TIMEOUT 20

enum em28xx_mode {
	EM28XX_MODE_UNDEFINED,
	EM28XX_ANALOG_MODE,
	EM28XX_DIGITAL_MODE,
};
@@ -228,7 +229,7 @@ enum em28xx_decoder {

struct em28xx_reg_seq {
	int reg;
	unsigned char val;
	unsigned char val, mask;
	int sleep;
};

@@ -274,12 +275,6 @@ enum em28xx_dev_state {
	DEV_MISCONFIGURED = 0x04,
};

enum em28xx_capture_mode {
	EM28XX_CAPTURE_OFF = 0,
	EM28XX_ANALOG_CAPTURE,
	EM28XX_DIGITAL_CAPTURE,
};

#define EM28XX_AUDIO_BUFS 5
#define EM28XX_NUM_AUDIO_PACKETS 64
#define EM28XX_AUDIO_MAX_PACKET_SIZE 196 /* static value */
@@ -335,9 +330,12 @@ struct em28xx {
	/* Some older em28xx chips needs a waiting time after writing */
	unsigned int wait_after_write;

	/* GPIO sequences for tuner callback */
	/* GPIO sequences for analog and digital mode */
	struct em28xx_reg_seq *analog_gpio, *digital_gpio;

	/* GPIO sequences for tuner callbacks */
	struct em28xx_reg_seq *tun_analog_gpio, *tun_digital_gpio;

	int video_inputs;	/* number of video inputs */
	struct list_head	devlist;

@@ -415,6 +413,9 @@ struct em28xx {

	enum em28xx_mode mode;

	/* Caches GPO and GPIO registers */
	unsigned char	reg_gpo, reg_gpio;

	struct em28xx_dvb *dvb;
};

@@ -455,9 +456,10 @@ int em28xx_resolution_set(struct em28xx *dev);
int em28xx_set_alternate(struct em28xx *dev);
int em28xx_init_isoc(struct em28xx *dev, int max_packets,
		     int num_bufs, int max_pkt_size,
		     int (*isoc_copy) (struct em28xx *dev, struct urb *urb),
		     int cap_type);
		     int (*isoc_copy) (struct em28xx *dev, struct urb *urb));
void em28xx_uninit_isoc(struct em28xx *dev);
int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode);
int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio);

/* Provided by em28xx-video.c */
int em28xx_register_extension(struct em28xx_ops *dev);