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: Maxim Levitsky <maximlevitsky@gmail.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
This commit is contained in:
Maxim Levitsky 2007-09-27 20:34:25 -03:00 committed by Mauro Carvalho Chehab
parent f5a1ac64cc
commit cb71201f20
5 changed files with 243 additions and 94 deletions

View File

@ -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,6 +680,39 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id)
/* ------------------------------------------------------------------ */
/* early init (no i2c, no irq) */
static int saa7134_hw_enable1(struct saa7134_dev *dev)
{
/* RAM FIFO config */
saa_writel(SAA7134_FIFO_SIZE, 0x08070503);
saa_writel(SAA7134_THRESHOULD, 0x02020202);
/* enable audio + video processing */
saa_writel(SAA7134_MAIN_CTRL,
SAA7134_MAIN_CTRL_VPLLE |
SAA7134_MAIN_CTRL_APLLE |
SAA7134_MAIN_CTRL_EXOSC |
SAA7134_MAIN_CTRL_EVFE1 |
SAA7134_MAIN_CTRL_EVFE2 |
SAA7134_MAIN_CTRL_ESFE |
SAA7134_MAIN_CTRL_EBDAC);
/*
* Initialize OSS _after_ enabling audio clock PLL and audio processing.
* OSS initialization writes to registers via the audio DSP; these
* writes will fail unless the audio clock has been started. At worst,
* audio will not work.
*/
/* enable peripheral devices */
saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
/* set vertical line numbering start (vbi needs this) */
saa_writeb(SAA7134_SOURCE_TIMING2, 0x20);
return 0;
}
static int saa7134_hwinit1(struct saa7134_dev *dev)
{
dprintk("hwinit1\n");
@ -663,44 +729,16 @@ static int saa7134_hwinit1(struct saa7134_dev *dev)
saa7134_ts_init1(dev);
saa7134_input_init1(dev);
/* RAM FIFO config */
saa_writel(SAA7134_FIFO_SIZE, 0x08070503);
saa_writel(SAA7134_THRESHOULD,0x02020202);
/* enable audio + video processing */
saa_writel(SAA7134_MAIN_CTRL,
SAA7134_MAIN_CTRL_VPLLE |
SAA7134_MAIN_CTRL_APLLE |
SAA7134_MAIN_CTRL_EXOSC |
SAA7134_MAIN_CTRL_EVFE1 |
SAA7134_MAIN_CTRL_EVFE2 |
SAA7134_MAIN_CTRL_ESFE |
SAA7134_MAIN_CTRL_EBDAC);
/*
* Initialize OSS _after_ enabling audio clock PLL and audio processing.
* OSS initialization writes to registers via the audio DSP; these
* writes will fail unless the audio clock has been started. At worst,
* audio will not work.
*/
/* enable peripheral devices */
saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
/* set vertical line numbering start (vbi needs this) */
saa_writeb(SAA7134_SOURCE_TIMING2, 0x20);
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)

View File

@ -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;
}

View File

@ -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;

View File

@ -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,34 +2406,40 @@ 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) {
/* enable video output */
int vo = saa7134_boards[dev->board].video_out;
int video_reg;
unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts;
saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]);
video_reg = video_out[vo][1];
if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED)
video_reg &= ~VP_T_CODE_P_INVERTED;
saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg);
saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]);
saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]);
saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]);
video_reg = video_out[vo][5];
if (vid_port_opts & SET_CLOCK_NOT_DELAYED)
video_reg &= ~VP_CLK_CTRL2_DELAYED;
if (vid_port_opts & SET_CLOCK_INVERTED)
video_reg |= VP_CLK_CTRL1_INVERTED;
saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_reg);
video_reg = video_out[vo][6];
if (vid_port_opts & SET_VSYNC_OFF) {
video_reg &= ~VP_VS_TYPE_MASK;
video_reg |= VP_VS_TYPE_OFF;
}
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]);
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;
unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts;
saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]);
video_reg = video_out[vo][1];
if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED)
video_reg &= ~VP_T_CODE_P_INVERTED;
saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg);
saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]);
saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]);
saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]);
video_reg = video_out[vo][5];
if (vid_port_opts & SET_CLOCK_NOT_DELAYED)
video_reg &= ~VP_CLK_CTRL2_DELAYED;
if (vid_port_opts & SET_CLOCK_INVERTED)
video_reg |= VP_CLK_CTRL1_INVERTED;
saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_reg);
video_reg = video_out[vo][6];
if (vid_port_opts & SET_VSYNC_OFF) {
video_reg &= ~VP_VS_TYPE_MASK;
video_reg |= VP_VS_TYPE_OFF;
}
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;
}

View File

@ -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 */