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

📄 tuner-simple.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * i2c tv tuner chip device driver * controls all those simple 4-control-bytes style tuners. * * This "tuner-simple" module was split apart from the original "tuner" module. */#include <linux/delay.h>#include <linux/i2c.h>#include "compat.h"#include <linux/videodev2.h>#include <media/tuner.h>#include <media/v4l2-common.h>#include <media/tuner-types.h>#include "tuner-i2c.h"#include "tuner-simple.h"static int debug;module_param(debug, int, 0644);MODULE_PARM_DESC(debug, "enable verbose debug messages");#define TUNER_SIMPLE_MAX 64static unsigned int simple_devcount;static int offset;module_param(offset, int, 0664);MODULE_PARM_DESC(offset, "Allows to specify an offset for tuner");static unsigned int atv_input[TUNER_SIMPLE_MAX] = \			{ [0 ... (TUNER_SIMPLE_MAX-1)] = 0 };static unsigned int dtv_input[TUNER_SIMPLE_MAX] = \			{ [0 ... (TUNER_SIMPLE_MAX-1)] = 0 };module_param_array(atv_input, int, NULL, 0644);module_param_array(dtv_input, int, NULL, 0644);MODULE_PARM_DESC(atv_input, "specify atv rf input, 0 for autoselect");MODULE_PARM_DESC(dtv_input, "specify dtv rf input, 0 for autoselect");/* ---------------------------------------------------------------------- *//* tv standard selection for Temic 4046 FM5   this value takes the low bits of control byte 2   from datasheet Rev.01, Feb.00     standard     BG      I       L       L2      D     picture IF   38.9    38.9    38.9    33.95   38.9     sound 1      33.4    32.9    32.4    40.45   32.4     sound 2      33.16     NICAM        33.05   32.348  33.05           33.05 */#define TEMIC_SET_PAL_I         0x05#define TEMIC_SET_PAL_DK        0x09#define TEMIC_SET_PAL_L         0x0a /* SECAM ? */#define TEMIC_SET_PAL_L2        0x0b /* change IF ! */#define TEMIC_SET_PAL_BG        0x0c/* tv tuner system standard selection for Philips FQ1216ME   this value takes the low bits of control byte 2   from datasheet "1999 Nov 16" (supersedes "1999 Mar 23")     standard 		BG	DK	I	L	L`     picture carrier	38.90	38.90	38.90	38.90	33.95     colour		34.47	34.47	34.47	34.47	38.38     sound 1		33.40	32.40	32.90	32.40	40.45     sound 2		33.16	-	-	-	-     NICAM		33.05	33.05	32.35	33.05	39.80 */#define PHILIPS_SET_PAL_I	0x01 /* Bit 2 always zero !*/#define PHILIPS_SET_PAL_BGDK	0x09#define PHILIPS_SET_PAL_L2	0x0a#define PHILIPS_SET_PAL_L	0x0b/* system switching for Philips FI1216MF MK2   from datasheet "1996 Jul 09",    standard         BG     L      L'    picture carrier  38.90  38.90  33.95    colour	     34.47  34.37  38.38    sound 1          33.40  32.40  40.45    sound 2          33.16  -      -    NICAM            33.05  33.05  39.80 */#define PHILIPS_MF_SET_STD_BG	0x01 /* Bit 2 must be zero, Bit 3 is system output */#define PHILIPS_MF_SET_STD_L	0x03 /* Used on Secam France */#define PHILIPS_MF_SET_STD_LC	0x02 /* Used on SECAM L' *//* Control byte */#define TUNER_RATIO_MASK        0x06 /* Bit cb1:cb2 */#define TUNER_RATIO_SELECT_50   0x00#define TUNER_RATIO_SELECT_32   0x02#define TUNER_RATIO_SELECT_166  0x04#define TUNER_RATIO_SELECT_62   0x06#define TUNER_CHARGE_PUMP       0x40  /* Bit cb6 *//* Status byte */#define TUNER_POR	  0x80#define TUNER_FL          0x40#define TUNER_MODE        0x38#define TUNER_AFC         0x07#define TUNER_SIGNAL      0x07#define TUNER_STEREO      0x10#define TUNER_PLL_LOCKED   0x40#define TUNER_STEREO_MK3   0x04static DEFINE_MUTEX(tuner_simple_list_mutex);static LIST_HEAD(hybrid_tuner_instance_list);struct tuner_simple_priv {	unsigned int nr;	u16 last_div;	struct tuner_i2c_props i2c_props;	struct list_head hybrid_tuner_instance_list;	unsigned int type;	struct tunertype *tun;	u32 frequency;	u32 bandwidth;};/* ---------------------------------------------------------------------- */static int tuner_read_status(struct dvb_frontend *fe){	struct tuner_simple_priv *priv = fe->tuner_priv;	unsigned char byte;	if (1 != tuner_i2c_xfer_recv(&priv->i2c_props, &byte, 1))		return 0;	return byte;}static inline int tuner_signal(const int status){	return (status & TUNER_SIGNAL) << 13;}static inline int tuner_stereo(const int type, const int status){	switch (type) {	case TUNER_PHILIPS_FM1216ME_MK3:	case TUNER_PHILIPS_FM1236_MK3:	case TUNER_PHILIPS_FM1256_IH3:	case TUNER_LG_NTSC_TAPE:	case TUNER_TCL_MF02GIP_5N:		return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);	default:		return status & TUNER_STEREO;	}}static inline int tuner_islocked(const int status){	return (status & TUNER_FL);}static inline int tuner_afcstatus(const int status){	return (status & TUNER_AFC) - 2;}#if 0 /* unused */static inline int tuner_mode(const int status){	return (status & TUNER_MODE) >> 3;}#endifstatic int simple_get_status(struct dvb_frontend *fe, u32 *status){	struct tuner_simple_priv *priv = fe->tuner_priv;	int tuner_status;	if (priv->i2c_props.adap == NULL)		return -EINVAL;	tuner_status = tuner_read_status(fe);	*status = 0;	if (tuner_islocked(tuner_status))		*status = TUNER_STATUS_LOCKED;	if (tuner_stereo(priv->type, tuner_status))		*status |= TUNER_STATUS_STEREO;	tuner_dbg("AFC Status: %d\n", tuner_afcstatus(tuner_status));	return 0;}static int simple_get_rf_strength(struct dvb_frontend *fe, u16 *strength){	struct tuner_simple_priv *priv = fe->tuner_priv;	int signal;	if (priv->i2c_props.adap == NULL)		return -EINVAL;	signal = tuner_signal(tuner_read_status(fe));	*strength = signal;	tuner_dbg("Signal strength: %d\n", signal);	return 0;}/* ---------------------------------------------------------------------- */static inline char *tuner_param_name(enum param_type type){	char *name;	switch (type) {	case TUNER_PARAM_TYPE_RADIO:		name = "radio";		break;	case TUNER_PARAM_TYPE_PAL:		name = "pal";		break;	case TUNER_PARAM_TYPE_SECAM:		name = "secam";		break;	case TUNER_PARAM_TYPE_NTSC:		name = "ntsc";		break;	case TUNER_PARAM_TYPE_DIGITAL:		name = "digital";		break;	default:		name = "unknown";		break;	}	return name;}static struct tuner_params *simple_tuner_params(struct dvb_frontend *fe,						enum param_type desired_type){	struct tuner_simple_priv *priv = fe->tuner_priv;	struct tunertype *tun = priv->tun;	int i;	for (i = 0; i < tun->count; i++)		if (desired_type == tun->params[i].type)			break;	/* use default tuner params if desired_type not available */	if (i == tun->count) {		tuner_dbg("desired params (%s) undefined for tuner %d\n",			  tuner_param_name(desired_type), priv->type);		i = 0;	}	tuner_dbg("using tuner params #%d (%s)\n", i,		  tuner_param_name(tun->params[i].type));	return &tun->params[i];}static int simple_config_lookup(struct dvb_frontend *fe,				struct tuner_params *t_params,				unsigned *frequency, u8 *config, u8 *cb){	struct tuner_simple_priv *priv = fe->tuner_priv;	int i;	for (i = 0; i < t_params->count; i++) {		if (*frequency > t_params->ranges[i].limit)			continue;		break;	}	if (i == t_params->count) {		tuner_dbg("frequency out of range (%d > %d)\n",			  *frequency, t_params->ranges[i - 1].limit);		*frequency = t_params->ranges[--i].limit;	}	*config = t_params->ranges[i].config;	*cb     = t_params->ranges[i].cb;	tuner_dbg("freq = %d.%02d (%d), range = %d, "		  "config = 0x%02x, cb = 0x%02x\n",		  *frequency / 16, *frequency % 16 * 100 / 16, *frequency,		  i, *config, *cb);	return i;}/* ---------------------------------------------------------------------- */static void simple_set_rf_input(struct dvb_frontend *fe,				u8 *config, u8 *cb, unsigned int rf){	struct tuner_simple_priv *priv = fe->tuner_priv;	switch (priv->type) {	case TUNER_PHILIPS_TUV1236D:		switch (rf) {		case 1:			*cb |= 0x08;			break;		default:			*cb &= ~0x08;			break;		}		break;	case TUNER_PHILIPS_FCV1236D:		switch (rf) {		case 1:			*cb |= 0x01;			break;		default:			*cb &= ~0x01;			break;		}		break;	default:		break;	}}static int simple_std_setup(struct dvb_frontend *fe,			    struct analog_parameters *params,			    u8 *config, u8 *cb){	struct tuner_simple_priv *priv = fe->tuner_priv;	u8 tuneraddr;	int rc;	/* tv norm specific stuff for multi-norm tuners */	switch (priv->type) {	case TUNER_PHILIPS_SECAM: /* FI1216MF */		/* 0x01 -> ??? no change ??? */		/* 0x02 -> PAL BDGHI / SECAM L */		/* 0x04 -> ??? PAL others / SECAM others ??? */		*cb &= ~0x03;		if (params->std & V4L2_STD_SECAM_L)			/* also valid for V4L2_STD_SECAM */			*cb |= PHILIPS_MF_SET_STD_L;		else if (params->std & V4L2_STD_SECAM_LC)			*cb |= PHILIPS_MF_SET_STD_LC;		else /* V4L2_STD_B|V4L2_STD_GH */			*cb |= PHILIPS_MF_SET_STD_BG;		break;	case TUNER_TEMIC_4046FM5:		*cb &= ~0x0f;		if (params->std & V4L2_STD_PAL_BG) {			*cb |= TEMIC_SET_PAL_BG;		} else if (params->std & V4L2_STD_PAL_I) {			*cb |= TEMIC_SET_PAL_I;		} else if (params->std & V4L2_STD_PAL_DK) {			*cb |= TEMIC_SET_PAL_DK;		} else if (params->std & V4L2_STD_SECAM_L) {			*cb |= TEMIC_SET_PAL_L;		}		break;	case TUNER_PHILIPS_FQ1216ME:		*cb &= ~0x0f;		if (params->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) {			*cb |= PHILIPS_SET_PAL_BGDK;		} else if (params->std & V4L2_STD_PAL_I) {			*cb |= PHILIPS_SET_PAL_I;		} else if (params->std & V4L2_STD_SECAM_L) {			*cb |= PHILIPS_SET_PAL_L;		}		break;	case TUNER_PHILIPS_FCV1236D:		/* 0x00 -> ATSC antenna input 1 */		/* 0x01 -> ATSC antenna input 2 */		/* 0x02 -> NTSC antenna input 1 */		/* 0x03 -> NTSC antenna input 2 */		*cb &= ~0x03;		if (!(params->std & V4L2_STD_ATSC))			*cb |= 2;		break;	case TUNER_MICROTUNE_4042FI5:		/* Set the charge pump for fast tuning */		*config |= TUNER_CHARGE_PUMP;		break;	case TUNER_PHILIPS_TUV1236D:	{		/* 0x40 -> ATSC antenna input 1 */		/* 0x48 -> ATSC antenna input 2 */		/* 0x00 -> NTSC antenna input 1 */		/* 0x08 -> NTSC antenna input 2 */		u8 buffer[4] = { 0x14, 0x00, 0x17, 0x00};		*cb &= ~0x40;		if (params->std & V4L2_STD_ATSC) {			*cb |= 0x40;			buffer[1] = 0x04;		}		/* set to the correct mode (analog or digital) */		tuneraddr = priv->i2c_props.addr;		priv->i2c_props.addr = 0x0a;		rc = tuner_i2c_xfer_send(&priv->i2c_props, &buffer[0], 2);		if (2 != rc)			tuner_warn("i2c i/o error: rc == %d "				   "(should be 2)\n", rc);		rc = tuner_i2c_xfer_send(&priv->i2c_props, &buffer[2], 2);		if (2 != rc)			tuner_warn("i2c i/o error: rc == %d "				   "(should be 2)\n", rc);		priv->i2c_props.addr = tuneraddr;		break;	}	}	if (atv_input[priv->nr])		simple_set_rf_input(fe, config, cb, atv_input[priv->nr]);	return 0;}static int simple_post_tune(struct dvb_frontend *fe, u8 *buffer,			    u16 div, u8 config, u8 cb){	struct tuner_simple_priv *priv = fe->tuner_priv;	int rc;	switch (priv->type) {	case TUNER_LG_TDVS_H06XF:		/* Set the Auxiliary Byte. */#if 0		buffer[2] &= ~0x20;		buffer[2] |= 0x18;		buffer[3] = 0x20;		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);#else		buffer[0] = buffer[2];		buffer[0] &= ~0x20;		buffer[0] |= 0x18;		buffer[1] = 0x20;		tuner_dbg("tv 0x%02x 0x%02x\n", buffer[0], buffer[1]);		rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 2);		if (2 != rc)			tuner_warn("i2c i/o error: rc == %d "				   "(should be 2)\n", rc);#endif		break;	case TUNER_MICROTUNE_4042FI5:	{		/* FIXME - this may also work for other tuners */		unsigned long timeout = jiffies + msecs_to_jiffies(1);		u8 status_byte = 0;		/* Wait until the PLL locks */		for (;;) {			if (time_after(jiffies, timeout))				return 0;			rc = tuner_i2c_xfer_recv(&priv->i2c_props,						 &status_byte, 1);			if (1 != rc) {				tuner_warn("i2c i/o read error: rc == %d "					   "(should be 1)\n", rc);				break;			}			if (status_byte & TUNER_PLL_LOCKED)				break;			udelay(10);		}		/* Set the charge pump for optimized phase noise figure */		config &= ~TUNER_CHARGE_PUMP;		buffer[0] = (div>>8) & 0x7f;		buffer[1] = div      & 0xff;		buffer[2] = config;		buffer[3] = cb;		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);		break;	}	}	return 0;}static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer){	struct tuner_simple_priv *priv = fe->tuner_priv;	switch (priv->type) {	case TUNER_TENA_9533_DI:	case TUNER_YMEC_TVF_5533MF:		tuner_dbg("This tuner doesn't have FM. "			  "Most cards have a TEA5767 for FM\n");		return 0;	case TUNER_PHILIPS_FM1216ME_MK3:	case TUNER_PHILIPS_FM1236_MK3:	case TUNER_PHILIPS_FMD1216ME_MK3:	case TUNER_PHILIPS_FMD1216MEX_MK3:	case TUNER_LG_NTSC_TAPE:	case TUNER_PHILIPS_FM1256_IH3:	case TUNER_TCL_MF02GIP_5N:		buffer[3] = 0x19;		break;	case TUNER_TNF_5335MF:		buffer[3] = 0x11;		break;	case TUNER_LG_PAL_FM:		buffer[3] = 0xa5;		break;	case TUNER_THOMSON_DTT761X:		buffer[3] = 0x39;		break;	case TUNER_MICROTUNE_4049FM5:	default:		buffer[3] = 0xa4;		break;	}	return 0;}/* ---------------------------------------------------------------------- */static int simple_set_tv_freq(struct dvb_frontend *fe,			      struct analog_parameters *params){	struct tuner_simple_priv *priv = fe->tuner_priv;	u8 config, cb;	u16 div;	struct tunertype *tun;	u8 buffer[4];	int rc, IFPCoff, i;	enum param_type desired_type;	struct tuner_params *t_params;	tun = priv->tun;	/* IFPCoff = Video Intermediate Frequency - Vif:		940  =16*58.75  NTSC/J (Japan)		732  =16*45.75  M/N STD		704  =16*44     ATSC (at DVB code)		632  =16*39.50  I U.K.		622.4=16*38.90  B/G D/K I, L STD		592  =16*37.00  D China		590  =16.36.875 B Australia		543.2=16*33.95  L' STD		171.2=16*10.70  FM Radio (at set_radio_freq)	*/	if (params->std == V4L2_STD_NTSC_M_JP) {

⌨️ 快捷键说明

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