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

📄 tuner-simple.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
		IFPCoff      = 940;		desired_type = TUNER_PARAM_TYPE_NTSC;	} else if ((params->std & V4L2_STD_MN) &&		  !(params->std & ~V4L2_STD_MN)) {		IFPCoff      = 732;		desired_type = TUNER_PARAM_TYPE_NTSC;	} else if (params->std == V4L2_STD_SECAM_LC) {		IFPCoff      = 543;		desired_type = TUNER_PARAM_TYPE_SECAM;	} else {		IFPCoff      = 623;		desired_type = TUNER_PARAM_TYPE_PAL;	}	t_params = simple_tuner_params(fe, desired_type);	i = simple_config_lookup(fe, t_params, &params->frequency,				 &config, &cb);	div = params->frequency + IFPCoff + offset;	tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, "		  "Offset=%d.%02d MHz, div=%0d\n",		  params->frequency / 16, params->frequency % 16 * 100 / 16,		  IFPCoff / 16, IFPCoff % 16 * 100 / 16,		  offset / 16, offset % 16 * 100 / 16, div);	/* tv norm specific stuff for multi-norm tuners */	simple_std_setup(fe, params, &config, &cb);	if (t_params->cb_first_if_lower_freq && div < priv->last_div) {		buffer[0] = config;		buffer[1] = cb;		buffer[2] = (div>>8) & 0x7f;		buffer[3] = div      & 0xff;	} else {		buffer[0] = (div>>8) & 0x7f;		buffer[1] = div      & 0xff;		buffer[2] = config;		buffer[3] = cb;	}	priv->last_div = div;	if (t_params->has_tda9887) {		struct v4l2_priv_tun_config tda9887_cfg;		int tda_config = 0;		int is_secam_l = (params->std & (V4L2_STD_SECAM_L |						 V4L2_STD_SECAM_LC)) &&			!(params->std & ~(V4L2_STD_SECAM_L |					  V4L2_STD_SECAM_LC));		tda9887_cfg.tuner = TUNER_TDA9887;		tda9887_cfg.priv  = &tda_config;		if (params->std == V4L2_STD_SECAM_LC) {			if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc)				tda_config |= TDA9887_PORT1_ACTIVE;			if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc)				tda_config |= TDA9887_PORT2_ACTIVE;		} else {			if (t_params->port1_active)				tda_config |= TDA9887_PORT1_ACTIVE;			if (t_params->port2_active)				tda_config |= TDA9887_PORT2_ACTIVE;		}		if (t_params->intercarrier_mode)			tda_config |= TDA9887_INTERCARRIER;		if (is_secam_l) {			if (i == 0 && t_params->default_top_secam_low)				tda_config |= TDA9887_TOP(t_params->default_top_secam_low);			else if (i == 1 && t_params->default_top_secam_mid)				tda_config |= TDA9887_TOP(t_params->default_top_secam_mid);			else if (t_params->default_top_secam_high)				tda_config |= TDA9887_TOP(t_params->default_top_secam_high);		} else {			if (i == 0 && t_params->default_top_low)				tda_config |= TDA9887_TOP(t_params->default_top_low);			else if (i == 1 && t_params->default_top_mid)				tda_config |= TDA9887_TOP(t_params->default_top_mid);			else if (t_params->default_top_high)				tda_config |= TDA9887_TOP(t_params->default_top_high);		}		if (t_params->default_pll_gating_18)			tda_config |= TDA9887_GATING_18;		i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,				    &tda9887_cfg);	}	tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",		  buffer[0], buffer[1], buffer[2], buffer[3]);	rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);	if (4 != rc)		tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc);	simple_post_tune(fe, &buffer[0], div, config, cb);	return 0;}static int simple_set_radio_freq(struct dvb_frontend *fe,				 struct analog_parameters *params){	struct tunertype *tun;	struct tuner_simple_priv *priv = fe->tuner_priv;	u8 buffer[4];	u16 div;	int rc, j;	struct tuner_params *t_params;	unsigned int freq = params->frequency;	tun = priv->tun;	for (j = tun->count-1; j > 0; j--)		if (tun->params[j].type == TUNER_PARAM_TYPE_RADIO)			break;	/* default t_params (j=0) will be used if desired type wasn't found */	t_params = &tun->params[j];	/* Select Radio 1st IF used */	switch (t_params->radio_if) {	case 0: /* 10.7 MHz */		freq += (unsigned int)(10.7*16000);		break;	case 1: /* 33.3 MHz */		freq += (unsigned int)(33.3*16000);		break;	case 2: /* 41.3 MHz */		freq += (unsigned int)(41.3*16000);		break;	default:		tuner_warn("Unsupported radio_if value %d\n",			   t_params->radio_if);		return 0;	}	/* Bandswitch byte */	simple_radio_bandswitch(fe, &buffer[0]);	buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) |		    TUNER_RATIO_SELECT_50; /* 50 kHz step */	/* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps	   freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) =	   freq * (1/800) */	div = (freq + 400) / 800;	if (t_params->cb_first_if_lower_freq && div < priv->last_div) {		buffer[0] = buffer[2];		buffer[1] = buffer[3];		buffer[2] = (div>>8) & 0x7f;		buffer[3] = div      & 0xff;	} else {		buffer[0] = (div>>8) & 0x7f;		buffer[1] = div      & 0xff;	}	tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n",	       buffer[0], buffer[1], buffer[2], buffer[3]);	priv->last_div = div;	if (t_params->has_tda9887) {		int config = 0;		struct v4l2_priv_tun_config tda9887_cfg;		tda9887_cfg.tuner = TUNER_TDA9887;		tda9887_cfg.priv = &config;		if (t_params->port1_active &&		    !t_params->port1_fm_high_sensitivity)			config |= TDA9887_PORT1_ACTIVE;		if (t_params->port2_active &&		    !t_params->port2_fm_high_sensitivity)			config |= TDA9887_PORT2_ACTIVE;		if (t_params->intercarrier_mode)			config |= TDA9887_INTERCARRIER;/*		if (t_params->port1_set_for_fm_mono)			config &= ~TDA9887_PORT1_ACTIVE;*/		if (t_params->fm_gain_normal)			config |= TDA9887_GAIN_NORMAL;		if (t_params->radio_if == 2)			config |= TDA9887_RIF_41_3;		i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,				    &tda9887_cfg);	}	rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);	if (4 != rc)		tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc);	return 0;}static int simple_set_params(struct dvb_frontend *fe,			     struct analog_parameters *params){	struct tuner_simple_priv *priv = fe->tuner_priv;	int ret = -EINVAL;	if (priv->i2c_props.adap == NULL)		return -EINVAL;	switch (params->mode) {	case V4L2_TUNER_RADIO:		ret = simple_set_radio_freq(fe, params);		priv->frequency = params->frequency * 125 / 2;		break;	case V4L2_TUNER_ANALOG_TV:	case V4L2_TUNER_DIGITAL_TV:		ret = simple_set_tv_freq(fe, params);		priv->frequency = params->frequency * 62500;		break;	}	priv->bandwidth = 0;	return ret;}static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf,			   const struct dvb_frontend_parameters *params){	struct tuner_simple_priv *priv = fe->tuner_priv;	switch (priv->type) {	case TUNER_PHILIPS_FMD1216ME_MK3:	case TUNER_PHILIPS_FMD1216MEX_MK3:		if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ &&		    params->frequency >= 158870000)			buf[3] |= 0x08;		break;	case TUNER_PHILIPS_TD1316:		/* determine band */		buf[3] |= (params->frequency < 161000000) ? 1 :			  (params->frequency < 444000000) ? 2 : 4;		/* setup PLL filter */		if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)			buf[3] |= 1 << 3;		break;	case TUNER_PHILIPS_TUV1236D:	case TUNER_PHILIPS_FCV1236D:	{		unsigned int new_rf;		if (dtv_input[priv->nr])			new_rf = dtv_input[priv->nr];		else			switch (params->u.vsb.modulation) {			case QAM_64:			case QAM_256:				new_rf = 1;				break;			case VSB_8:			default:				new_rf = 0;				break;			}		simple_set_rf_input(fe, &buf[2], &buf[3], new_rf);		break;	}	default:		break;	}}static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf,				const struct dvb_frontend_parameters *params){	/* This function returns the tuned frequency on success, 0 on error */	struct tuner_simple_priv *priv = fe->tuner_priv;	struct tunertype *tun = priv->tun;	static struct tuner_params *t_params;	u8 config, cb;	u32 div;	int ret;	unsigned frequency = params->frequency / 62500;	t_params = simple_tuner_params(fe, TUNER_PARAM_TYPE_DIGITAL);	ret = simple_config_lookup(fe, t_params, &frequency, &config, &cb);	if (ret < 0)		return 0; /* failure */	div = ((frequency + t_params->iffreq) * 62500 + offset +	       tun->stepsize/2) / tun->stepsize;	buf[0] = div >> 8;	buf[1] = div & 0xff;	buf[2] = config;	buf[3] = cb;	simple_set_dvb(fe, buf, params);	tuner_dbg("%s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",		  tun->name, div, buf[0], buf[1], buf[2], buf[3]);	/* calculate the frequency we set it to */	return (div * tun->stepsize) - t_params->iffreq;}static int simple_dvb_calc_regs(struct dvb_frontend *fe,				struct dvb_frontend_parameters *params,				u8 *buf, int buf_len){	struct tuner_simple_priv *priv = fe->tuner_priv;	u32 frequency;	if (buf_len < 5)		return -EINVAL;	frequency = simple_dvb_configure(fe, buf+1, params);	if (frequency == 0)		return -EINVAL;	buf[0] = priv->i2c_props.addr;	priv->frequency = frequency;	priv->bandwidth = (fe->ops.info.type == FE_OFDM) ?		params->u.ofdm.bandwidth : 0;	return 5;}static int simple_dvb_set_params(struct dvb_frontend *fe,				 struct dvb_frontend_parameters *params){	struct tuner_simple_priv *priv = fe->tuner_priv;	u32 prev_freq, prev_bw;	int ret;	u8 buf[5];	if (priv->i2c_props.adap == NULL)		return -EINVAL;	prev_freq = priv->frequency;	prev_bw   = priv->bandwidth;	ret = simple_dvb_calc_regs(fe, params, buf, 5);	if (ret != 5)		goto fail;	/* put analog demod in standby when tuning digital */	if (fe->ops.analog_ops.standby)		fe->ops.analog_ops.standby(fe);	if (fe->ops.i2c_gate_ctrl)		fe->ops.i2c_gate_ctrl(fe, 1);	/* buf[0] contains the i2c address, but *	 * we already have it in i2c_props.addr */	ret = tuner_i2c_xfer_send(&priv->i2c_props, buf+1, 4);	if (ret != 4)		goto fail;	return 0;fail:	/* calc_regs sets frequency and bandwidth. if we failed, unset them */	priv->frequency = prev_freq;	priv->bandwidth = prev_bw;	return ret;}static int simple_init(struct dvb_frontend *fe){	struct tuner_simple_priv *priv = fe->tuner_priv;	if (priv->i2c_props.adap == NULL)		return -EINVAL;	if (priv->tun->initdata) {		int ret;		if (fe->ops.i2c_gate_ctrl)			fe->ops.i2c_gate_ctrl(fe, 1);		ret = tuner_i2c_xfer_send(&priv->i2c_props,					  priv->tun->initdata + 1,					  priv->tun->initdata[0]);		if (ret != priv->tun->initdata[0])			return ret;	}	return 0;}static int simple_sleep(struct dvb_frontend *fe){	struct tuner_simple_priv *priv = fe->tuner_priv;	if (priv->i2c_props.adap == NULL)		return -EINVAL;	if (priv->tun->sleepdata) {		int ret;		if (fe->ops.i2c_gate_ctrl)			fe->ops.i2c_gate_ctrl(fe, 1);		ret = tuner_i2c_xfer_send(&priv->i2c_props,					  priv->tun->sleepdata + 1,					  priv->tun->sleepdata[0]);		if (ret != priv->tun->sleepdata[0])			return ret;	}	return 0;}static int simple_release(struct dvb_frontend *fe){	struct tuner_simple_priv *priv = fe->tuner_priv;	mutex_lock(&tuner_simple_list_mutex);	if (priv)		hybrid_tuner_release_state(priv);	mutex_unlock(&tuner_simple_list_mutex);	fe->tuner_priv = NULL;	return 0;}static int simple_get_frequency(struct dvb_frontend *fe, u32 *frequency){	struct tuner_simple_priv *priv = fe->tuner_priv;	*frequency = priv->frequency;	return 0;}static int simple_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth){	struct tuner_simple_priv *priv = fe->tuner_priv;	*bandwidth = priv->bandwidth;	return 0;}static struct dvb_tuner_ops simple_tuner_ops = {#if 0	.info = {		.name           = "tuner-simple",		.frequency_min  = ,		.frequency_max  = ,		.frequency_step = ,	},#endif	.init              = simple_init,	.sleep             = simple_sleep,	.set_analog_params = simple_set_params,	.set_params        = simple_dvb_set_params,	.calc_regs         = simple_dvb_calc_regs,	.release           = simple_release,	.get_frequency     = simple_get_frequency,	.get_bandwidth     = simple_get_bandwidth,	.get_status        = simple_get_status,	.get_rf_strength   = simple_get_rf_strength,};struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,					 struct i2c_adapter *i2c_adap,					 u8 i2c_addr,					 unsigned int type){	struct tuner_simple_priv *priv = NULL;	int instance;	if (type >= tuner_count) {		printk(KERN_WARNING "%s: invalid tuner type: %d (max: %d)\n",		       __func__, type, tuner_count-1);		return NULL;	}	/* If i2c_adap is set, check that the tuner is at the correct address.	 * Otherwise, if i2c_adap is NULL, the tuner will be programmed directly	 * by the digital demod via calc_regs.	 */	if (i2c_adap != NULL) {		u8 b[1];		struct i2c_msg msg = {			.addr = i2c_addr, .flags = I2C_M_RD,			.buf = b, .len = 1,		};		if (fe->ops.i2c_gate_ctrl)			fe->ops.i2c_gate_ctrl(fe, 1);		if (1 != i2c_transfer(i2c_adap, &msg, 1))			printk(KERN_WARNING "tuner-simple %d-%04x: "			       "unable to probe %s, proceeding anyway.",			       i2c_adapter_id(i2c_adap), i2c_addr,			       tuners[type].name);		if (fe->ops.i2c_gate_ctrl)			fe->ops.i2c_gate_ctrl(fe, 0);	}	mutex_lock(&tuner_simple_list_mutex);	instance = hybrid_tuner_request_state(struct tuner_simple_priv, priv,					      hybrid_tuner_instance_list,					      i2c_adap, i2c_addr,					      "tuner-simple");	switch (instance) {	case 0:		mutex_unlock(&tuner_simple_list_mutex);		return NULL;	case 1:		fe->tuner_priv = priv;		priv->type = type;		priv->tun  = &tuners[type];		priv->nr   = simple_devcount++;		break;	default:		fe->tuner_priv = priv;#if 0		/* caller didn't pass in a configuration last time		 * use current configuration, instead */		if (!priv->tun) {			priv->type = type;			priv->tun  = &tuners[type];		}#endif		break;	}	mutex_unlock(&tuner_simple_list_mutex);	memcpy(&fe->ops.tuner_ops, &simple_tuner_ops,	       sizeof(struct dvb_tuner_ops));	tuner_info("type set to %d (%s)\n", type, priv->tun->name);	if ((debug) || ((atv_input[priv->nr] > 0) ||			(dtv_input[priv->nr] > 0))) {		if (0 == atv_input[priv->nr])			tuner_info("tuner %d atv rf input will be "				   "autoselected\n", priv->nr);		else			tuner_info("tuner %d atv rf input will be "				   "set to input %d (insmod option)\n",				   priv->nr, atv_input[priv->nr]);		if (0 == dtv_input[priv->nr])			tuner_info("tuner %d dtv rf input will be "				   "autoselected\n", priv->nr);		else			tuner_info("tuner %d dtv rf input will be "				   "set to input %d (insmod option)\n",				   priv->nr, dtv_input[priv->nr]);	}	strlcpy(fe->ops.tuner_ops.info.name, priv->tun->name,		sizeof(fe->ops.tuner_ops.info.name));	return fe;}EXPORT_SYMBOL_GPL(simple_tuner_attach);MODULE_DESCRIPTION("Simple 4-control-bytes style tuner driver");MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");MODULE_LICENSE("GPL");/* * Overrides for Emacs so that we follow Linus's tabbing style. * --------------------------------------------------------------------------- * Local variables: * c-basic-offset: 8 * End: */

⌨️ 快捷键说明

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