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

Commit cb71201f authored by Maxim Levitsky's avatar Maxim Levitsky Committed by Mauro Carvalho Chehab
Browse files

V4L/DVB (6271): V4L: Add basic support for suspend/resume for saa7134



This adds support for suspend/resume for core of saa7134

Should fix bug#7220

Signed-off-by: default avatarMaxim Levitsky <maximlevitsky@gmail.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent f5a1ac64
Loading
Loading
Loading
Loading
+144 −31
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/dma-mapping.h>
#include <linux/pm.h>

#include "saa7134-reg.h"
#include "saa7134.h"
@@ -392,6 +393,38 @@ void saa7134_buffer_timeout(unsigned long data)
	spin_unlock_irqrestore(&dev->slock,flags);
}

/* resends a current buffer in queue after resume */

int saa7134_buffer_requeue(struct saa7134_dev *dev,
			 struct saa7134_dmaqueue *q)
{
	struct saa7134_buf *buf , *next;
	unsigned long flags;

	spin_lock_irqsave(&dev->slock, flags);

	buf  = q->curr;
	next = buf;

	dprintk("buffer_requeue\n");

	if (!buf) {
		spin_unlock_irqrestore(&dev->slock, flags);
		return 0;
	}

	dprintk("buffer_requeue : resending active buffers \n");

	if (!list_empty(&q->queue))
		next = list_entry(q->queue.next, struct saa7134_buf,
					  vb.queue);

	buf->activate(dev, buf, next);
	spin_unlock_irqrestore(&dev->slock, flags);

	return 0;
}

/* ------------------------------------------------------------------ */

int saa7134_set_dmabits(struct saa7134_dev *dev)
@@ -647,22 +680,9 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id)
/* ------------------------------------------------------------------ */

/* early init (no i2c, no irq) */
static int saa7134_hwinit1(struct saa7134_dev *dev)
{
	dprintk("hwinit1\n");

	saa_writel(SAA7134_IRQ1, 0);
	saa_writel(SAA7134_IRQ2, 0);
	mutex_init(&dev->lock);
	spin_lock_init(&dev->slock);

	saa7134_track_gpio(dev,"pre-init");
	saa7134_video_init1(dev);
	saa7134_vbi_init1(dev);
	if (card_has_mpeg(dev))
		saa7134_ts_init1(dev);
	saa7134_input_init1(dev);

static int saa7134_hw_enable1(struct saa7134_dev *dev)
{
	/* RAM FIFO config */
	saa_writel(SAA7134_FIFO_SIZE, 0x08070503);
	saa_writel(SAA7134_THRESHOULD, 0x02020202);
@@ -693,14 +713,32 @@ static int saa7134_hwinit1(struct saa7134_dev *dev)
	return 0;
}

static int saa7134_hwinit1(struct saa7134_dev *dev)
{
	dprintk("hwinit1\n");

	saa_writel(SAA7134_IRQ1, 0);
	saa_writel(SAA7134_IRQ2, 0);
	mutex_init(&dev->lock);
	spin_lock_init(&dev->slock);

	saa7134_track_gpio(dev,"pre-init");
	saa7134_video_init1(dev);
	saa7134_vbi_init1(dev);
	if (card_has_mpeg(dev))
		saa7134_ts_init1(dev);
	saa7134_input_init1(dev);

	saa7134_hw_enable1(dev);

	return 0;
}

/* late init (with i2c + irq) */
static int saa7134_hwinit2(struct saa7134_dev *dev)
static int saa7134_hw_enable2(struct saa7134_dev *dev)
{
	unsigned int irq2_mask;
	dprintk("hwinit2\n");

	saa7134_video_init2(dev);
	saa7134_tvaudio_init2(dev);
	unsigned int irq2_mask;

	/* enable IRQ's */
	irq2_mask =
@@ -726,6 +764,20 @@ static int saa7134_hwinit2(struct saa7134_dev *dev)
	return 0;
}

static int saa7134_hwinit2(struct saa7134_dev *dev)
{

	dprintk("hwinit2\n");

	saa7134_video_init2(dev);
	saa7134_tvaudio_init2(dev);

	saa7134_hw_enable2(dev);

	return 0;
}


/* shutdown */
static int saa7134_hwfini(struct saa7134_dev *dev)
{
@@ -1118,6 +1170,65 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
	kfree(dev);
}

static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state)
{

	/* Disable card's IRQs to prevent it from resuming computer */

	struct saa7134_dev *dev = pci_get_drvdata(pci_dev);

	saa_writel(SAA7134_IRQ1, 0);
	saa_writel(SAA7134_IRQ2, 0);


	pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
	pci_save_state(pci_dev);

    return 0;
}

