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

📄 s5h1420.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
static void s5h1420_reset(struct s5h1420_state* state){	s5h1420_writereg (state, 0x01, 0x08);	s5h1420_writereg (state, 0x01, 0x00);	udelay(10);}static void s5h1420_setsymbolrate(struct s5h1420_state* state,				  struct dvb_frontend_parameters *p){	u64 val;	val = ((u64) p->u.qpsk.symbol_rate / 1000ULL) * (1ULL<<24);	if (p->u.qpsk.symbol_rate <= 21000000) {		val *= 2;	}	do_div(val, (state->fclk / 1000));	s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) & 0x7f);	s5h1420_writereg(state, 0x11, val >> 16);	s5h1420_writereg(state, 0x12, val >> 8);	s5h1420_writereg(state, 0x13, val & 0xff);	s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) | 0x80);}static u32 s5h1420_getsymbolrate(struct s5h1420_state* state){	u64 val = 0;	int sampling = 2;	if (s5h1420_readreg(state, 0x05) & 0x2)		sampling = 1;	s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) | 0x08);	val  = s5h1420_readreg(state, 0x11) << 16;	val |= s5h1420_readreg(state, 0x12) << 8;	val |= s5h1420_readreg(state, 0x13);	s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) & 0xf7);	val *= (state->fclk / 1000ULL);	do_div(val, ((1<<24) * sampling));	return (u32) (val * 1000ULL);}static void s5h1420_setfreqoffset(struct s5h1420_state* state, int freqoffset){	int val;	/* remember freqoffset is in kHz, but the chip wants the offset in Hz, so	 * divide fclk by 1000000 to get the correct value. */	val = -(int) ((freqoffset * (1<<24)) / (state->fclk / 1000000));	s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) & 0xbf);	s5h1420_writereg(state, 0x0e, val >> 16);	s5h1420_writereg(state, 0x0f, val >> 8);	s5h1420_writereg(state, 0x10, val & 0xff);	s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) | 0x40);}static int s5h1420_getfreqoffset(struct s5h1420_state* state){	int val;	s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) | 0x08);	val  = s5h1420_readreg(state, 0x0e) << 16;	val |= s5h1420_readreg(state, 0x0f) << 8;	val |= s5h1420_readreg(state, 0x10);	s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) & 0xf7);	if (val & 0x800000)		val |= 0xff000000;	/* remember freqoffset is in kHz, but the chip wants the offset in Hz, so	 * divide fclk by 1000000 to get the correct value. */	val = (((-val) * (state->fclk/1000000)) / (1<<24));	return val;}static void s5h1420_setfec_inversion(struct s5h1420_state* state,				     struct dvb_frontend_parameters *p){	u8 inversion = 0;	if (p->inversion == INVERSION_OFF) {		inversion = state->config->invert ? 0x08 : 0;	} else if (p->inversion == INVERSION_ON) {		inversion = state->config->invert ? 0 : 0x08;	}	if ((p->u.qpsk.fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) {		s5h1420_writereg(state, 0x30, 0x3f);		s5h1420_writereg(state, 0x31, 0x00 | inversion);	} else {		switch(p->u.qpsk.fec_inner) {		case FEC_1_2:			s5h1420_writereg(state, 0x30, 0x01);			s5h1420_writereg(state, 0x31, 0x10 | inversion);			break;		case FEC_2_3:			s5h1420_writereg(state, 0x30, 0x02);			s5h1420_writereg(state, 0x31, 0x11 | inversion);			break;		case FEC_3_4:			s5h1420_writereg(state, 0x30, 0x04);		        s5h1420_writereg(state, 0x31, 0x12 | inversion);		        break;		case FEC_5_6:			s5h1420_writereg(state, 0x30, 0x08);			s5h1420_writereg(state, 0x31, 0x13 | inversion);			break;		case FEC_6_7:			s5h1420_writereg(state, 0x30, 0x10);			s5h1420_writereg(state, 0x31, 0x14 | inversion);			break;		case FEC_7_8:			s5h1420_writereg(state, 0x30, 0x20);			s5h1420_writereg(state, 0x31, 0x15 | inversion);			break;		default:			return;		}	}}static fe_code_rate_t s5h1420_getfec(struct s5h1420_state* state){	switch(s5h1420_readreg(state, 0x32) & 0x07) {	case 0:		return FEC_1_2;	case 1:		return FEC_2_3;	case 2:		return FEC_3_4;	case 3:		return FEC_5_6;	case 4:		return FEC_6_7;	case 5:		return FEC_7_8;	}	return FEC_NONE;}static fe_spectral_inversion_t s5h1420_getinversion(struct s5h1420_state* state){	if (s5h1420_readreg(state, 0x32) & 0x08)		return INVERSION_ON;	return INVERSION_OFF;}static int s5h1420_set_frontend(struct dvb_frontend* fe,				struct dvb_frontend_parameters *p){	struct s5h1420_state* state = fe->demodulator_priv;	int frequency_delta;	struct dvb_frontend_tune_settings fesettings;	u32 tmp;	/* check if we should do a fast-tune */	memcpy(&fesettings.parameters, p, sizeof(struct dvb_frontend_parameters));	s5h1420_get_tune_settings(fe, &fesettings);	frequency_delta = p->frequency - state->tunedfreq;	if ((frequency_delta > -fesettings.max_drift) &&	    (frequency_delta < fesettings.max_drift) &&	    (frequency_delta != 0) &&	    (state->fec_inner == p->u.qpsk.fec_inner) &&	    (state->symbol_rate == p->u.qpsk.symbol_rate)) {		if (state->config->pll_set) {			s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);			state->config->pll_set(fe, p, &tmp);			s5h1420_setfreqoffset(state, p->frequency - tmp);		}		return 0;	}	/* first of all, software reset */	s5h1420_reset(state);	/* set s5h1420 fclk PLL according to desired symbol rate */	if (p->u.qpsk.symbol_rate > 28000000) {		state->fclk = 88000000;		s5h1420_writereg(state, 0x03, 0x50);		s5h1420_writereg(state, 0x04, 0x40);		s5h1420_writereg(state, 0x05, 0xae);	} else if (p->u.qpsk.symbol_rate > 21000000) {		state->fclk = 59000000;		s5h1420_writereg(state, 0x03, 0x33);		s5h1420_writereg(state, 0x04, 0x40);		s5h1420_writereg(state, 0x05, 0xae);	} else {		state->fclk = 88000000;		s5h1420_writereg(state, 0x03, 0x50);		s5h1420_writereg(state, 0x04, 0x40);		s5h1420_writereg(state, 0x05, 0xac);	}	/* set misc registers */	s5h1420_writereg(state, 0x02, 0x00);	s5h1420_writereg(state, 0x06, 0x00);	s5h1420_writereg(state, 0x07, 0xb0);	s5h1420_writereg(state, 0x0a, 0xe7);	s5h1420_writereg(state, 0x0b, 0x78);	s5h1420_writereg(state, 0x0c, 0x48);	s5h1420_writereg(state, 0x0d, 0x6b);	s5h1420_writereg(state, 0x2e, 0x8e);	s5h1420_writereg(state, 0x35, 0x33);	s5h1420_writereg(state, 0x38, 0x01);	s5h1420_writereg(state, 0x39, 0x7d);	s5h1420_writereg(state, 0x3a, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32));	s5h1420_writereg(state, 0x3c, 0x00);	s5h1420_writereg(state, 0x45, 0x61);	s5h1420_writereg(state, 0x46, 0x1d);	/* start QPSK */	s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) | 1);	/* set tuner PLL */	if (state->config->pll_set) {		s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);		state->config->pll_set(fe, p, &tmp);		s5h1420_setfreqoffset(state, 0);	}	/* set the reset of the parameters */	s5h1420_setsymbolrate(state, p);	s5h1420_setfec_inversion(state, p);	state->fec_inner = p->u.qpsk.fec_inner;	state->symbol_rate = p->u.qpsk.symbol_rate;	state->postlocked = 0;	state->tunedfreq = p->frequency;	return 0;}static int s5h1420_get_frontend(struct dvb_frontend* fe,				struct dvb_frontend_parameters *p){	struct s5h1420_state* state = fe->demodulator_priv;	p->frequency = state->tunedfreq + s5h1420_getfreqoffset(state);	p->inversion = s5h1420_getinversion(state);	p->u.qpsk.symbol_rate = s5h1420_getsymbolrate(state);	p->u.qpsk.fec_inner = s5h1420_getfec(state);	return 0;}static int s5h1420_get_tune_settings(struct dvb_frontend* fe,				     struct dvb_frontend_tune_settings* fesettings){	if (fesettings->parameters.u.qpsk.symbol_rate > 20000000) {		fesettings->min_delay_ms = 50;		fesettings->step_size = 2000;		fesettings->max_drift = 8000;	} else if (fesettings->parameters.u.qpsk.symbol_rate > 12000000) {		fesettings->min_delay_ms = 100;		fesettings->step_size = 1500;		fesettings->max_drift = 9000;	} else if (fesettings->parameters.u.qpsk.symbol_rate > 8000000) {		fesettings->min_delay_ms = 100;		fesettings->step_size = 1000;		fesettings->max_drift = 8000;	} else if (fesettings->parameters.u.qpsk.symbol_rate > 4000000) {		fesettings->min_delay_ms = 100;		fesettings->step_size = 500;		fesettings->max_drift = 7000;	} else if (fesettings->parameters.u.qpsk.symbol_rate > 2000000) {		fesettings->min_delay_ms = 200;		fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000);		fesettings->max_drift = 14 * fesettings->step_size;	} else {		fesettings->min_delay_ms = 200;		fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000);		fesettings->max_drift = 18 * fesettings->step_size;	}	return 0;}static int s5h1420_init (struct dvb_frontend* fe){	struct s5h1420_state* state = fe->demodulator_priv;	/* disable power down and do reset */	s5h1420_writereg(state, 0x02, 0x10);	msleep(10);	s5h1420_reset(state);	/* init PLL */	if (state->config->pll_init) {		s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);		state->config->pll_init(fe);		s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe);	}	return 0;}static int s5h1420_sleep(struct dvb_frontend* fe){	struct s5h1420_state* state = fe->demodulator_priv;	return s5h1420_writereg(state, 0x02, 0x12);}static void s5h1420_release(struct dvb_frontend* fe){	struct s5h1420_state* state = fe->demodulator_priv;	kfree(state);}static struct dvb_frontend_ops s5h1420_ops;struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,				    struct i2c_adapter* i2c){	struct s5h1420_state* state = NULL;	u8 identity;	/* allocate memory for the internal state */	state = kmalloc(sizeof(struct s5h1420_state), GFP_KERNEL);	if (state == NULL)		goto error;	/* setup the state */	state->config = config;	state->i2c = i2c;	memcpy(&state->ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops));	state->postlocked = 0;	state->fclk = 88000000;	state->tunedfreq = 0;	state->fec_inner = FEC_NONE;	state->symbol_rate = 0;	/* check if the demod is there + identify it */	identity = s5h1420_readreg(state, 0x00);	if (identity != 0x03)		goto error;	/* create dvb_frontend */	state->frontend.ops = &state->ops;	state->frontend.demodulator_priv = state;	return &state->frontend;error:	kfree(state);	return NULL;}static struct dvb_frontend_ops s5h1420_ops = {	.info = {		.name     = "Samsung S5H1420 DVB-S",		.type     = FE_QPSK,		.frequency_min    = 950000,		.frequency_max    = 2150000,		.frequency_stepsize = 125,     /* kHz for QPSK frontends */		.frequency_tolerance  = 29500,		.symbol_rate_min  = 1000000,		.symbol_rate_max  = 45000000,		/*  .symbol_rate_tolerance  = ???,*/		.caps = FE_CAN_INVERSION_AUTO |		FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |		FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |		FE_CAN_QPSK	},	.release = s5h1420_release,	.init = s5h1420_init,	.sleep = s5h1420_sleep,	.set_frontend = s5h1420_set_frontend,	.get_frontend = s5h1420_get_frontend,	.get_tune_settings = s5h1420_get_tune_settings,	.read_status = s5h1420_read_status,	.read_ber = s5h1420_read_ber,	.read_signal_strength = s5h1420_read_signal_strength,	.read_ucblocks = s5h1420_read_ucblocks,	.diseqc_send_master_cmd = s5h1420_send_master_cmd,	.diseqc_recv_slave_reply = s5h1420_recv_slave_reply,	.diseqc_send_burst = s5h1420_send_burst,	.set_tone = s5h1420_set_tone,	.set_voltage = s5h1420_set_voltage,};module_param(debug, int, 0644);MODULE_DESCRIPTION("Samsung S5H1420 DVB-S Demodulator driver");MODULE_AUTHOR("Andrew de Quincey");MODULE_LICENSE("GPL");EXPORT_SYMBOL(s5h1420_attach);

⌨️ 快捷键说明

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