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

📄 msp3400.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
	case VIDEO_MODE_PAL:		msp3400_dbg("video mode selected to PAL\n");#if 1		/* experimental: not sure this works with all chip versions */		return 0x7003;#else		/* previous value, try this if it breaks ... */		return 0x1003;#endif	case VIDEO_MODE_NTSC:  /* BTSC */		msp3400_dbg("video mode selected to NTSC\n");		return 0x2003;	case VIDEO_MODE_SECAM:		msp3400_dbg("video mode selected to SECAM\n");		return 0x0003;	case VIDEO_MODE_RADIO:		msp3400_dbg("video mode selected to Radio\n");		return 0x0003;	case VIDEO_MODE_AUTO:		msp3400_dbg("video mode selected to Auto\n");		return 0x2003;	default:		return 0x0003;	}}static int msp34xx_standard(int norm){	switch (norm) {	case VIDEO_MODE_PAL:		return 1;	case VIDEO_MODE_NTSC:  /* BTSC */		return 0x0020;	case VIDEO_MODE_SECAM:		return 1;	case VIDEO_MODE_RADIO:		return 0x0040;	default:		return 1;	}}static int msp3410d_thread(void *data){	struct i2c_client *client = data;	struct msp3400c *msp = i2c_get_clientdata(client);	int mode,val,i,std;	msp3400_info("msp3410 daemon started\n");	for (;;) {		msp3400_dbg_mediumvol("msp3410 thread: sleep\n");		msp34xx_sleep(msp,-1);		msp3400_dbg_mediumvol("msp3410 thread: wakeup\n");	restart:		msp3400_dbg("thread: restart scan\n");		msp->restart = 0;		if (kthread_should_stop())			break;		if (msp->mode == MSP_MODE_EXTERN) {			/* no carrier scan needed, just unmute */			msp3400_dbg("thread: no carrier scan\n");		msp3400c_setvolume(client, msp->muted, msp->left, msp->right);			continue;		}		/* put into sane state (and mute) */		msp3400c_reset(client);		/* some time for the tuner to sync */		if (msp34xx_sleep(msp,200))			goto restart;		/* start autodetect */		mode = msp34xx_modus(client, msp->norm);		std  = msp34xx_standard(msp->norm);		msp3400c_write(client, I2C_MSP3400C_DEM, 0x30, mode);		msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, std);		msp->watch_stereo = 0;		if (debug)			msp3400_dbg("setting mode: %s (0x%04x)\n",			       msp34xx_standard_mode_name(std) ,std);		if (std != 1) {			/* programmed some specific mode */			val = std;		} else {			/* triggered autodetect */			for (;;) {				if (msp34xx_sleep(msp,100))					goto restart;				/* check results */				val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e);				if (val < 0x07ff)					break;				msp3400_dbg("detection still in progress\n");			}		}		for (i = 0; modelist[i].name != NULL; i++)			if (modelist[i].retval == val)				break;		msp3400_dbg("current mode: %s (0x%04x)\n",			modelist[i].name ? modelist[i].name : "unknown",			val);		msp->main   = modelist[i].main;		msp->second = modelist[i].second;		if (amsound && (msp->norm == VIDEO_MODE_SECAM) && (val != 0x0009)) {			/* autodetection has failed, let backup */			msp3400_dbg("autodetection failed,"				" switching to backup mode: %s (0x%04x)\n",				modelist[8].name ? modelist[8].name : "unknown",val);			val = 0x0009;			msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, val);		}		/* set various prescales */		msp3400c_write(client, I2C_MSP3400C_DFP, 0x0d, 0x1900); /* scart */		msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM */		msp3400c_write(client, I2C_MSP3400C_DFP, 0x10, 0x5a00); /* nicam */		/* set stereo */		switch (val) {		case 0x0008: /* B/G NICAM */		case 0x000a: /* I NICAM */			if (val == 0x0008)				msp->mode = MSP_MODE_FM_NICAM1;			else				msp->mode = MSP_MODE_FM_NICAM2;			/* just turn on stereo */			msp->rxsubchans = V4L2_TUNER_SUB_STEREO;			msp->nicam_on = 1;			msp->watch_stereo = 1;			msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);			break;		case 0x0009:			msp->mode = MSP_MODE_AM_NICAM;			msp->rxsubchans = V4L2_TUNER_SUB_MONO;			msp->nicam_on = 1;			msp3400c_setstereo(client,V4L2_TUNER_MODE_MONO);			msp->watch_stereo = 1;			break;		case 0x0020: /* BTSC */			/* just turn on stereo */			msp->mode = MSP_MODE_BTSC;			msp->rxsubchans = V4L2_TUNER_SUB_STEREO;			msp->nicam_on = 0;			msp->watch_stereo = 1;			msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);			break;		case 0x0040: /* FM radio */			msp->mode   = MSP_MODE_FM_RADIO;			msp->rxsubchans = V4L2_TUNER_SUB_STEREO;			msp->audmode = V4L2_TUNER_MODE_STEREO;			msp->nicam_on = 0;			msp->watch_stereo = 0;			/* not needed in theory if HAVE_RADIO(), but			   short programming enables carrier mute */			msp3400c_setmode(client,MSP_MODE_FM_RADIO);			msp3400c_setcarrier(client, MSP_CARRIER(10.7),					    MSP_CARRIER(10.7));			/* scart routing */			msp3400c_set_scart(client,SCART_IN2,0);			/* msp34xx does radio decoding */			msp3400c_write(client,I2C_MSP3400C_DFP, 0x08, 0x0020);			msp3400c_write(client,I2C_MSP3400C_DFP, 0x09, 0x0020);			msp3400c_write(client,I2C_MSP3400C_DFP, 0x0b, 0x0020);			break;		case 0x0003:		case 0x0004:		case 0x0005:			msp->mode   = MSP_MODE_FM_TERRA;			msp->rxsubchans = V4L2_TUNER_SUB_MONO;			msp->audmode = V4L2_TUNER_MODE_MONO;			msp->nicam_on = 0;			msp->watch_stereo = 1;			break;		}		/* unmute, restore misc registers */		msp3400c_setbass(client, msp->bass);		msp3400c_settreble(client, msp->treble);		msp3400c_setvolume(client, msp->muted, msp->left, msp->right);		msp3400c_write(client, I2C_MSP3400C_DFP, 0x13, msp->acb);		msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);		msp3400c_restore_dfp(client);		/* monitor tv audio mode */		while (msp->watch_stereo) {			if (msp34xx_sleep(msp,5000))				goto restart;			watch_stereo(client);		}	}	msp3400_dbg("thread: exit\n");	return 0;}/* ----------------------------------------------------------------------- *//* msp34xxG + (simpler no-thread)                                          *//* this one uses both automatic standard detection and automatic sound     *//* select which are available in the newer G versions                      *//* struct msp: only norm, acb and source are really used in this mode      */static void msp34xxg_set_source(struct i2c_client *client, int source);/* (re-)initialize the msp34xxg, according to the current norm in msp->norm * return 0 if it worked, -1 if it failed */static int msp34xxg_reset(struct i2c_client *client){	struct msp3400c *msp = i2c_get_clientdata(client);	int modus,std;	if (msp3400c_reset(client))		return -1;	/* make sure that input/output is muted (paranoid mode) */	if (msp3400c_write(client,			   I2C_MSP3400C_DFP,			   0x13, /* ACB */			   0x0f20 /* mute DSP input, mute SCART 1 */))		return -1;	msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);	/* step-by-step initialisation, as described in the manual */	modus = msp34xx_modus(client, msp->norm);	std   = msp34xx_standard(msp->norm);	modus &= ~0x03; /* STATUS_CHANGE=0 */	modus |= 0x01;  /* AUTOMATIC_SOUND_DETECTION=1 */	if (msp3400c_write(client,			   I2C_MSP3400C_DEM,			   0x30/*MODUS*/,			   modus))		return -1;	if (msp3400c_write(client,			   I2C_MSP3400C_DEM,			   0x20/*standard*/,			   std))		return -1;	/* write the dfps that may have an influence on	   standard/audio autodetection right now */	msp34xxg_set_source(client, msp->source);	if (msp3400c_write_dfp_with_default(client, 0x0e,	/* AM/FM Prescale */					    0x3000					    /* default: [15:8] 75khz deviation */	    ))		return -1;	if (msp3400c_write_dfp_with_default(client, 0x10,	/* NICAM Prescale */					    0x5a00					    /* default: 9db gain (as recommended) */	    ))		return -1;	return 0;}static int msp34xxg_thread(void *data){	struct i2c_client *client = data;	struct msp3400c *msp = i2c_get_clientdata(client);	int val, std, i;	msp3400_info("msp34xxg daemon started\n");	msp->source = 1; /* default */	for (;;) {		msp3400_dbg_mediumvol("msp34xxg thread: sleep\n");		msp34xx_sleep(msp,-1);		msp3400_dbg_mediumvol("msp34xxg thread: wakeup\n");	restart:		msp3400_dbg("thread: restart scan\n");		msp->restart = 0;		if (kthread_should_stop())			break;		/* setup the chip*/		msp34xxg_reset(client);		std = standard;		if (std != 0x01)			goto unmute;		/* watch autodetect */		msp3400_dbg("triggered autodetect, waiting for result\n");		for (i = 0; i < 10; i++) {			if (msp34xx_sleep(msp,100))				goto restart;			/* check results */			val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e);			if (val < 0x07ff) {				std = val;				break;			}			msp3400_dbg("detection still in progress\n");		}		if (0x01 == std) {			msp3400_dbg("detection still in progress after 10 tries. giving up.\n");			continue;		}	unmute:		msp3400_dbg("current mode: %s (0x%04x)\n",			msp34xx_standard_mode_name(std), std);		/* unmute: dispatch sound to scart output, set scart volume */		msp3400_dbg("unmute\n");		msp3400c_setbass(client, msp->bass);		msp3400c_settreble(client, msp->treble);		msp3400c_setvolume(client, msp->muted, msp->left, msp->right);		/* restore ACB */		if (msp3400c_write(client,				   I2C_MSP3400C_DFP,				   0x13, /* ACB */				   msp->acb))			return -1;		msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);	}	msp3400_dbg("thread: exit\n");	return 0;}/* set the same 'source' for the loudspeaker, scart and quasi-peak detector * the value for source is the same as bit 15:8 of DFP registers 0x08, * 0x0a and 0x0c: 0=mono, 1=stereo or A|B, 2=SCART, 3=stereo or A, 4=stereo or B * * this function replaces msp3400c_setstereo */static void msp34xxg_set_source(struct i2c_client *client, int source){	struct msp3400c *msp = i2c_get_clientdata(client);	/* fix matrix mode to stereo and let the msp choose what	 * to output according to 'source', as recommended	 * for MONO (source==0) downmixing set bit[7:0] to 0x30	 */	int value = (source&0x07)<<8|(source==0 ? 0x30:0x20);	msp3400_dbg("set source to %d (0x%x)\n", source, value);	msp3400c_write(client,		       I2C_MSP3400C_DFP,		       0x08, /* Loudspeaker Output */		       value);	msp3400c_write(client,		       I2C_MSP3400C_DFP,		       0x0a, /* SCART1 DA Output */		       value);	msp3400c_write(client,		       I2C_MSP3400C_DFP,		       0x0c, /* Quasi-peak detector */		       value);	/*	 * set identification threshold. Personally, I	 * I set it to a higher value that the default	 * of 0x190 to ignore noisy stereo signals.	 * this needs tuning. (recommended range 0x00a0-0x03c0)	 * 0x7f0 = forced mono mode	 */	msp3400c_write(client,		       I2C_MSP3400C_DEM,		       0x22, /* a2 threshold for stereo/bilingual */		       stereo_threshold);	msp->source=source;}static void msp34xxg_detect_stereo(struct i2c_client *client){	struct msp3400c *msp = i2c_get_clientdata(client);	int status = msp3400c_read(client,				   I2C_MSP3400C_DEM,				   0x0200 /* STATUS */);	int is_bilingual = status&0x100;	int is_stereo = status&0x40;	msp->rxsubchans = 0;	if (is_stereo)		msp->rxsubchans |= V4L2_TUNER_SUB_STEREO;	else		msp->rxsubchans |= V4L2_TUNER_SUB_MONO;	if (is_bilingual) {		msp->rxsubchans |= V4L2_TUNER_SUB_LANG1|V4L2_TUNER_SUB_LANG2;		/* I'm supposed to check whether it's SAP or not		 * and set only LANG2/SAP in this case. Yet, the MSP		 * does a lot of work to hide this and handle everything		 * the same way. I don't want to work around it so unless		 * this is a problem, I'll handle SAP just like lang1/lang2.		 */	}	msp3400_dbg("status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n",		status, is_stereo, is_bilingual, msp->rxsubchans);}static void msp34xxg_set_audmode(struct i2c_client *client, int audmode){	struct msp3400c *msp = i2c_get_clientdata(client);	int source;	switch (audmode) {	case V4L2_TUNER_MODE_MONO:		source=0; /* mono only */		break;	case V4L2_TUNER_MODE_STEREO:		source=1; /* stereo or A|B, see comment in msp34xxg_get_v4l2_stereo() */		/* problem: that could also mean 2 (scart input) */		break;	case V4L2_TUNER_MODE_LANG1:		source=3; /* stereo or A */		break;	case V4L2_TUNER_MODE_LANG2:		source=4; /* stereo or B */		break;	default:		audmode = 0;		source  = 1;		break;	}	msp->audmode = audmode;	msp34xxg_set_source(client, source);}/* ----------------------------------------------------------------------- */static int msp_attach(struct i2c_adapter *adap, int addr, int kind);static int msp_detach(struct i2c_client *client);static int msp_probe(struct i2c_adapter *adap);static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg);static int msp_suspend(struct device * dev, pm_message_t state);static int msp_resume(struct device * dev);static void msp_wake_thread(struct i2c_client *client);static struct i2c_driver driver = {	.owner          = THIS_MODULE,	.name           = "msp3400",	.id             = I2C_DRIVERID_MSP3400,	.flags          = I2C_DF_NOTIFY,	.attach_adapter = msp_probe,	.detach_client  = msp_detach,	.command        = msp_command,	.driver = {		.suspend = msp_suspend,		.resume  = msp_resume,	},};static struct i2c_client client_template ={	.name      = "(unset)",	.flags     = I2C_CLIENT_ALLOW_USE,	.driver    = &driver,};static int msp_attach(struct i2c_adapter *adap, int addr, int kind){	struct msp3400c *msp;	struct i2c_client *client = &client_template;	int (*thread_func)(void *data) = NULL;	int i;	client_template.adapter = adap;	client_template.addr = addr;	if (-1 == msp3400c_reset(&client_template)) {		msp3400_dbg("no chip found\n");		return -1;	}	if (NULL == (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL)))		return -ENOMEM;	memcpy(client,&client_template,sizeof(struct i2c_client));	if (NULL == (msp = kmalloc(sizeof(struct msp3400c),GFP_KERNEL))) {		kfree(client);		return -ENOMEM;	}	memset(msp,0,sizeof(struct msp3400c));	msp->norm = VIDEO_MODE_NTSC;	msp->left = 58880;	/* 0db gain */	msp->right = 58880;	/* 0db gain */	msp->bass = 32768;	msp->treble = 32768;	msp->input = -1;	msp->muted = 0;	msp->i2s_mode = 0;	for (i = 0; i < DFP_COUNT; i++)		msp->dfp_regs[i] = -1;	i2c_set_clientdata(client, msp);	init_waitqueue_head(&msp->wq);	if (-1 == msp3400c_reset(client)) {		kfree(msp);		kfree(client);		msp3400_dbg("no chip found\n");		return -1;	}	msp->rev1 = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1e);	if (-1 != msp->rev1)		msp->rev2 = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1f);	if ((-1 == msp->rev1) || (0 == msp->rev1 && 0 == msp->rev2)) {		kfree(msp);		kfree(client);		msp3400_dbg("error while reading chip version\n");		return -1;	}	msp3400_dbg("rev1=0x%04x, rev2=0x%04x\n", msp->rev1, msp->rev2);	msp3400c_setvolume(client, msp->muted, msp->left, msp->right);	snprintf(client->name, sizeof(client->name), "MSP%c4%02d%c-%c%d",		 ((msp->rev1>>4)&0x0f) + '3',		 (msp->rev2>>8)&0xff, (msp->rev1&0x0f)+'@',		 ((msp->rev1>>8)&0xff)+'@', msp->rev2&0x1f);	msp->opmode = opmode;	if (OPMODE_AUTO == msp->opmode) {		if (HAVE_SIMPLER(msp))			msp->opmode = OPMODE_SIMPLER;		else if (HAVE_SIMPLE(msp))			msp->opmode = OPMODE_SIMPLE;		else			msp->opmode = OPMODE_MANUAL;	}	/* hello world :-) */	msp3400_info("chip=%s", client->name);	if (HAVE_NICAM(msp))		printk(" +nicam");	if (HAVE_SIMPLE(msp))		printk(" +simple");	if (HAVE_SIMPLER(msp))		printk(" +simpler");	if (HAVE_RADIO(msp))		printk(" +radio");	/* version-specific initialization */	switch (msp->opmode) {	case OPMODE_MANUAL:		printk(" mode=manual");		thread_func = msp3400c_thread;		break;	case OPMODE_SIMPLE:

⌨️ 快捷键说明

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