static int saa7134_resume(struct pci_dev *pci_dev)
{

	struct saa7134_dev *dev = pci_get_drvdata(pci_dev);

	pci_restore_state(pci_dev);
	pci_set_power_state(pci_dev, PCI_D0);

	/* Do things that are done in saa7134_initdev ,
		except of initializing memory structures.*/

	saa7134_board_init1(dev);

	if (saa7134_boards[dev->board].video_out)
		saa7134_videoport_init(dev);

	if (card_has_mpeg(dev))
		saa7134_ts_init_hw(dev);

	saa7134_hw_enable1(dev);

	saa7134_set_decoder(dev);

	saa7134_i2c_call_clients(dev, VIDIOC_S_STD, &dev->tvnorm->id);

	saa7134_board_init2(dev);
	saa7134_hw_enable2(dev);

	dev->force_mute_update = 1;
	saa7134_tvaudio_setmute(dev);
	dev->force_mute_update = 0;
	saa7134_tvaudio_setvolume(dev, dev->ctl_volume);
	saa7134_enable_i2s(dev);

	/*recapture unfinished buffer(s)*/
	saa7134_buffer_requeue(dev, &dev->video_q);
	saa7134_buffer_requeue(dev, &dev->vbi_q);
	saa7134_buffer_requeue(dev, &dev->ts_q);

	return 0;
}

/* ----------------------------------------------------------- */

int saa7134_ts_register(struct saa7134_mpeg_ops *ops)
@@ -1159,6 +1270,8 @@ static struct pci_driver saa7134_pci_driver = {
	.id_table = saa7134_pci_tbl,
	.probe    = saa7134_initdev,
	.remove   = __devexit_p(saa7134_finidev),
	.suspend  = saa7134_suspend,
	.resume   = saa7134_resume
};

static int saa7134_init(void)
+17 −6
Original line number Diff line number Diff line
@@ -177,6 +177,22 @@ static unsigned int ts_nr_packets = 64;
module_param(ts_nr_packets, int, 0444);
MODULE_PARM_DESC(ts_nr_packets,"size of a ts buffers (in ts packets)");

int saa7134_ts_init_hw(struct saa7134_dev *dev)
{
	/* deactivate TS softreset */
	saa_writeb(SAA7134_TS_SERIAL1, 0x00);
	/* TSSOP high active, TSVAL high active, TSLOCK ignored */
	saa_writeb(SAA7134_TS_PARALLEL, 0xec);
	saa_writeb(SAA7134_TS_PARALLEL_SERIAL, (TS_PACKET_SIZE-1));
	saa_writeb(SAA7134_TS_DMA0, ((dev->ts.nr_packets-1)&0xff));
	saa_writeb(SAA7134_TS_DMA1, (((dev->ts.nr_packets-1)>>8)&0xff));
	/* TSNOPIT=0, TSCOLAP=0 */
	saa_writeb(SAA7134_TS_DMA2,
		((((dev->ts.nr_packets-1)>>16)&0x3f) | 0x00));

	return 0;
}

