⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 saa7134-tvaudio.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
				}			}		}		if (0 != carrier && max1 > 2000 && max1 > max2*3) {			/* found good carrier */			dprintk("found %s main sound carrier @ %d.%03d MHz [%d/%d]\n",				dev->tvnorm->name, carrier/1000, carrier%1000,				max1, max2);			dev->last_carrier = carrier;		} else if (0 != dev->last_carrier) {			/* no carrier -- try last detected one as fallback */			carrier = dev->last_carrier;			dprintk(KERN_WARNING "%s/audio: audio carrier scan failed, "			       "using %d.%03d MHz [last detected]\n",			       dev->name, carrier/1000, carrier%1000);		} else {			/* no carrier + no fallback -- use default */			carrier = default_carrier;			dprintk(KERN_WARNING "%s/audio: audio carrier scan failed, "			       "using %d.%03d MHz [default]\n",			       dev->name, carrier/1000, carrier%1000);		}		tvaudio_setcarrier(dev,carrier,carrier);		dev->automute = 0;		saa_andorb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0x30, 0x00);		saa7134_tvaudio_setmute(dev);		/* find the exact tv audio norm */		for (audio = UNSET, i = 0; i < TVAUDIO; i++) {			if (dev->tvnorm->id != UNSET &&				!(dev->tvnorm->id & tvaudio[i].std))				continue;			if (tvaudio[i].carr1 != carrier)				continue;			/* Note: at least the primary carrier is right here */			if (UNSET == audio)				audio = i;			tvaudio_setmode(dev,&tvaudio[i],"trying");			if (tvaudio_sleep(dev,SCAN_SUBCARRIER_DELAY))				goto restart;			if (-1 != tvaudio_getstereo(dev,&tvaudio[i])) {				audio = i;				break;			}		}		saa_andorb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0x30, 0x30);		if (UNSET == audio)			continue;		tvaudio_setmode(dev,&tvaudio[audio],"using");		tvaudio_setstereo(dev,&tvaudio[audio],V4L2_TUNER_MODE_MONO);		dev->tvaudio = &tvaudio[audio];		lastmode = 42;		for (;;) {			try_to_freeze();			if (tvaudio_sleep(dev,5000))				goto restart;			if (kthread_should_stop())				break;			if (UNSET == dev->thread.mode) {				rx = tvaudio_getstereo(dev,&tvaudio[i]);				mode = saa7134_tvaudio_rx2mode(rx);			} else {				mode = dev->thread.mode;			}			if (lastmode != mode) {				tvaudio_setstereo(dev,&tvaudio[audio],mode);				lastmode = mode;			}		}	} done:	dev->thread.stopped = 1;	return 0;}/* ------------------------------------------------------------------ *//* saa7133 / saa7135 code                                             */static char *stdres[0x20] = {	[0x00] = "no standard detected",	[0x01] = "B/G (in progress)",	[0x02] = "D/K (in progress)",	[0x03] = "M (in progress)",	[0x04] = "B/G A2",	[0x05] = "B/G NICAM",	[0x06] = "D/K A2 (1)",	[0x07] = "D/K A2 (2)",	[0x08] = "D/K A2 (3)",	[0x09] = "D/K NICAM",	[0x0a] = "L NICAM",	[0x0b] = "I NICAM",	[0x0c] = "M Korea",	[0x0d] = "M BTSC ",	[0x0e] = "M EIAJ",	[0x0f] = "FM radio / IF 10.7 / 50 deemp",	[0x10] = "FM radio / IF 10.7 / 75 deemp",	[0x11] = "FM radio / IF sel / 50 deemp",	[0x12] = "FM radio / IF sel / 75 deemp",	[0x13 ... 0x1e ] = "unknown",	[0x1f] = "??? [in progress]",};#define DSP_RETRY 32#define DSP_DELAY 16#define SAA7135_DSP_RWCLEAR_RERR 1static inline int saa_dsp_reset_error_bit(struct saa7134_dev *dev){	int state = saa_readb(SAA7135_DSP_RWSTATE);	if (unlikely(state & SAA7135_DSP_RWSTATE_ERR)) {		d2printk("%s: resetting error bit\n", dev->name);		saa_writeb(SAA7135_DSP_RWCLEAR, SAA7135_DSP_RWCLEAR_RERR);	}	return 0;}static inline int saa_dsp_wait_bit(struct saa7134_dev *dev, int bit){	int state, count = DSP_RETRY;	state = saa_readb(SAA7135_DSP_RWSTATE);	if (unlikely(state & SAA7135_DSP_RWSTATE_ERR)) {		printk(KERN_WARNING "%s: dsp access error\n", dev->name);		saa_dsp_reset_error_bit(dev);		return -EIO;	}	while (0 == (state & bit)) {		if (unlikely(0 == count)) {			printk("%s: dsp access wait timeout [bit=%s]\n",			       dev->name,			       (bit & SAA7135_DSP_RWSTATE_WRR) ? "WRR" :			       (bit & SAA7135_DSP_RWSTATE_RDB) ? "RDB" :			       (bit & SAA7135_DSP_RWSTATE_IDA) ? "IDA" :			       "???");			return -EIO;		}		saa_wait(DSP_DELAY);		state = saa_readb(SAA7135_DSP_RWSTATE);		count--;	}	return 0;}#if 0static int saa_dsp_readl(struct saa7134_dev *dev, int reg, u32 *value){	int err;	d2printk("dsp read reg 0x%x\n", reg<<2);	saa_readl(reg);	err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_RDB);	if (err < 0)		return err;	*value = saa_readl(reg);	d2printk("dsp read   => 0x%06x\n", *value & 0xffffff);	err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_IDA);	if (err < 0)		return err;	return 0;}#endifint saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value){	int err;	d2printk("dsp write reg 0x%x = 0x%06x\n",reg<<2,value);	err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_WRR);	if (err < 0)		return err;	saa_writel(reg,value);	err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_WRR);	if (err < 0)		return err;	return 0;}static int getstereo_7133(struct saa7134_dev *dev){	int retval = V4L2_TUNER_SUB_MONO;	u32 value;	value = saa_readl(0x528 >> 2);	if (value & 0x20)		retval = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;	if (value & 0x40)		retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;	return retval;}static int mute_input_7133(struct saa7134_dev *dev){	u32 reg = 0;	u32 xbarin, xbarout;	int mask;	struct saa7134_input *in;	xbarin = 0x03;	switch (dev->input->amux) {	case TV:		reg = 0x02;		xbarin = 0;		break;	case LINE1:		reg = 0x00;		break;	case LINE2:	case LINE2_LEFT:		reg = 0x09;		break;	}	saa_dsp_writel(dev, 0x464 >> 2, xbarin);	if (dev->ctl_mute) {		reg = 0x07;		xbarout = 0xbbbbbb;	} else		xbarout = 0xbbbb10;	saa_dsp_writel(dev, 0x46c >> 2, xbarout);	saa_writel(0x594 >> 2, reg);	/* switch gpio-connected external audio mux */	if (0 != card(dev).gpiomask) {		mask = card(dev).gpiomask;		if (card(dev).mute.name && dev->ctl_mute)			in = &card(dev).mute;		else			in = dev->input;		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   mask, mask);		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, in->gpio);		saa7134_track_gpio(dev,in->name);	}	return 0;}static int tvaudio_thread_ddep(void *data){	struct saa7134_dev *dev = data;	u32 value, norms;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)	set_freezable();#endif	for (;;) {		tvaudio_sleep(dev,-1);		if (kthread_should_stop())			goto done;	restart:		try_to_freeze();		dev->thread.scan1 = dev->thread.scan2;		dprintk("tvaudio thread scan start [%d]\n",dev->thread.scan1);		if (audio_ddep >= 0x04 && audio_ddep <= 0x0e) {			/* insmod option override */			norms = (audio_ddep << 2) | 0x01;			dprintk("ddep override: %s\n",stdres[audio_ddep]);		} else if (&card(dev).radio == dev->input) {			dprintk("FM Radio\n");			if (dev->tuner_type == TUNER_PHILIPS_TDA8290) {				norms = (0x11 << 2) | 0x01;				saa_dsp_writel(dev, 0x42c >> 2, 0x729555);			} else {				norms = (0x0f << 2) | 0x01;			}		} else {			/* (let chip) scan for sound carrier */			norms = 0;			if (dev->tvnorm->id & (V4L2_STD_B | V4L2_STD_GH))				norms |= 0x04;			if (dev->tvnorm->id & V4L2_STD_PAL_I)				norms |= 0x20;			if (dev->tvnorm->id & V4L2_STD_DK)				norms |= 0x08;			if (dev->tvnorm->id & V4L2_STD_MN)				norms |= 0x40;			if (dev->tvnorm->id & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))				norms |= 0x10;			if (0 == norms)				norms = 0x7c; /* all */			dprintk("scanning:%s%s%s%s%s\n",				(norms & 0x04) ? " B/G"  : "",				(norms & 0x08) ? " D/K"  : "",				(norms & 0x10) ? " L/L'" : "",				(norms & 0x20) ? " I"    : "",				(norms & 0x40) ? " M"    : "");		}		/* kick automatic standard detection */		saa_dsp_writel(dev, 0x454 >> 2, 0);		saa_dsp_writel(dev, 0x454 >> 2, norms | 0x80);		/* setup crossbars */		saa_dsp_writel(dev, 0x464 >> 2, 0x000000);		saa_dsp_writel(dev, 0x470 >> 2, 0x101010);		if (tvaudio_sleep(dev,3000))			goto restart;		value = saa_readl(0x528 >> 2) & 0xffffff;		dprintk("tvaudio thread status: 0x%x [%s%s%s]\n",			value, stdres[value & 0x1f],			(value & 0x000020) ? ",stereo" : "",			(value & 0x000040) ? ",dual"   : "");		dprintk("detailed status: "			"%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s\n",			(value & 0x000080) ? " A2/EIAJ pilot tone "     : "",			(value & 0x000100) ? " A2/EIAJ dual "           : "",			(value & 0x000200) ? " A2/EIAJ stereo "         : "",			(value & 0x000400) ? " A2/EIAJ noise mute "     : "",			(value & 0x000800) ? " BTSC/FM radio pilot "    : "",			(value & 0x001000) ? " SAP carrier "            : "",			(value & 0x002000) ? " BTSC stereo noise mute " : "",			(value & 0x004000) ? " SAP noise mute "         : "",			(value & 0x008000) ? " VDSP "                   : "",			(value & 0x010000) ? " NICST "                  : "",			(value & 0x020000) ? " NICDU "                  : "",			(value & 0x040000) ? " NICAM muted "            : "",			(value & 0x080000) ? " NICAM reserve sound "    : "",			(value & 0x100000) ? " init done "              : "");	} done:	dev->thread.stopped = 1;	return 0;}/* ------------------------------------------------------------------ *//* common stuff + external entry points                               */void saa7134_enable_i2s(struct saa7134_dev *dev){	int i2s_format;	if (!card_is_empress(dev))		return;	if (dev->pci->device == PCI_DEVICE_ID_PHILIPS_SAA7130)		return;	/* configure GPIO for out */	saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x0E000000, 0x00000000);	switch (dev->pci->device) {	case PCI_DEVICE_ID_PHILIPS_SAA7133:	case PCI_DEVICE_ID_PHILIPS_SAA7135:	    /* Set I2S format (SONY)  */	    saa_writeb(SAA7133_I2S_AUDIO_CONTROL, 0x00);	    /* Start I2S */	    saa_writeb(SAA7134_I2S_AUDIO_OUTPUT, 0x11);	    break;	case PCI_DEVICE_ID_PHILIPS_SAA7134:	    i2s_format = (dev->input->amux == TV) ? 0x00 : 0x01;	    /* enable I2S audio output for the mpeg encoder */	    saa_writeb(SAA7134_I2S_OUTPUT_SELECT, 0x80);	    saa_writeb(SAA7134_I2S_OUTPUT_FORMAT, i2s_format);	    saa_writeb(SAA7134_I2S_OUTPUT_LEVEL,  0x0F);	    saa_writeb(SAA7134_I2S_AUDIO_OUTPUT,  0x01);	default:	    break;	}}int saa7134_tvaudio_rx2mode(u32 rx){	u32 mode;	mode = V4L2_TUNER_MODE_MONO;	if (rx & V4L2_TUNER_SUB_STEREO)		mode = V4L2_TUNER_MODE_STEREO;	else if (rx & V4L2_TUNER_SUB_LANG1)		mode = V4L2_TUNER_MODE_LANG1;	else if (rx & V4L2_TUNER_SUB_LANG2)		mode = V4L2_TUNER_MODE_LANG2;	return mode;}void saa7134_tvaudio_setmute(struct saa7134_dev *dev){	switch (dev->pci->device) {	case PCI_DEVICE_ID_PHILIPS_SAA7130:	case PCI_DEVICE_ID_PHILIPS_SAA7134:		mute_input_7134(dev);		break;	case PCI_DEVICE_ID_PHILIPS_SAA7133:	case PCI_DEVICE_ID_PHILIPS_SAA7135:		mute_input_7133(dev);		break;	}}void saa7134_tvaudio_setinput(struct saa7134_dev *dev,			      struct saa7134_input *in){	dev->input = in;	switch (dev->pci->device) {	case PCI_DEVICE_ID_PHILIPS_SAA7130:	case PCI_DEVICE_ID_PHILIPS_SAA7134:		mute_input_7134(dev);		break;	case PCI_DEVICE_ID_PHILIPS_SAA7133:	case PCI_DEVICE_ID_PHILIPS_SAA7135:		mute_input_7133(dev);		break;	}	saa7134_enable_i2s(dev);}void saa7134_tvaudio_setvolume(struct saa7134_dev *dev, int level){	switch (dev->pci->device) {	case PCI_DEVICE_ID_PHILIPS_SAA7134:		saa_writeb(SAA7134_CHANNEL1_LEVEL,     level & 0x1f);		saa_writeb(SAA7134_CHANNEL2_LEVEL,     level & 0x1f);		saa_writeb(SAA7134_NICAM_LEVEL_ADJUST, level & 0x1f);		break;	}}int saa7134_tvaudio_getstereo(struct saa7134_dev *dev){	int retval = V4L2_TUNER_SUB_MONO;	switch (dev->pci->device) {	case PCI_DEVICE_ID_PHILIPS_SAA7134:		if (dev->tvaudio)			retval = tvaudio_getstereo(dev,dev->tvaudio);		break;	case PCI_DEVICE_ID_PHILIPS_SAA7133:	case PCI_DEVICE_ID_PHILIPS_SAA7135:		retval = getstereo_7133(dev);		break;	}	return retval;}void saa7134_tvaudio_init(struct saa7134_dev *dev){	int clock = saa7134_boards[dev->board].audio_clock;	if (UNSET != audio_clock_override)		clock = audio_clock_override;	switch (dev->pci->device) {	case PCI_DEVICE_ID_PHILIPS_SAA7134:		/* init all audio registers */		saa_writeb(SAA7134_AUDIO_PLL_CTRL,   0x00);		if (need_resched())			schedule();		else			udelay(10);		saa_writeb(SAA7134_AUDIO_CLOCK0,      clock        & 0xff);		saa_writeb(SAA7134_AUDIO_CLOCK1,     (clock >>  8) & 0xff);		saa_writeb(SAA7134_AUDIO_CLOCK2,     (clock >> 16) & 0xff);		/* frame locked audio is mandatory for NICAM */		saa_writeb(SAA7134_AUDIO_PLL_CTRL,   0x01);		saa_writeb(SAA7134_NICAM_ERROR_LOW,  0x14);		saa_writeb(SAA7134_NICAM_ERROR_HIGH, 0x50);		break;	case PCI_DEVICE_ID_PHILIPS_SAA7133:	case PCI_DEVICE_ID_PHILIPS_SAA7135:		saa_writel(0x598 >> 2, clock);		saa_dsp_writel(dev, 0x474 >> 2, 0x00);		saa_dsp_writel(dev, 0x450 >> 2, 0x00);	}}int saa7134_tvaudio_init2(struct saa7134_dev *dev){	int (*my_thread)(void *data) = NULL;	switch (dev->pci->device) {	case PCI_DEVICE_ID_PHILIPS_SAA7134:		my_thread = tvaudio_thread;		break;	case PCI_DEVICE_ID_PHILIPS_SAA7133:	case PCI_DEVICE_ID_PHILIPS_SAA7135:		my_thread = tvaudio_thread_ddep;		break;	}	dev->thread.thread = NULL;	if (my_thread) {		saa7134_tvaudio_init(dev);		/* start tvaudio thread */		dev->thread.thread = kthread_run(my_thread, dev, "%s", dev->name);		if (IS_ERR(dev->thread.thread)) {			printk(KERN_WARNING "%s: kernel_thread() failed\n",			       dev->name);			/* XXX: missing error handling here */		}		saa7134_tvaudio_do_scan(dev);	}	saa7134_enable_i2s(dev);	return 0;}int saa7134_tvaudio_fini(struct saa7134_dev *dev){	/* shutdown tvaudio thread */	if (dev->thread.thread && !dev->thread.stopped)		kthread_stop(dev->thread.thread);	saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x07, 0x00); /* LINE1 */	return 0;}int saa7134_tvaudio_do_scan(struct saa7134_dev *dev){	if (dev->input->amux != TV) {		dprintk("sound IF not in use, skipping scan\n");		dev->automute = 0;		saa7134_tvaudio_setmute(dev);	} else if (dev->thread.thread) {		dev->thread.mode = UNSET;		dev->thread.scan2++;		if (!dev->insuspend && !dev->thread.stopped)			wake_up_process(dev->thread.thread);	} else {		dev->automute = 0;		saa7134_tvaudio_setmute(dev);	}	return 0;}EXPORT_SYMBOL(saa_dsp_writel);EXPORT_SYMBOL(saa7134_tvaudio_setmute);/* ----------------------------------------------------------- *//* * Local variables: * c-basic-offset: 8 * End: */

⌨️ 快捷键说明

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