From cb71201f20e43581857043a1f856fb61ce44bdf8 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 27 Sep 2007 20:34:25 -0300 Subject: [PATCH] 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 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-core.c | 175 ++++++++++++++---- drivers/media/video/saa7134/saa7134-ts.c | 23 ++- drivers/media/video/saa7134/saa7134-tvaudio.c | 4 +- drivers/media/video/saa7134/saa7134-video.c | 125 +++++++------ drivers/media/video/saa7134/saa7134.h | 12 ++ 5 files changed, 244 insertions(+), 95 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index a1d986e01a30..7f5df32ed0e8 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -31,6 +31,7 @@ #include #include #include +#include #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) diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c index 5b1d1dafb5a5..4b63ad3e8466 100644 --- a/drivers/media/video/saa7134/saa7134-ts.c +++ b/drivers/media/video/saa7134/saa7134-ts.c @@ -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; } diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c index 43501b5dc05b..df2dab06387d 100644 --- a/drivers/media/video/saa7134/saa7134-tvaudio.c +++ b/drivers/media/video/saa7134/saa7134-tvaudio.c @@ -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; diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 525b5b77c13a..24d579723b55 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -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; } diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index cb617c8dbb71..5b1f22606558 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -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 */ -- GitLab