int saa7134_ts_init1(struct saa7134_dev *dev)
{
	/* sanitycheck insmod options */
@@ -200,12 +216,7 @@ int saa7134_ts_init1(struct saa7134_dev *dev)
	saa7134_pgtable_alloc(dev->pci,&dev->ts.pt_ts);

	/* init TS hw */
	saa_writeb(SAA7134_TS_SERIAL1, 0x00);  /* deactivate TS softreset */
	saa_writeb(SAA7134_TS_PARALLEL, 0xec); /* TSSOP high active, TSVAL high active, TSLOCK ignored */
	saa_writeb(SAA7134_TS_PARALLEL_SERIAL, (TS_PACKET_SIZE-1));
	saa_writeb(SAA7134_TS_DMA0, ((dev->ts.nr_packets-1)&0xff));
	saa_writeb(SAA7134_TS_DMA1, (((dev->ts.nr_packets-1)>>8)&0xff));
	saa_writeb(SAA7134_TS_DMA2, ((((dev->ts.nr_packets-1)>>16)&0x3f) | 0x00)); /* TSNOPIT=0, TSCOLAP=0 */
	saa7134_ts_init_hw(dev);

	return 0;
}
+2 −2
Original line number Diff line number Diff line
@@ -231,7 +231,7 @@ static void mute_input_7134(struct saa7134_dev *dev)
	}

	if (dev->hw_mute  == mute &&
		dev->hw_input == in) {
		dev->hw_input == in && !dev->force_mute_update) {
		dprintk("mute/input: nothing to do [mute=%d,input=%s]\n",
			mute,in->name);
		return;
@@ -876,7 +876,7 @@ static int tvaudio_thread_ddep(void *data)
/* ------------------------------------------------------------------ */
/* common stuff + external entry points                               */

static void saa7134_enable_i2s(struct saa7134_dev *dev)
void saa7134_enable_i2s(struct saa7134_dev *dev)
{
	int i2s_format;

+69 −56
Original line number Diff line number Diff line
@@ -540,22 +540,12 @@ void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits)

/* ------------------------------------------------------------------ */

static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
{
	int luma_control,sync_control,mux;

	dprintk("set tv norm = %s\n",norm->name);
	dev->tvnorm = norm;

	mux = card_in(dev,dev->ctl_input).vmux;
	luma_control = norm->luma_control;
	sync_control = norm->sync_control;

	if (mux > 5)
		luma_control |= 0x80; /* svideo */
	if (noninterlaced || dev->nosignal)
		sync_control |= 0x20;

	/* setup cropping */
	dev->crop_bounds.left    = norm->h_start;
	dev->crop_defrect.left   = norm->h_start;
@@ -570,6 +560,40 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)

	dev->crop_current = dev->crop_defrect;

	saa7134_set_decoder(dev);

	if (card_in(dev, dev->ctl_input).tv) {
		if ((card(dev).tuner_type == TUNER_PHILIPS_TDA8290)
				&& ((card(dev).tuner_config == 1)
				||  (card(dev).tuner_config == 2)))
			saa7134_set_gpio(dev, 22, 5);
		saa7134_i2c_call_clients(dev, VIDIOC_S_STD, &norm->id);
	}
}

static void video_mux(struct saa7134_dev *dev, int input)
{
	dprintk("video input = %d [%s]\n", input, card_in(dev, input).name);
	dev->ctl_input = input;
	set_tvnorm(dev, dev->tvnorm);
	saa7134_tvaudio_setinput(dev, &card_in(dev, input));
}

