| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * Frontend driver for mobile DVB-T demodulator DiBcom 3000P/M-C | 
 | 3 |  * DiBcom (http://www.dibcom.fr/) | 
 | 4 |  * | 
 | 5 |  * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) | 
 | 6 |  * | 
 | 7 |  * based on GPL code from DiBCom, which has | 
 | 8 |  * | 
 | 9 |  * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr) | 
 | 10 |  * | 
 | 11 |  *	This program is free software; you can redistribute it and/or | 
 | 12 |  *	modify it under the terms of the GNU General Public License as | 
 | 13 |  *	published by the Free Software Foundation, version 2. | 
 | 14 |  * | 
 | 15 |  * Acknowledgements | 
 | 16 |  * | 
 | 17 |  *  Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver | 
 | 18 |  *  sources, on which this driver (and the dvb-dibusb) are based. | 
 | 19 |  * | 
 | 20 |  * see Documentation/dvb/README.dibusb for more information | 
 | 21 |  * | 
 | 22 |  */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 23 | #include <linux/kernel.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 24 | #include <linux/module.h> | 
 | 25 | #include <linux/moduleparam.h> | 
 | 26 | #include <linux/init.h> | 
 | 27 | #include <linux/delay.h> | 
| Tim Schmielau | 4e57b68 | 2005-10-30 15:03:48 -0800 | [diff] [blame] | 28 | #include <linux/string.h> | 
 | 29 | #include <linux/slab.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 30 |  | 
 | 31 | #include "dib3000-common.h" | 
 | 32 | #include "dib3000mc_priv.h" | 
 | 33 | #include "dib3000.h" | 
 | 34 |  | 
 | 35 | /* Version information */ | 
 | 36 | #define DRIVER_VERSION "0.1" | 
 | 37 | #define DRIVER_DESC "DiBcom 3000M-C DVB-T demodulator" | 
 | 38 | #define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de" | 
 | 39 |  | 
 | 40 | #ifdef CONFIG_DVB_DIBCOM_DEBUG | 
 | 41 | static int debug; | 
 | 42 | module_param(debug, int, 0644); | 
 | 43 | MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe,16=stat (|-able))."); | 
 | 44 | #endif | 
 | 45 | #define deb_info(args...) dprintk(0x01,args) | 
 | 46 | #define deb_xfer(args...) dprintk(0x02,args) | 
 | 47 | #define deb_setf(args...) dprintk(0x04,args) | 
 | 48 | #define deb_getf(args...) dprintk(0x08,args) | 
 | 49 | #define deb_stat(args...) dprintk(0x10,args) | 
 | 50 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 51 | static int dib3000mc_set_impulse_noise(struct dib3000_state * state, int mode, | 
 | 52 | 	fe_transmit_mode_t transmission_mode, fe_bandwidth_t bandwidth) | 
 | 53 | { | 
 | 54 | 	switch (transmission_mode) { | 
 | 55 | 		case TRANSMISSION_MODE_2K: | 
 | 56 | 			wr_foreach(dib3000mc_reg_fft,dib3000mc_fft_modes[0]); | 
 | 57 | 			break; | 
 | 58 | 		case TRANSMISSION_MODE_8K: | 
 | 59 | 			wr_foreach(dib3000mc_reg_fft,dib3000mc_fft_modes[1]); | 
 | 60 | 			break; | 
 | 61 | 		default: | 
 | 62 | 			break; | 
 | 63 | 	} | 
 | 64 |  | 
 | 65 | 	switch (bandwidth) { | 
 | 66 | /*		case BANDWIDTH_5_MHZ: | 
 | 67 | 			wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[0]); | 
 | 68 | 			break; */ | 
 | 69 | 		case BANDWIDTH_6_MHZ: | 
 | 70 | 			wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[1]); | 
 | 71 | 			break; | 
 | 72 | 		case BANDWIDTH_7_MHZ: | 
 | 73 | 			wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[2]); | 
 | 74 | 			break; | 
 | 75 | 		case BANDWIDTH_8_MHZ: | 
 | 76 | 			wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[3]); | 
 | 77 | 			break; | 
 | 78 | 		default: | 
 | 79 | 			break; | 
 | 80 | 	} | 
 | 81 |  | 
 | 82 | 	switch (mode) { | 
 | 83 | 		case 0: /* no impulse */ /* fall through */ | 
 | 84 | 			wr_foreach(dib3000mc_reg_imp_noise_ctl,dib3000mc_imp_noise_ctl[0]); | 
 | 85 | 			break; | 
 | 86 | 		case 1: /* new algo */ | 
 | 87 | 			wr_foreach(dib3000mc_reg_imp_noise_ctl,dib3000mc_imp_noise_ctl[1]); | 
 | 88 | 			set_or(DIB3000MC_REG_IMP_NOISE_55,DIB3000MC_IMP_NEW_ALGO(0)); /* gives 1<<10 */ | 
 | 89 | 			break; | 
 | 90 | 		default: /* old algo */ | 
 | 91 | 			wr_foreach(dib3000mc_reg_imp_noise_ctl,dib3000mc_imp_noise_ctl[3]); | 
 | 92 | 			break; | 
 | 93 | 	} | 
 | 94 | 	return 0; | 
 | 95 | } | 
 | 96 |  | 
 | 97 | static int dib3000mc_set_timing(struct dib3000_state *state, int upd_offset, | 
 | 98 | 		fe_transmit_mode_t fft, fe_bandwidth_t bw) | 
 | 99 | { | 
 | 100 | 	u16 timf_msb,timf_lsb; | 
 | 101 | 	s32 tim_offset,tim_sgn; | 
 | 102 | 	u64 comp1,comp2,comp=0; | 
 | 103 |  | 
 | 104 | 	switch (bw) { | 
 | 105 | 		case BANDWIDTH_8_MHZ: comp = DIB3000MC_CLOCK_REF*8; break; | 
 | 106 | 		case BANDWIDTH_7_MHZ: comp = DIB3000MC_CLOCK_REF*7; break; | 
 | 107 | 		case BANDWIDTH_6_MHZ: comp = DIB3000MC_CLOCK_REF*6; break; | 
 | 108 | 		default: err("unknown bandwidth (%d)",bw); break; | 
 | 109 | 	} | 
 | 110 | 	timf_msb = (comp >> 16) & 0xff; | 
 | 111 | 	timf_lsb = (comp & 0xffff); | 
 | 112 |  | 
 | 113 | 	// Update the timing offset ; | 
 | 114 | 	if (upd_offset > 0) { | 
 | 115 | 		if (!state->timing_offset_comp_done) { | 
 | 116 | 			msleep(200); | 
 | 117 | 			state->timing_offset_comp_done = 1; | 
 | 118 | 		} | 
 | 119 | 		tim_offset = rd(DIB3000MC_REG_TIMING_OFFS_MSB); | 
 | 120 | 		if ((tim_offset & 0x2000) == 0x2000) | 
 | 121 | 			tim_offset |= 0xC000; | 
 | 122 | 		if (fft == TRANSMISSION_MODE_2K) | 
 | 123 | 			tim_offset <<= 2; | 
 | 124 | 		state->timing_offset += tim_offset; | 
 | 125 | 	} | 
 | 126 |  | 
 | 127 | 	tim_offset = state->timing_offset; | 
 | 128 | 	if (tim_offset < 0) { | 
 | 129 | 		tim_sgn = 1; | 
 | 130 | 		tim_offset = -tim_offset; | 
 | 131 | 	} else | 
 | 132 | 		tim_sgn = 0; | 
 | 133 |  | 
 | 134 | 	comp1 =  (u32)tim_offset * (u32)timf_lsb ; | 
 | 135 | 	comp2 =  (u32)tim_offset * (u32)timf_msb ; | 
 | 136 | 	comp  = ((comp1 >> 16) + comp2) >> 7; | 
 | 137 |  | 
 | 138 | 	if (tim_sgn == 0) | 
 | 139 | 		comp = (u32)(timf_msb << 16) + (u32) timf_lsb + comp; | 
 | 140 | 	else | 
 | 141 | 		comp = (u32)(timf_msb << 16) + (u32) timf_lsb - comp ; | 
 | 142 |  | 
 | 143 | 	timf_msb = (comp >> 16) & 0xff; | 
 | 144 | 	timf_lsb = comp & 0xffff; | 
 | 145 |  | 
 | 146 | 	wr(DIB3000MC_REG_TIMING_FREQ_MSB,timf_msb); | 
 | 147 | 	wr(DIB3000MC_REG_TIMING_FREQ_LSB,timf_lsb); | 
 | 148 | 	return 0; | 
 | 149 | } | 
 | 150 |  | 
 | 151 | static int dib3000mc_init_auto_scan(struct dib3000_state *state, fe_bandwidth_t bw, int boost) | 
 | 152 | { | 
 | 153 | 	if (boost) { | 
 | 154 | 		wr(DIB3000MC_REG_SCAN_BOOST,DIB3000MC_SCAN_BOOST_ON); | 
 | 155 | 	} else { | 
 | 156 | 		wr(DIB3000MC_REG_SCAN_BOOST,DIB3000MC_SCAN_BOOST_OFF); | 
 | 157 | 	} | 
 | 158 | 	switch (bw) { | 
 | 159 | 		case BANDWIDTH_8_MHZ: | 
 | 160 | 			wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_8mhz); | 
 | 161 | 			break; | 
 | 162 | 		case BANDWIDTH_7_MHZ: | 
 | 163 | 			wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_7mhz); | 
 | 164 | 			break; | 
 | 165 | 		case BANDWIDTH_6_MHZ: | 
 | 166 | 			wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_6mhz); | 
 | 167 | 			break; | 
 | 168 | /*		case BANDWIDTH_5_MHZ: | 
 | 169 | 			wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_5mhz); | 
 | 170 | 			break;*/ | 
 | 171 | 		case BANDWIDTH_AUTO: | 
 | 172 | 			return -EOPNOTSUPP; | 
 | 173 | 		default: | 
 | 174 | 			err("unknown bandwidth value (%d).",bw); | 
 | 175 | 			return -EINVAL; | 
 | 176 | 	} | 
 | 177 | 	if (boost) { | 
 | 178 | 		u32 timeout = (rd(DIB3000MC_REG_BW_TIMOUT_MSB) << 16) + | 
 | 179 | 			rd(DIB3000MC_REG_BW_TIMOUT_LSB); | 
 | 180 | 		timeout *= 85; timeout >>= 7; | 
 | 181 | 		wr(DIB3000MC_REG_BW_TIMOUT_MSB,(timeout >> 16) & 0xffff); | 
 | 182 | 		wr(DIB3000MC_REG_BW_TIMOUT_LSB,timeout & 0xffff); | 
 | 183 | 	} | 
 | 184 | 	return 0; | 
 | 185 | } | 
 | 186 |  | 
 | 187 | static int dib3000mc_set_adp_cfg(struct dib3000_state *state, fe_modulation_t con) | 
 | 188 | { | 
 | 189 | 	switch (con) { | 
 | 190 | 		case QAM_64: | 
 | 191 | 			wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[2]); | 
 | 192 | 			break; | 
 | 193 | 		case QAM_16: | 
 | 194 | 			wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[1]); | 
 | 195 | 			break; | 
 | 196 | 		case QPSK: | 
 | 197 | 			wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[0]); | 
 | 198 | 			break; | 
 | 199 | 		case QAM_AUTO: | 
 | 200 | 			break; | 
 | 201 | 		default: | 
 | 202 | 			warn("unkown constellation."); | 
 | 203 | 			break; | 
 | 204 | 	} | 
 | 205 | 	return 0; | 
 | 206 | } | 
 | 207 |  | 
 | 208 | static int dib3000mc_set_general_cfg(struct dib3000_state *state, struct dvb_frontend_parameters *fep, int *auto_val) | 
 | 209 | { | 
 | 210 | 	struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; | 
 | 211 | 	fe_code_rate_t fe_cr = FEC_NONE; | 
 | 212 | 	u8 fft=0, guard=0, qam=0, alpha=0, sel_hp=0, cr=0, hrch=0; | 
 | 213 | 	int seq; | 
 | 214 |  | 
 | 215 | 	switch (ofdm->transmission_mode) { | 
 | 216 | 		case TRANSMISSION_MODE_2K: fft = DIB3000_TRANSMISSION_MODE_2K; break; | 
 | 217 | 		case TRANSMISSION_MODE_8K: fft = DIB3000_TRANSMISSION_MODE_8K; break; | 
 | 218 | 		case TRANSMISSION_MODE_AUTO: break; | 
 | 219 | 		default: return -EINVAL; | 
 | 220 | 	} | 
 | 221 | 	switch (ofdm->guard_interval) { | 
 | 222 | 		case GUARD_INTERVAL_1_32: guard = DIB3000_GUARD_TIME_1_32; break; | 
 | 223 | 		case GUARD_INTERVAL_1_16: guard = DIB3000_GUARD_TIME_1_16; break; | 
 | 224 | 		case GUARD_INTERVAL_1_8:  guard = DIB3000_GUARD_TIME_1_8; break; | 
 | 225 | 		case GUARD_INTERVAL_1_4:  guard = DIB3000_GUARD_TIME_1_4; break; | 
 | 226 | 		case GUARD_INTERVAL_AUTO: break; | 
 | 227 | 		default: return -EINVAL; | 
 | 228 | 	} | 
 | 229 | 	switch (ofdm->constellation) { | 
 | 230 | 		case QPSK:   qam = DIB3000_CONSTELLATION_QPSK; break; | 
 | 231 | 		case QAM_16: qam = DIB3000_CONSTELLATION_16QAM; break; | 
 | 232 | 		case QAM_64: qam = DIB3000_CONSTELLATION_64QAM; break; | 
 | 233 | 		case QAM_AUTO: break; | 
 | 234 | 		default: return -EINVAL; | 
 | 235 | 	} | 
 | 236 | 	switch (ofdm->hierarchy_information) { | 
 | 237 | 		case HIERARCHY_NONE: /* fall through */ | 
 | 238 | 		case HIERARCHY_1: alpha = DIB3000_ALPHA_1; break; | 
 | 239 | 		case HIERARCHY_2: alpha = DIB3000_ALPHA_2; break; | 
 | 240 | 		case HIERARCHY_4: alpha = DIB3000_ALPHA_4; break; | 
 | 241 | 		case HIERARCHY_AUTO: break; | 
 | 242 | 		default: return -EINVAL; | 
 | 243 | 	} | 
 | 244 | 	if (ofdm->hierarchy_information == HIERARCHY_NONE) { | 
 | 245 | 		hrch   = DIB3000_HRCH_OFF; | 
 | 246 | 		sel_hp = DIB3000_SELECT_HP; | 
 | 247 | 		fe_cr  = ofdm->code_rate_HP; | 
 | 248 | 	} else if (ofdm->hierarchy_information != HIERARCHY_AUTO) { | 
 | 249 | 		hrch   = DIB3000_HRCH_ON; | 
 | 250 | 		sel_hp = DIB3000_SELECT_LP; | 
 | 251 | 		fe_cr  = ofdm->code_rate_LP; | 
 | 252 | 	} | 
 | 253 | 	switch (fe_cr) { | 
 | 254 | 		case FEC_1_2: cr = DIB3000_FEC_1_2; break; | 
 | 255 | 		case FEC_2_3: cr = DIB3000_FEC_2_3; break; | 
 | 256 | 		case FEC_3_4: cr = DIB3000_FEC_3_4; break; | 
 | 257 | 		case FEC_5_6: cr = DIB3000_FEC_5_6; break; | 
 | 258 | 		case FEC_7_8: cr = DIB3000_FEC_7_8; break; | 
 | 259 | 		case FEC_NONE: break; | 
 | 260 | 		case FEC_AUTO: break; | 
 | 261 | 		default: return -EINVAL; | 
 | 262 | 	} | 
 | 263 |  | 
 | 264 | 	wr(DIB3000MC_REG_DEMOD_PARM,DIB3000MC_DEMOD_PARM(alpha,qam,guard,fft)); | 
 | 265 | 	wr(DIB3000MC_REG_HRCH_PARM,DIB3000MC_HRCH_PARM(sel_hp,cr,hrch)); | 
 | 266 |  | 
 | 267 | 	switch (fep->inversion) { | 
 | 268 | 		case INVERSION_OFF: | 
 | 269 | 			wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_OFF); | 
 | 270 | 			break; | 
 | 271 | 		case INVERSION_AUTO: /* fall through */ | 
 | 272 | 		case INVERSION_ON: | 
 | 273 | 			wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_ON); | 
 | 274 | 			break; | 
 | 275 | 		default: | 
 | 276 | 			return -EINVAL; | 
 | 277 | 	} | 
 | 278 |  | 
 | 279 | 	seq = dib3000_seq | 
 | 280 | 		[ofdm->transmission_mode == TRANSMISSION_MODE_AUTO] | 
 | 281 | 		[ofdm->guard_interval == GUARD_INTERVAL_AUTO] | 
 | 282 | 		[fep->inversion == INVERSION_AUTO]; | 
 | 283 |  | 
 | 284 | 	deb_setf("seq? %d\n", seq); | 
 | 285 | 	wr(DIB3000MC_REG_SEQ_TPS,DIB3000MC_SEQ_TPS(seq,1)); | 
 | 286 | 	*auto_val = ofdm->constellation == QAM_AUTO || | 
 | 287 | 			ofdm->hierarchy_information == HIERARCHY_AUTO || | 
 | 288 | 			ofdm->guard_interval == GUARD_INTERVAL_AUTO || | 
 | 289 | 			ofdm->transmission_mode == TRANSMISSION_MODE_AUTO || | 
 | 290 | 			fe_cr == FEC_AUTO || | 
 | 291 | 			fep->inversion == INVERSION_AUTO; | 
 | 292 | 	return 0; | 
 | 293 | } | 
 | 294 |  | 
 | 295 | static int dib3000mc_get_frontend(struct dvb_frontend* fe, | 
 | 296 | 				  struct dvb_frontend_parameters *fep) | 
 | 297 | { | 
| Johannes Stezenbach | b874270 | 2005-05-16 21:54:31 -0700 | [diff] [blame] | 298 | 	struct dib3000_state* state = fe->demodulator_priv; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 299 | 	struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; | 
 | 300 | 	fe_code_rate_t *cr; | 
 | 301 | 	u16 tps_val,cr_val; | 
 | 302 | 	int inv_test1,inv_test2; | 
 | 303 | 	u32 dds_val, threshold = 0x1000000; | 
 | 304 |  | 
 | 305 | 	if (!(rd(DIB3000MC_REG_LOCK_507) & DIB3000MC_LOCK_507)) | 
 | 306 | 		return 0; | 
 | 307 |  | 
 | 308 | 	dds_val = (rd(DIB3000MC_REG_DDS_FREQ_MSB) << 16) + rd(DIB3000MC_REG_DDS_FREQ_LSB); | 
 | 309 | 	deb_getf("DDS_FREQ: %6x\n",dds_val); | 
 | 310 | 	if (dds_val < threshold) | 
 | 311 | 		inv_test1 = 0; | 
 | 312 | 	else if (dds_val == threshold) | 
 | 313 | 		inv_test1 = 1; | 
 | 314 | 	else | 
 | 315 | 		inv_test1 = 2; | 
 | 316 |  | 
 | 317 | 	dds_val = (rd(DIB3000MC_REG_SET_DDS_FREQ_MSB) << 16) + rd(DIB3000MC_REG_SET_DDS_FREQ_LSB); | 
 | 318 | 	deb_getf("DDS_SET_FREQ: %6x\n",dds_val); | 
 | 319 | 	if (dds_val < threshold) | 
 | 320 | 		inv_test2 = 0; | 
 | 321 | 	else if (dds_val == threshold) | 
 | 322 | 		inv_test2 = 1; | 
 | 323 | 	else | 
 | 324 | 		inv_test2 = 2; | 
 | 325 |  | 
 | 326 | 	fep->inversion = | 
 | 327 | 		((inv_test2 == 2) && (inv_test1==1 || inv_test1==0)) || | 
 | 328 | 		((inv_test2 == 0) && (inv_test1==1 || inv_test1==2)) ? | 
 | 329 | 		INVERSION_ON : INVERSION_OFF; | 
 | 330 |  | 
 | 331 | 	deb_getf("inversion %d %d, %d\n", inv_test2, inv_test1, fep->inversion); | 
 | 332 |  | 
 | 333 | 	fep->frequency = state->last_tuned_freq; | 
 | 334 | 	fep->u.ofdm.bandwidth= state->last_tuned_bw; | 
 | 335 |  | 
 | 336 | 	tps_val = rd(DIB3000MC_REG_TUNING_PARM); | 
 | 337 |  | 
 | 338 | 	switch (DIB3000MC_TP_QAM(tps_val)) { | 
 | 339 | 		case DIB3000_CONSTELLATION_QPSK: | 
 | 340 | 			deb_getf("QPSK "); | 
 | 341 | 			ofdm->constellation = QPSK; | 
 | 342 | 			break; | 
 | 343 | 		case DIB3000_CONSTELLATION_16QAM: | 
 | 344 | 			deb_getf("QAM16 "); | 
 | 345 | 			ofdm->constellation = QAM_16; | 
 | 346 | 			break; | 
 | 347 | 		case DIB3000_CONSTELLATION_64QAM: | 
 | 348 | 			deb_getf("QAM64 "); | 
 | 349 | 			ofdm->constellation = QAM_64; | 
 | 350 | 			break; | 
 | 351 | 		default: | 
 | 352 | 			err("Unexpected constellation returned by TPS (%d)", tps_val); | 
 | 353 | 			break; | 
 | 354 | 	} | 
 | 355 |  | 
 | 356 | 	if (DIB3000MC_TP_HRCH(tps_val)) { | 
 | 357 | 		deb_getf("HRCH ON "); | 
 | 358 | 		cr = &ofdm->code_rate_LP; | 
 | 359 | 		ofdm->code_rate_HP = FEC_NONE; | 
 | 360 | 		switch (DIB3000MC_TP_ALPHA(tps_val)) { | 
 | 361 | 			case DIB3000_ALPHA_0: | 
 | 362 | 				deb_getf("HIERARCHY_NONE "); | 
 | 363 | 				ofdm->hierarchy_information = HIERARCHY_NONE; | 
 | 364 | 				break; | 
 | 365 | 			case DIB3000_ALPHA_1: | 
 | 366 | 				deb_getf("HIERARCHY_1 "); | 
 | 367 | 				ofdm->hierarchy_information = HIERARCHY_1; | 
 | 368 | 				break; | 
 | 369 | 			case DIB3000_ALPHA_2: | 
 | 370 | 				deb_getf("HIERARCHY_2 "); | 
 | 371 | 				ofdm->hierarchy_information = HIERARCHY_2; | 
 | 372 | 				break; | 
 | 373 | 			case DIB3000_ALPHA_4: | 
 | 374 | 				deb_getf("HIERARCHY_4 "); | 
 | 375 | 				ofdm->hierarchy_information = HIERARCHY_4; | 
 | 376 | 				break; | 
 | 377 | 			default: | 
 | 378 | 				err("Unexpected ALPHA value returned by TPS (%d)", tps_val); | 
 | 379 | 				break; | 
 | 380 | 		} | 
 | 381 | 		cr_val = DIB3000MC_TP_FEC_CR_LP(tps_val); | 
 | 382 | 	} else { | 
 | 383 | 		deb_getf("HRCH OFF "); | 
 | 384 | 		cr = &ofdm->code_rate_HP; | 
 | 385 | 		ofdm->code_rate_LP = FEC_NONE; | 
 | 386 | 		ofdm->hierarchy_information = HIERARCHY_NONE; | 
 | 387 | 		cr_val = DIB3000MC_TP_FEC_CR_HP(tps_val); | 
 | 388 | 	} | 
 | 389 |  | 
 | 390 | 	switch (cr_val) { | 
 | 391 | 		case DIB3000_FEC_1_2: | 
 | 392 | 			deb_getf("FEC_1_2 "); | 
 | 393 | 			*cr = FEC_1_2; | 
 | 394 | 			break; | 
 | 395 | 		case DIB3000_FEC_2_3: | 
 | 396 | 			deb_getf("FEC_2_3 "); | 
 | 397 | 			*cr = FEC_2_3; | 
 | 398 | 			break; | 
 | 399 | 		case DIB3000_FEC_3_4: | 
 | 400 | 			deb_getf("FEC_3_4 "); | 
 | 401 | 			*cr = FEC_3_4; | 
 | 402 | 			break; | 
 | 403 | 		case DIB3000_FEC_5_6: | 
 | 404 | 			deb_getf("FEC_5_6 "); | 
 | 405 | 			*cr = FEC_4_5; | 
 | 406 | 			break; | 
 | 407 | 		case DIB3000_FEC_7_8: | 
 | 408 | 			deb_getf("FEC_7_8 "); | 
 | 409 | 			*cr = FEC_7_8; | 
 | 410 | 			break; | 
 | 411 | 		default: | 
 | 412 | 			err("Unexpected FEC returned by TPS (%d)", tps_val); | 
 | 413 | 			break; | 
 | 414 | 	} | 
 | 415 |  | 
 | 416 | 	switch (DIB3000MC_TP_GUARD(tps_val)) { | 
 | 417 | 		case DIB3000_GUARD_TIME_1_32: | 
 | 418 | 			deb_getf("GUARD_INTERVAL_1_32 "); | 
 | 419 | 			ofdm->guard_interval = GUARD_INTERVAL_1_32; | 
 | 420 | 			break; | 
 | 421 | 		case DIB3000_GUARD_TIME_1_16: | 
 | 422 | 			deb_getf("GUARD_INTERVAL_1_16 "); | 
 | 423 | 			ofdm->guard_interval = GUARD_INTERVAL_1_16; | 
 | 424 | 			break; | 
 | 425 | 		case DIB3000_GUARD_TIME_1_8: | 
 | 426 | 			deb_getf("GUARD_INTERVAL_1_8 "); | 
 | 427 | 			ofdm->guard_interval = GUARD_INTERVAL_1_8; | 
 | 428 | 			break; | 
 | 429 | 		case DIB3000_GUARD_TIME_1_4: | 
 | 430 | 			deb_getf("GUARD_INTERVAL_1_4 "); | 
 | 431 | 			ofdm->guard_interval = GUARD_INTERVAL_1_4; | 
 | 432 | 			break; | 
 | 433 | 		default: | 
 | 434 | 			err("Unexpected Guard Time returned by TPS (%d)", tps_val); | 
 | 435 | 			break; | 
 | 436 | 	} | 
 | 437 |  | 
 | 438 | 	switch (DIB3000MC_TP_FFT(tps_val)) { | 
 | 439 | 		case DIB3000_TRANSMISSION_MODE_2K: | 
 | 440 | 			deb_getf("TRANSMISSION_MODE_2K "); | 
 | 441 | 			ofdm->transmission_mode = TRANSMISSION_MODE_2K; | 
 | 442 | 			break; | 
 | 443 | 		case DIB3000_TRANSMISSION_MODE_8K: | 
 | 444 | 			deb_getf("TRANSMISSION_MODE_8K "); | 
 | 445 | 			ofdm->transmission_mode = TRANSMISSION_MODE_8K; | 
 | 446 | 			break; | 
 | 447 | 		default: | 
 | 448 | 			err("unexpected transmission mode return by TPS (%d)", tps_val); | 
 | 449 | 			break; | 
 | 450 | 	} | 
 | 451 | 	deb_getf("\n"); | 
 | 452 |  | 
 | 453 | 	return 0; | 
 | 454 | } | 
 | 455 |  | 
 | 456 | static int dib3000mc_set_frontend(struct dvb_frontend* fe, | 
 | 457 | 				  struct dvb_frontend_parameters *fep, int tuner) | 
 | 458 | { | 
| Johannes Stezenbach | b874270 | 2005-05-16 21:54:31 -0700 | [diff] [blame] | 459 | 	struct dib3000_state* state = fe->demodulator_priv; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 460 | 	struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; | 
 | 461 | 	int search_state,auto_val; | 
 | 462 | 	u16 val; | 
 | 463 |  | 
| Patrick Boettcher | dea7486 | 2006-05-14 05:01:31 -0300 | [diff] [blame] | 464 | 	if (tuner && fe->ops.tuner_ops.set_params) { /* initial call from dvb */ | 
 | 465 | 		fe->ops.tuner_ops.set_params(fe, fep); | 
 | 466 | 		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 467 |  | 
 | 468 | 		state->last_tuned_freq = fep->frequency; | 
 | 469 | 	//	if (!scanboost) { | 
 | 470 | 			dib3000mc_set_timing(state,0,ofdm->transmission_mode,ofdm->bandwidth); | 
 | 471 | 			dib3000mc_init_auto_scan(state, ofdm->bandwidth, 0); | 
 | 472 | 			state->last_tuned_bw = ofdm->bandwidth; | 
 | 473 |  | 
 | 474 | 			wr_foreach(dib3000mc_reg_agc_bandwidth,dib3000mc_agc_bandwidth); | 
 | 475 | 			wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_AGC); | 
 | 476 | 			wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_OFF); | 
 | 477 |  | 
 | 478 | 			/* Default cfg isi offset adp */ | 
 | 479 | 			wr_foreach(dib3000mc_reg_offset,dib3000mc_offset[0]); | 
 | 480 |  | 
 | 481 | 			wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT | DIB3000MC_ISI_INHIBIT); | 
 | 482 | 			dib3000mc_set_adp_cfg(state,ofdm->constellation); | 
 | 483 | 			wr(DIB3000MC_REG_UNK_133,DIB3000MC_UNK_133); | 
 | 484 |  | 
 | 485 | 			wr_foreach(dib3000mc_reg_bandwidth_general,dib3000mc_bandwidth_general); | 
 | 486 | 			/* power smoothing */ | 
 | 487 | 			if (ofdm->bandwidth != BANDWIDTH_8_MHZ) { | 
 | 488 | 				wr_foreach(dib3000mc_reg_bw,dib3000mc_bw[0]); | 
 | 489 | 			} else { | 
 | 490 | 				wr_foreach(dib3000mc_reg_bw,dib3000mc_bw[3]); | 
 | 491 | 			} | 
 | 492 | 			auto_val = 0; | 
 | 493 | 			dib3000mc_set_general_cfg(state,fep,&auto_val); | 
 | 494 | 			dib3000mc_set_impulse_noise(state,0,ofdm->constellation,ofdm->bandwidth); | 
 | 495 |  | 
 | 496 | 			val = rd(DIB3000MC_REG_DEMOD_PARM); | 
 | 497 | 			wr(DIB3000MC_REG_DEMOD_PARM,val|DIB3000MC_DEMOD_RST_DEMOD_ON); | 
 | 498 | 			wr(DIB3000MC_REG_DEMOD_PARM,val); | 
 | 499 | 	//	} | 
 | 500 | 		msleep(70); | 
 | 501 |  | 
 | 502 | 		/* something has to be auto searched */ | 
 | 503 | 		if (auto_val) { | 
 | 504 | 			int as_count=0; | 
 | 505 |  | 
 | 506 | 			deb_setf("autosearch enabled.\n"); | 
 | 507 |  | 
 | 508 | 			val = rd(DIB3000MC_REG_DEMOD_PARM); | 
 | 509 | 			wr(DIB3000MC_REG_DEMOD_PARM,val | DIB3000MC_DEMOD_RST_AUTO_SRCH_ON); | 
 | 510 | 			wr(DIB3000MC_REG_DEMOD_PARM,val); | 
 | 511 |  | 
 | 512 | 			while ((search_state = dib3000_search_status( | 
 | 513 | 						rd(DIB3000MC_REG_AS_IRQ),1)) < 0 && as_count++ < 100) | 
 | 514 | 				msleep(10); | 
 | 515 |  | 
 | 516 | 			deb_info("search_state after autosearch %d after %d checks\n",search_state,as_count); | 
 | 517 |  | 
 | 518 | 			if (search_state == 1) { | 
 | 519 | 				struct dvb_frontend_parameters feps; | 
 | 520 | 				if (dib3000mc_get_frontend(fe, &feps) == 0) { | 
 | 521 | 					deb_setf("reading tuning data from frontend succeeded.\n"); | 
 | 522 | 					return dib3000mc_set_frontend(fe, &feps, 0); | 
 | 523 | 				} | 
 | 524 | 			} | 
 | 525 | 		} else { | 
 | 526 | 			dib3000mc_set_impulse_noise(state,0,ofdm->transmission_mode,ofdm->bandwidth); | 
 | 527 | 			wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT|DIB3000MC_ISI_ACTIVATE); | 
 | 528 | 			dib3000mc_set_adp_cfg(state,ofdm->constellation); | 
 | 529 |  | 
 | 530 | 			/* set_offset_cfg */ | 
 | 531 | 			wr_foreach(dib3000mc_reg_offset, | 
 | 532 | 					dib3000mc_offset[(ofdm->transmission_mode == TRANSMISSION_MODE_8K)+1]); | 
 | 533 | 		} | 
 | 534 | 	} else { /* second call, after autosearch (fka: set_WithKnownParams) */ | 
 | 535 | //		dib3000mc_set_timing(state,1,ofdm->transmission_mode,ofdm->bandwidth); | 
 | 536 |  | 
 | 537 | 		auto_val = 0; | 
 | 538 | 		dib3000mc_set_general_cfg(state,fep,&auto_val); | 
 | 539 | 		if (auto_val) | 
 | 540 | 			deb_info("auto_val is true, even though an auto search was already performed.\n"); | 
 | 541 |  | 
 | 542 | 		dib3000mc_set_impulse_noise(state,0,ofdm->constellation,ofdm->bandwidth); | 
 | 543 |  | 
 | 544 | 		val = rd(DIB3000MC_REG_DEMOD_PARM); | 
 | 545 | 		wr(DIB3000MC_REG_DEMOD_PARM,val | DIB3000MC_DEMOD_RST_AUTO_SRCH_ON); | 
 | 546 | 		wr(DIB3000MC_REG_DEMOD_PARM,val); | 
 | 547 |  | 
 | 548 | 		msleep(30); | 
 | 549 |  | 
 | 550 | 		wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT|DIB3000MC_ISI_ACTIVATE); | 
 | 551 | 			dib3000mc_set_adp_cfg(state,ofdm->constellation); | 
 | 552 | 		wr_foreach(dib3000mc_reg_offset, | 
 | 553 | 				dib3000mc_offset[(ofdm->transmission_mode == TRANSMISSION_MODE_8K)+1]); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 554 | 	} | 
 | 555 | 	return 0; | 
 | 556 | } | 
 | 557 |  | 
 | 558 | static int dib3000mc_fe_init(struct dvb_frontend* fe, int mobile_mode) | 
 | 559 | { | 
| Johannes Stezenbach | 776338e | 2005-06-23 22:02:35 -0700 | [diff] [blame] | 560 | 	struct dib3000_state *state = fe->demodulator_priv; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 561 | 	deb_info("init start\n"); | 
 | 562 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 563 | 	state->timing_offset = 0; | 
 | 564 | 	state->timing_offset_comp_done = 0; | 
 | 565 |  | 
 | 566 | 	wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_CONFIG); | 
 | 567 | 	wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_OFF); | 
 | 568 | 	wr(DIB3000MC_REG_CLK_CFG_1,DIB3000MC_CLK_CFG_1_POWER_UP); | 
 | 569 | 	wr(DIB3000MC_REG_CLK_CFG_2,DIB3000MC_CLK_CFG_2_PUP_MOBILE); | 
 | 570 | 	wr(DIB3000MC_REG_CLK_CFG_3,DIB3000MC_CLK_CFG_3_POWER_UP); | 
 | 571 | 	wr(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_INIT); | 
 | 572 |  | 
 | 573 | 	wr(DIB3000MC_REG_RST_UNC,DIB3000MC_RST_UNC_OFF); | 
 | 574 | 	wr(DIB3000MC_REG_UNK_19,DIB3000MC_UNK_19); | 
 | 575 |  | 
 | 576 | 	wr(33,5); | 
 | 577 | 	wr(36,81); | 
 | 578 | 	wr(DIB3000MC_REG_UNK_88,DIB3000MC_UNK_88); | 
 | 579 |  | 
 | 580 | 	wr(DIB3000MC_REG_UNK_99,DIB3000MC_UNK_99); | 
 | 581 | 	wr(DIB3000MC_REG_UNK_111,DIB3000MC_UNK_111_PH_N_MODE_0); /* phase noise algo off */ | 
 | 582 |  | 
 | 583 | 	/* mobile mode - portable reception */ | 
 | 584 | 	wr_foreach(dib3000mc_reg_mobile_mode,dib3000mc_mobile_mode[1]); | 
 | 585 |  | 
 | 586 | /* TUNER_PANASONIC_ENV57H12D5: */ | 
 | 587 | 	wr_foreach(dib3000mc_reg_agc_bandwidth,dib3000mc_agc_bandwidth); | 
 | 588 | 	wr_foreach(dib3000mc_reg_agc_bandwidth_general,dib3000mc_agc_bandwidth_general); | 
 | 589 | 	wr_foreach(dib3000mc_reg_agc,dib3000mc_agc_tuner[1]); | 
 | 590 |  | 
 | 591 | 	wr(DIB3000MC_REG_UNK_110,DIB3000MC_UNK_110); | 
 | 592 | 	wr(26,0x6680); | 
 | 593 | 	wr(DIB3000MC_REG_UNK_1,DIB3000MC_UNK_1); | 
 | 594 | 	wr(DIB3000MC_REG_UNK_2,DIB3000MC_UNK_2); | 
 | 595 | 	wr(DIB3000MC_REG_UNK_3,DIB3000MC_UNK_3); | 
 | 596 | 	wr(DIB3000MC_REG_SEQ_TPS,DIB3000MC_SEQ_TPS_DEFAULT); | 
 | 597 |  | 
 | 598 | 	wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_8mhz); | 
 | 599 | 	wr_foreach(dib3000mc_reg_bandwidth_general,dib3000mc_bandwidth_general); | 
 | 600 |  | 
 | 601 | 	wr(DIB3000MC_REG_UNK_4,DIB3000MC_UNK_4); | 
 | 602 |  | 
 | 603 | 	wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_OFF); | 
 | 604 | 	wr(DIB3000MC_REG_SET_DDS_FREQ_LSB,DIB3000MC_DDS_FREQ_LSB); | 
 | 605 |  | 
 | 606 | 	dib3000mc_set_timing(state,0,TRANSMISSION_MODE_8K,BANDWIDTH_8_MHZ); | 
 | 607 | //	wr_foreach(dib3000mc_reg_timing_freq,dib3000mc_timing_freq[3]); | 
 | 608 |  | 
 | 609 | 	wr(DIB3000MC_REG_UNK_120,DIB3000MC_UNK_120); | 
 | 610 | 	wr(DIB3000MC_REG_UNK_134,DIB3000MC_UNK_134); | 
 | 611 | 	wr(DIB3000MC_REG_FEC_CFG,DIB3000MC_FEC_CFG); | 
 | 612 |  | 
 | 613 | 	wr(DIB3000MC_REG_DIVERSITY3,DIB3000MC_DIVERSITY3_IN_OFF); | 
 | 614 |  | 
 | 615 | 	dib3000mc_set_impulse_noise(state,0,TRANSMISSION_MODE_8K,BANDWIDTH_8_MHZ); | 
 | 616 |  | 
 | 617 | /* output mode control, just the MPEG2_SLAVE */ | 
 | 618 | //	set_or(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_SLAVE); | 
 | 619 | 	wr(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_SLAVE); | 
 | 620 | 	wr(DIB3000MC_REG_SMO_MODE,DIB3000MC_SMO_MODE_SLAVE); | 
 | 621 | 	wr(DIB3000MC_REG_FIFO_THRESHOLD,DIB3000MC_FIFO_THRESHOLD_SLAVE); | 
 | 622 | 	wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_SLAVE); | 
 | 623 |  | 
 | 624 | /* MPEG2_PARALLEL_CONTINUOUS_CLOCK | 
 | 625 | 	wr(DIB3000MC_REG_OUTMODE, | 
 | 626 | 		DIB3000MC_SET_OUTMODE(DIB3000MC_OM_PAR_CONT_CLK, | 
 | 627 | 			rd(DIB3000MC_REG_OUTMODE))); | 
 | 628 |  | 
 | 629 | 	wr(DIB3000MC_REG_SMO_MODE, | 
 | 630 | 			DIB3000MC_SMO_MODE_DEFAULT | | 
 | 631 | 			DIB3000MC_SMO_MODE_188); | 
 | 632 |  | 
 | 633 | 	wr(DIB3000MC_REG_FIFO_THRESHOLD,DIB3000MC_FIFO_THRESHOLD_DEFAULT); | 
 | 634 | 	wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_DIV_OUT_ON); | 
 | 635 | */ | 
 | 636 |  | 
 | 637 | /* diversity */ | 
 | 638 | 	wr(DIB3000MC_REG_DIVERSITY1,DIB3000MC_DIVERSITY1_DEFAULT); | 
 | 639 | 	wr(DIB3000MC_REG_DIVERSITY2,DIB3000MC_DIVERSITY2_DEFAULT); | 
 | 640 |  | 
 | 641 | 	set_and(DIB3000MC_REG_DIVERSITY3,DIB3000MC_DIVERSITY3_IN_OFF); | 
 | 642 |  | 
 | 643 | 	set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_DIV_IN_OFF); | 
 | 644 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 645 | 	deb_info("init end\n"); | 
 | 646 | 	return 0; | 
 | 647 | } | 
 | 648 | static int dib3000mc_read_status(struct dvb_frontend* fe, fe_status_t *stat) | 
 | 649 | { | 
| Johannes Stezenbach | b874270 | 2005-05-16 21:54:31 -0700 | [diff] [blame] | 650 | 	struct dib3000_state* state = fe->demodulator_priv; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 651 | 	u16 lock = rd(DIB3000MC_REG_LOCKING); | 
 | 652 |  | 
 | 653 | 	*stat = 0; | 
 | 654 | 	if (DIB3000MC_AGC_LOCK(lock)) | 
 | 655 | 		*stat |= FE_HAS_SIGNAL; | 
 | 656 | 	if (DIB3000MC_CARRIER_LOCK(lock)) | 
 | 657 | 		*stat |= FE_HAS_CARRIER; | 
 | 658 | 	if (DIB3000MC_TPS_LOCK(lock)) | 
 | 659 | 		*stat |= FE_HAS_VITERBI; | 
 | 660 | 	if (DIB3000MC_MPEG_SYNC_LOCK(lock)) | 
 | 661 | 		*stat |= (FE_HAS_SYNC | FE_HAS_LOCK); | 
 | 662 |  | 
 | 663 | 	deb_stat("actual status is %2x fifo_level: %x,244: %x, 206: %x, 207: %x, 1040: %x\n",*stat,rd(510),rd(244),rd(206),rd(207),rd(1040)); | 
 | 664 |  | 
 | 665 | 	return 0; | 
 | 666 | } | 
 | 667 |  | 
 | 668 | static int dib3000mc_read_ber(struct dvb_frontend* fe, u32 *ber) | 
 | 669 | { | 
| Johannes Stezenbach | b874270 | 2005-05-16 21:54:31 -0700 | [diff] [blame] | 670 | 	struct dib3000_state* state = fe->demodulator_priv; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 671 | 	*ber = ((rd(DIB3000MC_REG_BER_MSB) << 16) | rd(DIB3000MC_REG_BER_LSB)); | 
 | 672 | 	return 0; | 
 | 673 | } | 
 | 674 |  | 
 | 675 | static int dib3000mc_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) | 
 | 676 | { | 
| Johannes Stezenbach | b874270 | 2005-05-16 21:54:31 -0700 | [diff] [blame] | 677 | 	struct dib3000_state* state = fe->demodulator_priv; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 678 |  | 
| Johannes Stezenbach | 776338e | 2005-06-23 22:02:35 -0700 | [diff] [blame] | 679 | 	*unc = rd(DIB3000MC_REG_PACKET_ERRORS); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 680 | 	return 0; | 
 | 681 | } | 
 | 682 |  | 
 | 683 | /* see dib3000mb.c for calculation comments */ | 
 | 684 | static int dib3000mc_read_signal_strength(struct dvb_frontend* fe, u16 *strength) | 
 | 685 | { | 
| Johannes Stezenbach | b874270 | 2005-05-16 21:54:31 -0700 | [diff] [blame] | 686 | 	struct dib3000_state* state = fe->demodulator_priv; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 687 | 	u16 val = rd(DIB3000MC_REG_SIGNAL_NOISE_LSB); | 
 | 688 | 	*strength = (((val >> 6) & 0xff) << 8) + (val & 0x3f); | 
 | 689 |  | 
 | 690 | 	deb_stat("signal: mantisse = %d, exponent = %d\n",(*strength >> 8) & 0xff, *strength & 0xff); | 
 | 691 | 	return 0; | 
 | 692 | } | 
 | 693 |  | 
 | 694 | /* see dib3000mb.c for calculation comments */ | 
 | 695 | static int dib3000mc_read_snr(struct dvb_frontend* fe, u16 *snr) | 
 | 696 | { | 
| Johannes Stezenbach | b874270 | 2005-05-16 21:54:31 -0700 | [diff] [blame] | 697 | 	struct dib3000_state* state = fe->demodulator_priv; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 698 | 	u16 val = rd(DIB3000MC_REG_SIGNAL_NOISE_LSB), | 
 | 699 | 		val2 = rd(DIB3000MC_REG_SIGNAL_NOISE_MSB); | 
 | 700 | 	u16 sig,noise; | 
 | 701 |  | 
 | 702 | 	sig =   (((val >> 6) & 0xff) << 8) + (val & 0x3f); | 
 | 703 | 	noise = (((val >> 4) & 0xff) << 8) + ((val & 0xf) << 2) + ((val2 >> 14) & 0x3); | 
 | 704 | 	if (noise == 0) | 
 | 705 | 		*snr = 0xffff; | 
 | 706 | 	else | 
 | 707 | 		*snr = (u16) sig/noise; | 
 | 708 |  | 
 | 709 | 	deb_stat("signal: mantisse = %d, exponent = %d\n",(sig >> 8) & 0xff, sig & 0xff); | 
 | 710 | 	deb_stat("noise:  mantisse = %d, exponent = %d\n",(noise >> 8) & 0xff, noise & 0xff); | 
 | 711 | 	deb_stat("snr: %d\n",*snr); | 
 | 712 | 	return 0; | 
 | 713 | } | 
 | 714 |  | 
 | 715 | static int dib3000mc_sleep(struct dvb_frontend* fe) | 
 | 716 | { | 
| Johannes Stezenbach | b874270 | 2005-05-16 21:54:31 -0700 | [diff] [blame] | 717 | 	struct dib3000_state* state = fe->demodulator_priv; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 718 |  | 
 | 719 | 	set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_PWR_DOWN); | 
 | 720 | 	wr(DIB3000MC_REG_CLK_CFG_1,DIB3000MC_CLK_CFG_1_POWER_DOWN); | 
 | 721 | 	wr(DIB3000MC_REG_CLK_CFG_2,DIB3000MC_CLK_CFG_2_POWER_DOWN); | 
 | 722 | 	wr(DIB3000MC_REG_CLK_CFG_3,DIB3000MC_CLK_CFG_3_POWER_DOWN); | 
 | 723 | 	return 0; | 
 | 724 | } | 
 | 725 |  | 
 | 726 | static int dib3000mc_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) | 
 | 727 | { | 
| Johannes Stezenbach | 776338e | 2005-06-23 22:02:35 -0700 | [diff] [blame] | 728 | 	tune->min_delay_ms = 1000; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 729 | 	return 0; | 
 | 730 | } | 
 | 731 |  | 
 | 732 | static int dib3000mc_fe_init_nonmobile(struct dvb_frontend* fe) | 
 | 733 | { | 
 | 734 | 	return dib3000mc_fe_init(fe, 0); | 
 | 735 | } | 
 | 736 |  | 
 | 737 | static int dib3000mc_set_frontend_and_tuner(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) | 
 | 738 | { | 
 | 739 | 	return dib3000mc_set_frontend(fe, fep, 1); | 
 | 740 | } | 
 | 741 |  | 
 | 742 | static void dib3000mc_release(struct dvb_frontend* fe) | 
 | 743 | { | 
| Johannes Stezenbach | b874270 | 2005-05-16 21:54:31 -0700 | [diff] [blame] | 744 | 	struct dib3000_state *state = fe->demodulator_priv; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 745 | 	kfree(state); | 
 | 746 | } | 
 | 747 |  | 
 | 748 | /* pid filter and transfer stuff */ | 
 | 749 | static int dib3000mc_pid_control(struct dvb_frontend *fe,int index, int pid,int onoff) | 
 | 750 | { | 
 | 751 | 	struct dib3000_state *state = fe->demodulator_priv; | 
 | 752 | 	pid = (onoff ? pid | DIB3000_ACTIVATE_PID_FILTERING : 0); | 
 | 753 | 	wr(index+DIB3000MC_REG_FIRST_PID,pid); | 
 | 754 | 	return 0; | 
 | 755 | } | 
 | 756 |  | 
 | 757 | static int dib3000mc_fifo_control(struct dvb_frontend *fe, int onoff) | 
 | 758 | { | 
| Johannes Stezenbach | b874270 | 2005-05-16 21:54:31 -0700 | [diff] [blame] | 759 | 	struct dib3000_state *state = fe->demodulator_priv; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 760 | 	u16 tmp = rd(DIB3000MC_REG_SMO_MODE); | 
 | 761 |  | 
 | 762 | 	deb_xfer("%s fifo\n",onoff ? "enabling" : "disabling"); | 
 | 763 |  | 
 | 764 | 	if (onoff) { | 
 | 765 | 		deb_xfer("%d %x\n",tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH,tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH); | 
 | 766 | 		wr(DIB3000MC_REG_SMO_MODE,tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH); | 
 | 767 | 	} else { | 
 | 768 | 		deb_xfer("%d %x\n",tmp | DIB3000MC_SMO_MODE_FIFO_FLUSH,tmp | DIB3000MC_SMO_MODE_FIFO_FLUSH); | 
 | 769 | 		wr(DIB3000MC_REG_SMO_MODE,tmp | DIB3000MC_SMO_MODE_FIFO_FLUSH); | 
 | 770 | 	} | 
 | 771 | 	return 0; | 
 | 772 | } | 
 | 773 |  | 
 | 774 | static int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff) | 
 | 775 | { | 
 | 776 | 	struct dib3000_state *state = fe->demodulator_priv; | 
 | 777 | 	u16 tmp = rd(DIB3000MC_REG_SMO_MODE); | 
 | 778 |  | 
 | 779 | 	deb_xfer("%s pid parsing\n",onoff ? "enabling" : "disabling"); | 
 | 780 |  | 
 | 781 | 	if (onoff) { | 
 | 782 | 		wr(DIB3000MC_REG_SMO_MODE,tmp | DIB3000MC_SMO_MODE_PID_PARSE); | 
 | 783 | 	} else { | 
 | 784 | 		wr(DIB3000MC_REG_SMO_MODE,tmp & DIB3000MC_SMO_MODE_NO_PID_PARSE); | 
 | 785 | 	} | 
 | 786 | 	return 0; | 
 | 787 | } | 
 | 788 |  | 
 | 789 | static int dib3000mc_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr) | 
 | 790 | { | 
| Johannes Stezenbach | b874270 | 2005-05-16 21:54:31 -0700 | [diff] [blame] | 791 | 	struct dib3000_state *state = fe->demodulator_priv; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 792 | 	if (onoff) { | 
 | 793 | 		wr(DIB3000MC_REG_TUNER, DIB3000_TUNER_WRITE_ENABLE(pll_addr)); | 
 | 794 | 	} else { | 
 | 795 | 		wr(DIB3000MC_REG_TUNER, DIB3000_TUNER_WRITE_DISABLE(pll_addr)); | 
 | 796 | 	} | 
 | 797 | 	return 0; | 
 | 798 | } | 
 | 799 |  | 
 | 800 | static int dib3000mc_demod_init(struct dib3000_state *state) | 
 | 801 | { | 
 | 802 | 	u16 default_addr = 0x0a; | 
 | 803 | 	/* first init */ | 
 | 804 | 	if (state->config.demod_address != default_addr) { | 
 | 805 | 		deb_info("initializing the demod the first time. Setting demod addr to 0x%x\n",default_addr); | 
 | 806 | 		wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_DIV_OUT_ON); | 
 | 807 | 		wr(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_PAR_CONT_CLK); | 
 | 808 |  | 
 | 809 | 		wr(DIB3000MC_REG_RST_I2C_ADDR, | 
 | 810 | 			DIB3000MC_DEMOD_ADDR(default_addr) | | 
 | 811 | 			DIB3000MC_DEMOD_ADDR_ON); | 
 | 812 |  | 
 | 813 | 		state->config.demod_address = default_addr; | 
 | 814 |  | 
 | 815 | 		wr(DIB3000MC_REG_RST_I2C_ADDR, | 
 | 816 | 			DIB3000MC_DEMOD_ADDR(default_addr)); | 
 | 817 | 	} else | 
 | 818 | 		deb_info("demod is already initialized. Demod addr: 0x%x\n",state->config.demod_address); | 
 | 819 | 	return 0; | 
 | 820 | } | 
 | 821 |  | 
 | 822 |  | 
 | 823 | static struct dvb_frontend_ops dib3000mc_ops; | 
 | 824 |  | 
 | 825 | struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config, | 
 | 826 | 				      struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops) | 
 | 827 | { | 
 | 828 | 	struct dib3000_state* state = NULL; | 
 | 829 | 	u16 devid; | 
 | 830 |  | 
 | 831 | 	/* allocate memory for the internal state */ | 
| Panagiotis Issaris | 7408187 | 2006-01-11 19:40:56 -0200 | [diff] [blame] | 832 | 	state = kzalloc(sizeof(struct dib3000_state), GFP_KERNEL); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 833 | 	if (state == NULL) | 
 | 834 | 		goto error; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 835 |  | 
 | 836 | 	/* setup the state */ | 
 | 837 | 	state->i2c = i2c; | 
 | 838 | 	memcpy(&state->config,config,sizeof(struct dib3000_config)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 839 |  | 
 | 840 | 	/* check for the correct demod */ | 
 | 841 | 	if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM) | 
 | 842 | 		goto error; | 
 | 843 |  | 
 | 844 | 	devid = rd(DIB3000_REG_DEVICE_ID); | 
 | 845 | 	if (devid != DIB3000MC_DEVICE_ID && devid != DIB3000P_DEVICE_ID) | 
 | 846 | 		goto error; | 
 | 847 |  | 
 | 848 | 	switch (devid) { | 
 | 849 | 		case DIB3000MC_DEVICE_ID: | 
 | 850 | 			info("Found a DiBcom 3000M-C, interesting..."); | 
 | 851 | 			break; | 
 | 852 | 		case DIB3000P_DEVICE_ID: | 
 | 853 | 			info("Found a DiBcom 3000P."); | 
 | 854 | 			break; | 
 | 855 | 	} | 
 | 856 |  | 
 | 857 | 	/* create dvb_frontend */ | 
| Patrick Boettcher | dea7486 | 2006-05-14 05:01:31 -0300 | [diff] [blame] | 858 | 	memcpy(&state->frontend.ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 859 | 	state->frontend.demodulator_priv = state; | 
 | 860 |  | 
 | 861 | 	/* set the xfer operations */ | 
 | 862 | 	xfer_ops->pid_parse = dib3000mc_pid_parse; | 
 | 863 | 	xfer_ops->fifo_ctrl = dib3000mc_fifo_control; | 
 | 864 | 	xfer_ops->pid_ctrl = dib3000mc_pid_control; | 
 | 865 | 	xfer_ops->tuner_pass_ctrl = dib3000mc_tuner_pass_ctrl; | 
 | 866 |  | 
 | 867 | 	dib3000mc_demod_init(state); | 
 | 868 |  | 
 | 869 | 	return &state->frontend; | 
 | 870 |  | 
 | 871 | error: | 
 | 872 | 	kfree(state); | 
 | 873 | 	return NULL; | 
 | 874 | } | 
| Patrick Boettcher | dea7486 | 2006-05-14 05:01:31 -0300 | [diff] [blame] | 875 | EXPORT_SYMBOL(dib3000mc_attach); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 876 |  | 
 | 877 | static struct dvb_frontend_ops dib3000mc_ops = { | 
 | 878 |  | 
 | 879 | 	.info = { | 
 | 880 | 		.name			= "DiBcom 3000P/M-C DVB-T", | 
 | 881 | 		.type			= FE_OFDM, | 
 | 882 | 		.frequency_min		= 44250000, | 
 | 883 | 		.frequency_max		= 867250000, | 
 | 884 | 		.frequency_stepsize	= 62500, | 
 | 885 | 		.caps = FE_CAN_INVERSION_AUTO | | 
 | 886 | 				FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | 
 | 887 | 				FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | | 
 | 888 | 				FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | | 
 | 889 | 				FE_CAN_TRANSMISSION_MODE_AUTO | | 
 | 890 | 				FE_CAN_GUARD_INTERVAL_AUTO | | 
 | 891 | 				FE_CAN_RECOVER | | 
 | 892 | 				FE_CAN_HIERARCHY_AUTO, | 
 | 893 | 	}, | 
 | 894 |  | 
 | 895 | 	.release = dib3000mc_release, | 
 | 896 |  | 
 | 897 | 	.init = dib3000mc_fe_init_nonmobile, | 
 | 898 | 	.sleep = dib3000mc_sleep, | 
 | 899 |  | 
 | 900 | 	.set_frontend = dib3000mc_set_frontend_and_tuner, | 
 | 901 | 	.get_frontend = dib3000mc_get_frontend, | 
 | 902 | 	.get_tune_settings = dib3000mc_fe_get_tune_settings, | 
 | 903 |  | 
 | 904 | 	.read_status = dib3000mc_read_status, | 
 | 905 | 	.read_ber = dib3000mc_read_ber, | 
 | 906 | 	.read_signal_strength = dib3000mc_read_signal_strength, | 
 | 907 | 	.read_snr = dib3000mc_read_snr, | 
 | 908 | 	.read_ucblocks = dib3000mc_read_unc_blocks, | 
 | 909 | }; | 
 | 910 |  | 
 | 911 | MODULE_AUTHOR(DRIVER_AUTHOR); | 
 | 912 | MODULE_DESCRIPTION(DRIVER_DESC); | 
 | 913 | MODULE_LICENSE("GPL"); |