cx88-core.c

来自「trident tm5600的linux驱动」· C语言 代码 · 共 1,130 行 · 第 1/3 页

C
1,130
字号
	// setup filters	value = 0;	value |= (1 << 19);        // CFILT (default)	if (core->tvnorm & V4L2_STD_SECAM) {		value |= (1 << 15);		value |= (1 << 16);	}	if (INPUT(core->input).type == CX88_VMUX_SVIDEO)		value |= (1 << 13) | (1 << 5);	if (V4L2_FIELD_INTERLACED == field)		value |= (1 << 3); // VINT (interlaced vertical scaling)	if (width < 385)		value |= (1 << 0); // 3-tap interpolation	if (width < 193)		value |= (1 << 1); // 5-tap interpolation	if (nocomb)		value |= (3 << 5); // disable comb filter	cx_write(MO_FILTER_EVEN,  value);	cx_write(MO_FILTER_ODD,   value);	dprintk(1,"set_scale: filter  0x%04x\n", value);	return 0;}static const u32 xtal = 28636363;static int set_pll(struct cx88_core *core, int prescale, u32 ofreq){	static u32 pre[] = { 0, 0, 0, 3, 2, 1 };	u64 pll;	u32 reg;	int i;	if (prescale < 2)		prescale = 2;	if (prescale > 5)		prescale = 5;	pll = ofreq * 8 * prescale * (u64)(1 << 20);	do_div(pll,xtal);	reg = (pll & 0x3ffffff) | (pre[prescale] << 26);	if (((reg >> 20) & 0x3f) < 14) {		printk("%s/0: pll out of range\n",core->name);		return -1;	}	dprintk(1,"set_pll:    MO_PLL_REG       0x%08x [old=0x%08x,freq=%d]\n",		reg, cx_read(MO_PLL_REG), ofreq);	cx_write(MO_PLL_REG, reg);	for (i = 0; i < 100; i++) {		reg = cx_read(MO_DEVICE_STATUS);		if (reg & (1<<2)) {			dprintk(1,"pll locked [pre=%d,ofreq=%d]\n",				prescale,ofreq);			return 0;		}		dprintk(1,"pll not locked yet, waiting ...\n");		msleep(10);	}	dprintk(1,"pll NOT locked [pre=%d,ofreq=%d]\n",prescale,ofreq);	return -1;}int cx88_start_audio_dma(struct cx88_core *core){	/* constant 128 made buzz in analog Nicam-stereo for bigger fifo_size */	int bpl = cx88_sram_channels[SRAM_CH25].fifo_size/4;	/* If downstream RISC is enabled, bail out; ALSA is managing DMA */	if (cx_read(MO_AUD_DMACNTRL) & 0x10)		return 0;	/* setup fifo + format */	cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], bpl, 0);	cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], bpl, 0);	cx_write(MO_AUDD_LNGTH, bpl); /* fifo bpl size */	cx_write(MO_AUDR_LNGTH, bpl); /* fifo bpl size */	/* start dma */	cx_write(MO_AUD_DMACNTRL, 0x0003); /* Up and Down fifo enable */	return 0;}int cx88_stop_audio_dma(struct cx88_core *core){	/* If downstream RISC is enabled, bail out; ALSA is managing DMA */	if (cx_read(MO_AUD_DMACNTRL) & 0x10)		return 0;	/* stop dma */	cx_write(MO_AUD_DMACNTRL, 0x0000);	return 0;}static int set_tvaudio(struct cx88_core *core){	v4l2_std_id norm = core->tvnorm;	if (CX88_VMUX_TELEVISION != INPUT(core->input).type)		return 0;	if (V4L2_STD_PAL_BG & norm) {		core->tvaudio = WW_BG;	} else if (V4L2_STD_PAL_DK & norm) {		core->tvaudio = WW_DK;	} else if (V4L2_STD_PAL_I & norm) {		core->tvaudio = WW_I;	} else if (V4L2_STD_SECAM_L & norm) {		core->tvaudio = WW_L;	} else if (V4L2_STD_SECAM_DK & norm) {		core->tvaudio = WW_DK;	} else if ((V4L2_STD_NTSC_M & norm) ||		   (V4L2_STD_PAL_M  & norm)) {		core->tvaudio = WW_BTSC;	} else if (V4L2_STD_NTSC_M_JP & norm) {		core->tvaudio = WW_EIAJ;	} else {		printk("%s/0: tvaudio support needs work for this tv norm [%s], sorry\n",		       core->name, v4l2_norm_to_name(core->tvnorm));		core->tvaudio = 0;		return 0;	}	cx_andor(MO_AFECFG_IO, 0x1f, 0x0);	cx88_set_tvaudio(core);	/* cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO); */#if 1/*   This should be needed only on cx88-alsa. It seems that some cx88 chips have   bugs and does require DMA enabled for it to work. */	cx88_start_audio_dma(core);#endif	return 0;}int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm){	u32 fsc8;	u32 adc_clock;	u32 vdec_clock;	u32 step_db,step_dr;	u64 tmp64;	u32 bdelay,agcdelay,htotal;	u32 cxiformat, cxoformat;	core->tvnorm = norm;	fsc8       = norm_fsc8(norm);	adc_clock  = xtal;	vdec_clock = fsc8;	step_db    = fsc8;	step_dr    = fsc8;	if (norm & V4L2_STD_NTSC_M_JP) {		cxiformat = VideoFormatNTSCJapan;		cxoformat = 0x181f0008;	} else if (norm & V4L2_STD_NTSC_443) {		cxiformat = VideoFormatNTSC443;		cxoformat = 0x181f0008;	} else if (norm & V4L2_STD_PAL_M) {		cxiformat = VideoFormatPALM;		cxoformat = 0x1c1f0008;	} else if (norm & V4L2_STD_PAL_N) {		cxiformat = VideoFormatPALN;		cxoformat = 0x1c1f0008;	} else if (norm & V4L2_STD_PAL_Nc) {		cxiformat = VideoFormatPALNC;		cxoformat = 0x1c1f0008;	} else if (norm & V4L2_STD_PAL_60) {		cxiformat = VideoFormatPAL60;		cxoformat = 0x181f0008;	} else if (norm & V4L2_STD_NTSC) {		cxiformat = VideoFormatNTSC;		cxoformat = 0x181f0008;	} else if (norm & V4L2_STD_SECAM) {		step_db = 4250000 * 8;		step_dr = 4406250 * 8;		cxiformat = VideoFormatSECAM;		cxoformat = 0x181f0008;	} else { /* PAL */		cxiformat = VideoFormatPAL;		cxoformat = 0x181f0008;	}	dprintk(1,"set_tvnorm: \"%s\" fsc8=%d adc=%d vdec=%d db/dr=%d/%d\n",		v4l2_norm_to_name(core->tvnorm), fsc8, adc_clock, vdec_clock,		step_db, step_dr);	set_pll(core,2,vdec_clock);	dprintk(1,"set_tvnorm: MO_INPUT_FORMAT  0x%08x [old=0x%08x]\n",		cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);	/* Chroma AGC must be disabled if SECAM is used, we enable it	   by default on PAL and NTSC */	cx_andor(MO_INPUT_FORMAT, 0x40f,		 norm & V4L2_STD_SECAM ? cxiformat : cxiformat | 0x400);#if 1	// FIXME: as-is from DScaler	dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n",		cxoformat, cx_read(MO_OUTPUT_FORMAT));	cx_write(MO_OUTPUT_FORMAT, cxoformat);#endif	// MO_SCONV_REG = adc clock / video dec clock * 2^17	tmp64  = adc_clock * (u64)(1 << 17);	do_div(tmp64, vdec_clock);	dprintk(1,"set_tvnorm: MO_SCONV_REG     0x%08x [old=0x%08x]\n",		(u32)tmp64, cx_read(MO_SCONV_REG));	cx_write(MO_SCONV_REG, (u32)tmp64);	// MO_SUB_STEP = 8 * fsc / video dec clock * 2^22	tmp64  = step_db * (u64)(1 << 22);	do_div(tmp64, vdec_clock);	dprintk(1,"set_tvnorm: MO_SUB_STEP      0x%08x [old=0x%08x]\n",		(u32)tmp64, cx_read(MO_SUB_STEP));	cx_write(MO_SUB_STEP, (u32)tmp64);	// MO_SUB_STEP_DR = 8 * 4406250 / video dec clock * 2^22	tmp64  = step_dr * (u64)(1 << 22);	do_div(tmp64, vdec_clock);	dprintk(1,"set_tvnorm: MO_SUB_STEP_DR   0x%08x [old=0x%08x]\n",		(u32)tmp64, cx_read(MO_SUB_STEP_DR));	cx_write(MO_SUB_STEP_DR, (u32)tmp64);	// bdelay + agcdelay	bdelay   = vdec_clock * 65 / 20000000 + 21;	agcdelay = vdec_clock * 68 / 20000000 + 15;	dprintk(1,"set_tvnorm: MO_AGC_BURST     0x%08x [old=0x%08x,bdelay=%d,agcdelay=%d]\n",		(bdelay << 8) | agcdelay, cx_read(MO_AGC_BURST), bdelay, agcdelay);	cx_write(MO_AGC_BURST, (bdelay << 8) | agcdelay);	// htotal	tmp64 = norm_htotal(norm) * (u64)vdec_clock;	do_div(tmp64, fsc8);	htotal = (u32)tmp64 | (HLNotchFilter4xFsc << 11);	dprintk(1,"set_tvnorm: MO_HTOTAL        0x%08x [old=0x%08x,htotal=%d]\n",		htotal, cx_read(MO_HTOTAL), (u32)tmp64);	cx_write(MO_HTOTAL, htotal);	// vbi stuff, set vbi offset to 10 (for 20 Clk*2 pixels), this makes	// the effective vbi offset ~244 samples, the same as the Bt8x8	cx_write(MO_VBI_PACKET, (10<<11) | norm_vbipack(norm));	// this is needed as well to set all tvnorm parameter	cx88_set_scale(core, 320, 240, V4L2_FIELD_INTERLACED);	// audio	set_tvaudio(core);	// tell i2c chips	cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm);	// done	return 0;}/* ------------------------------------------------------------------ */struct video_device *cx88_vdev_init(struct cx88_core *core,				    struct pci_dev *pci,				    struct video_device *template,				    char *type){	struct video_device *vfd;	vfd = video_device_alloc();	if (NULL == vfd)		return NULL;	*vfd = *template;	vfd->minor   = -1;	vfd->parent  = &pci->dev;	vfd->release = video_device_release;	snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",		 core->name, type, core->board.name);	return vfd;}struct cx88_core* cx88_core_get(struct pci_dev *pci){	struct cx88_core *core;	mutex_lock(&devlist);	list_for_each_entry(core, &cx88_devlist, devlist) {		if (pci->bus->number != core->pci_bus)			continue;		if (PCI_SLOT(pci->devfn) != core->pci_slot)			continue;		if (0 != cx88_get_resources(core, pci)) {			mutex_unlock(&devlist);			return NULL;		}		atomic_inc(&core->refcount);		mutex_unlock(&devlist);		return core;	}	core = cx88_core_create(pci, cx88_devcount);	if (NULL != core) {		cx88_devcount++;		list_add_tail(&core->devlist, &cx88_devlist);	}	mutex_unlock(&devlist);	return core;}void cx88_core_put(struct cx88_core *core, struct pci_dev *pci){	release_mem_region(pci_resource_start(pci,0),			   pci_resource_len(pci,0));	if (!atomic_dec_and_test(&core->refcount))		return;	mutex_lock(&devlist);	cx88_ir_fini(core);	if (0 == core->i2c_rc)		i2c_del_adapter(&core->i2c_adap);	list_del(&core->devlist);	iounmap(core->lmmio);	cx88_devcount--;	mutex_unlock(&devlist);	kfree(core);}/* ------------------------------------------------------------------ */EXPORT_SYMBOL(cx88_print_irqbits);EXPORT_SYMBOL(cx88_core_irq);EXPORT_SYMBOL(cx88_wakeup);EXPORT_SYMBOL(cx88_reset);EXPORT_SYMBOL(cx88_shutdown);EXPORT_SYMBOL(cx88_risc_buffer);EXPORT_SYMBOL(cx88_risc_databuffer);EXPORT_SYMBOL(cx88_risc_stopper);EXPORT_SYMBOL(cx88_free_buffer);EXPORT_SYMBOL(cx88_sram_channels);EXPORT_SYMBOL(cx88_sram_channel_setup);EXPORT_SYMBOL(cx88_sram_channel_dump);EXPORT_SYMBOL(cx88_set_tvnorm);EXPORT_SYMBOL(cx88_set_scale);EXPORT_SYMBOL(cx88_vdev_init);EXPORT_SYMBOL(cx88_core_get);EXPORT_SYMBOL(cx88_core_put);EXPORT_SYMBOL(cx88_ir_start);EXPORT_SYMBOL(cx88_ir_stop);/* * Local variables: * c-basic-offset: 8 * End: * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?