void saa7134_set_decoder(struct saa7134_dev *dev)
{
	int luma_control, sync_control, mux;

	struct saa7134_tvnorm *norm = dev->tvnorm;
	mux = card_in(dev, dev->ctl_input).vmux;

	luma_control = norm->luma_control;
	sync_control = norm->sync_control;

	if (mux > 5)
		luma_control |= 0x80; /* svideo */
	if (noninterlaced || dev->nosignal)
		sync_control |= 0x20;

	/* setup video decoder */
	saa_writeb(SAA7134_INCR_DELAY,            0x08);
	saa_writeb(SAA7134_ANALOG_IN_CTRL1,       0xc0 | mux);
@@ -604,23 +628,6 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
	saa_writeb(SAA7134_MISC_VGATE_MSB,        norm->vgate_misc);
	saa_writeb(SAA7134_RAW_DATA_GAIN,         0x40);
	saa_writeb(SAA7134_RAW_DATA_OFFSET,       0x80);

	/* only tell the tuner if this is a tv input */
	if (card_in(dev,dev->ctl_input).tv) {
		if ((card(dev).tuner_type == TUNER_PHILIPS_TDA8290)
				&& ((card(dev).tuner_config == 1)
				||  (card(dev).tuner_config == 2)))
			saa7134_set_gpio(dev, 22, 5);
		saa7134_i2c_call_clients(dev,VIDIOC_S_STD,&norm->id);
	}
}

static void video_mux(struct saa7134_dev *dev, int input)
{
	dprintk("video input = %d [%s]\n",input,card_in(dev,input).name);
	dev->ctl_input = input;
	set_tvnorm(dev,dev->tvnorm);
	saa7134_tvaudio_setinput(dev,&card_in(dev,input));
}

static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale)
@@ -2399,7 +2406,14 @@ int saa7134_video_init1(struct saa7134_dev *dev)
	dev->video_q.timeout.data     = (unsigned long)(&dev->video_q);
	dev->video_q.dev              = dev;

	if (saa7134_boards[dev->board].video_out) {
	if (saa7134_boards[dev->board].video_out)
		saa7134_videoport_init(dev);

	return 0;
}

int saa7134_videoport_init(struct saa7134_dev *dev)
{
	/* enable video output */
	int vo = saa7134_boards[dev->board].video_out;
	int video_reg;
@@ -2426,7 +2440,6 @@ int saa7134_video_init1(struct saa7134_dev *dev)
	saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_reg);
	saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]);
	saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]);
	}

	return 0;
}
+12 −0
Original line number Diff line number Diff line
@@ -522,6 +522,7 @@ struct saa7134_dev {
	struct saa7134_input       *input;
	struct saa7134_input       *hw_input;
	unsigned int               hw_mute;
	unsigned int               force_mute_update;
	int                        last_carrier;
	int                        nosignal;

@@ -594,6 +595,9 @@ void saa7134_buffer_next(struct saa7134_dev *dev, struct saa7134_dmaqueue *q);
void saa7134_buffer_timeout(unsigned long data);
void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf);

int saa7134_buffer_requeue(struct saa7134_dev *dev,
			 struct saa7134_dmaqueue *q);

int saa7134_set_dmabits(struct saa7134_dev *dev);

extern int (*saa7134_dmasound_init)(struct saa7134_dev *dev);
@@ -626,6 +630,10 @@ void saa7134_i2c_call_clients(struct saa7134_dev *dev,
extern struct video_device saa7134_video_template;
extern struct video_device saa7134_radio_template;

void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm);
int saa7134_videoport_init(struct saa7134_dev *dev);
void saa7134_set_decoder(struct saa7134_dev *dev);

int saa7134_common_ioctl(struct saa7134_dev *dev,
			 unsigned int cmd, void *arg);

@@ -649,6 +657,8 @@ void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status);
int saa7134_ts_register(struct saa7134_mpeg_ops *ops);
void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops);

int saa7134_ts_init_hw(struct saa7134_dev *dev);

/* ----------------------------------------------------------- */
/* saa7134-vbi.c                                               */

@@ -677,6 +687,8 @@ int saa7134_tvaudio_do_scan(struct saa7134_dev *dev);

int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value);

void saa7134_enable_i2s(struct saa7134_dev *dev);

/* ----------------------------------------------------------- */
/* saa7134-oss.c                                               */