19a0bf528SMauro Carvalho Chehab /*
29a0bf528SMauro Carvalho Chehab 	STB0899 Multistandard Frontend driver
39a0bf528SMauro Carvalho Chehab 	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
49a0bf528SMauro Carvalho Chehab 
59a0bf528SMauro Carvalho Chehab 	Copyright (C) ST Microelectronics
69a0bf528SMauro Carvalho Chehab 
79a0bf528SMauro Carvalho Chehab 	This program is free software; you can redistribute it and/or modify
89a0bf528SMauro Carvalho Chehab 	it under the terms of the GNU General Public License as published by
99a0bf528SMauro Carvalho Chehab 	the Free Software Foundation; either version 2 of the License, or
109a0bf528SMauro Carvalho Chehab 	(at your option) any later version.
119a0bf528SMauro Carvalho Chehab 
129a0bf528SMauro Carvalho Chehab 	This program is distributed in the hope that it will be useful,
139a0bf528SMauro Carvalho Chehab 	but WITHOUT ANY WARRANTY; without even the implied warranty of
149a0bf528SMauro Carvalho Chehab 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
159a0bf528SMauro Carvalho Chehab 	GNU General Public License for more details.
169a0bf528SMauro Carvalho Chehab 
179a0bf528SMauro Carvalho Chehab 	You should have received a copy of the GNU General Public License
189a0bf528SMauro Carvalho Chehab 	along with this program; if not, write to the Free Software
199a0bf528SMauro Carvalho Chehab 	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
209a0bf528SMauro Carvalho Chehab */
219a0bf528SMauro Carvalho Chehab 
229a0bf528SMauro Carvalho Chehab #include "stb0899_drv.h"
239a0bf528SMauro Carvalho Chehab #include "stb0899_priv.h"
249a0bf528SMauro Carvalho Chehab #include "stb0899_reg.h"
259a0bf528SMauro Carvalho Chehab 
269a0bf528SMauro Carvalho Chehab static inline u32 stb0899_do_div(u64 n, u32 d)
279a0bf528SMauro Carvalho Chehab {
289a0bf528SMauro Carvalho Chehab 	/* wrap do_div() for ease of use */
299a0bf528SMauro Carvalho Chehab 
309a0bf528SMauro Carvalho Chehab 	do_div(n, d);
319a0bf528SMauro Carvalho Chehab 	return n;
329a0bf528SMauro Carvalho Chehab }
339a0bf528SMauro Carvalho Chehab 
349a0bf528SMauro Carvalho Chehab #if 0
359a0bf528SMauro Carvalho Chehab /* These functions are currently unused */
369a0bf528SMauro Carvalho Chehab /*
379a0bf528SMauro Carvalho Chehab  * stb0899_calc_srate
389a0bf528SMauro Carvalho Chehab  * Compute symbol rate
399a0bf528SMauro Carvalho Chehab  */
409a0bf528SMauro Carvalho Chehab static u32 stb0899_calc_srate(u32 master_clk, u8 *sfr)
419a0bf528SMauro Carvalho Chehab {
429a0bf528SMauro Carvalho Chehab 	u64 tmp;
439a0bf528SMauro Carvalho Chehab 
449a0bf528SMauro Carvalho Chehab 	/* srate = (SFR * master_clk) >> 20 */
459a0bf528SMauro Carvalho Chehab 
469a0bf528SMauro Carvalho Chehab 	/* sfr is of size 20 bit, stored with an offset of 4 bit */
479a0bf528SMauro Carvalho Chehab 	tmp = (((u32)sfr[0]) << 16) | (((u32)sfr[1]) << 8) | sfr[2];
489a0bf528SMauro Carvalho Chehab 	tmp &= ~0xf;
499a0bf528SMauro Carvalho Chehab 	tmp *= master_clk;
509a0bf528SMauro Carvalho Chehab 	tmp >>= 24;
519a0bf528SMauro Carvalho Chehab 
529a0bf528SMauro Carvalho Chehab 	return tmp;
539a0bf528SMauro Carvalho Chehab }
549a0bf528SMauro Carvalho Chehab 
559a0bf528SMauro Carvalho Chehab /*
569a0bf528SMauro Carvalho Chehab  * stb0899_get_srate
579a0bf528SMauro Carvalho Chehab  * Get the current symbol rate
589a0bf528SMauro Carvalho Chehab  */
599a0bf528SMauro Carvalho Chehab static u32 stb0899_get_srate(struct stb0899_state *state)
609a0bf528SMauro Carvalho Chehab {
619a0bf528SMauro Carvalho Chehab 	struct stb0899_internal *internal = &state->internal;
629a0bf528SMauro Carvalho Chehab 	u8 sfr[3];
639a0bf528SMauro Carvalho Chehab 
649a0bf528SMauro Carvalho Chehab 	stb0899_read_regs(state, STB0899_SFRH, sfr, 3);
659a0bf528SMauro Carvalho Chehab 
669a0bf528SMauro Carvalho Chehab 	return stb0899_calc_srate(internal->master_clk, sfr);
679a0bf528SMauro Carvalho Chehab }
689a0bf528SMauro Carvalho Chehab #endif
699a0bf528SMauro Carvalho Chehab 
709a0bf528SMauro Carvalho Chehab /*
719a0bf528SMauro Carvalho Chehab  * stb0899_set_srate
729a0bf528SMauro Carvalho Chehab  * Set symbol frequency
739a0bf528SMauro Carvalho Chehab  * MasterClock: master clock frequency (hz)
749a0bf528SMauro Carvalho Chehab  * SymbolRate: symbol rate (bauds)
759a0bf528SMauro Carvalho Chehab  * return symbol frequency
769a0bf528SMauro Carvalho Chehab  */
779a0bf528SMauro Carvalho Chehab static u32 stb0899_set_srate(struct stb0899_state *state, u32 master_clk, u32 srate)
789a0bf528SMauro Carvalho Chehab {
799a0bf528SMauro Carvalho Chehab 	u32 tmp;
809a0bf528SMauro Carvalho Chehab 	u8 sfr[3];
819a0bf528SMauro Carvalho Chehab 
829a0bf528SMauro Carvalho Chehab 	dprintk(state->verbose, FE_DEBUG, 1, "-->");
839a0bf528SMauro Carvalho Chehab 	/*
849a0bf528SMauro Carvalho Chehab 	 * in order to have the maximum precision, the symbol rate entered into
859a0bf528SMauro Carvalho Chehab 	 * the chip is computed as the closest value of the "true value".
869a0bf528SMauro Carvalho Chehab 	 * In this purpose, the symbol rate value is rounded (1 is added on the bit
879a0bf528SMauro Carvalho Chehab 	 * below the LSB )
889a0bf528SMauro Carvalho Chehab 	 *
899a0bf528SMauro Carvalho Chehab 	 * srate = (SFR * master_clk) >> 20
909a0bf528SMauro Carvalho Chehab 	 *      <=>
919a0bf528SMauro Carvalho Chehab 	 *   SFR = srate << 20 / master_clk
929a0bf528SMauro Carvalho Chehab 	 *
939a0bf528SMauro Carvalho Chehab 	 * rounded:
949a0bf528SMauro Carvalho Chehab 	 *   SFR = (srate << 21 + master_clk) / (2 * master_clk)
959a0bf528SMauro Carvalho Chehab 	 *
969a0bf528SMauro Carvalho Chehab 	 * stored as 20 bit number with an offset of 4 bit:
979a0bf528SMauro Carvalho Chehab 	 *   sfr = SFR << 4;
989a0bf528SMauro Carvalho Chehab 	 */
999a0bf528SMauro Carvalho Chehab 
1009a0bf528SMauro Carvalho Chehab 	tmp = stb0899_do_div((((u64)srate) << 21) + master_clk, 2 * master_clk);
1019a0bf528SMauro Carvalho Chehab 	tmp <<= 4;
1029a0bf528SMauro Carvalho Chehab 
1039a0bf528SMauro Carvalho Chehab 	sfr[0] = tmp >> 16;
1049a0bf528SMauro Carvalho Chehab 	sfr[1] = tmp >>  8;
1059a0bf528SMauro Carvalho Chehab 	sfr[2] = tmp;
1069a0bf528SMauro Carvalho Chehab 
1079a0bf528SMauro Carvalho Chehab 	stb0899_write_regs(state, STB0899_SFRH, sfr, 3);
1089a0bf528SMauro Carvalho Chehab 
1099a0bf528SMauro Carvalho Chehab 	return srate;
1109a0bf528SMauro Carvalho Chehab }
1119a0bf528SMauro Carvalho Chehab 
1129a0bf528SMauro Carvalho Chehab /*
1139a0bf528SMauro Carvalho Chehab  * stb0899_calc_derot_time
1149a0bf528SMauro Carvalho Chehab  * Compute the amount of time needed by the derotator to lock
1159a0bf528SMauro Carvalho Chehab  * SymbolRate: Symbol rate
1169a0bf528SMauro Carvalho Chehab  * return: derotator time constant (ms)
1179a0bf528SMauro Carvalho Chehab  */
1189a0bf528SMauro Carvalho Chehab static long stb0899_calc_derot_time(long srate)
1199a0bf528SMauro Carvalho Chehab {
1209a0bf528SMauro Carvalho Chehab 	if (srate > 0)
1219a0bf528SMauro Carvalho Chehab 		return (100000 / (srate / 1000));
1229a0bf528SMauro Carvalho Chehab 	else
1239a0bf528SMauro Carvalho Chehab 		return 0;
1249a0bf528SMauro Carvalho Chehab }
1259a0bf528SMauro Carvalho Chehab 
1269a0bf528SMauro Carvalho Chehab /*
1279a0bf528SMauro Carvalho Chehab  * stb0899_carr_width
1289a0bf528SMauro Carvalho Chehab  * Compute the width of the carrier
1299a0bf528SMauro Carvalho Chehab  * return: width of carrier (kHz or Mhz)
1309a0bf528SMauro Carvalho Chehab  */
1319a0bf528SMauro Carvalho Chehab long stb0899_carr_width(struct stb0899_state *state)
1329a0bf528SMauro Carvalho Chehab {
1339a0bf528SMauro Carvalho Chehab 	struct stb0899_internal *internal = &state->internal;
1349a0bf528SMauro Carvalho Chehab 
1359a0bf528SMauro Carvalho Chehab 	return (internal->srate + (internal->srate * internal->rolloff) / 100);
1369a0bf528SMauro Carvalho Chehab }
1379a0bf528SMauro Carvalho Chehab 
1389a0bf528SMauro Carvalho Chehab /*
1399a0bf528SMauro Carvalho Chehab  * stb0899_first_subrange
1409a0bf528SMauro Carvalho Chehab  * Compute the first subrange of the search
1419a0bf528SMauro Carvalho Chehab  */
1429a0bf528SMauro Carvalho Chehab static void stb0899_first_subrange(struct stb0899_state *state)
1439a0bf528SMauro Carvalho Chehab {
1449a0bf528SMauro Carvalho Chehab 	struct stb0899_internal *internal	= &state->internal;
1459a0bf528SMauro Carvalho Chehab 	struct stb0899_params *params		= &state->params;
1469a0bf528SMauro Carvalho Chehab 	struct stb0899_config *config		=  state->config;
1479a0bf528SMauro Carvalho Chehab 
1489a0bf528SMauro Carvalho Chehab 	int range = 0;
1499a0bf528SMauro Carvalho Chehab 	u32 bandwidth = 0;
1509a0bf528SMauro Carvalho Chehab 
1519a0bf528SMauro Carvalho Chehab 	if (config->tuner_get_bandwidth) {
1529a0bf528SMauro Carvalho Chehab 		stb0899_i2c_gate_ctrl(&state->frontend, 1);
1539a0bf528SMauro Carvalho Chehab 		config->tuner_get_bandwidth(&state->frontend, &bandwidth);
1549a0bf528SMauro Carvalho Chehab 		stb0899_i2c_gate_ctrl(&state->frontend, 0);
1559a0bf528SMauro Carvalho Chehab 		range = bandwidth - stb0899_carr_width(state) / 2;
1569a0bf528SMauro Carvalho Chehab 	}
1579a0bf528SMauro Carvalho Chehab 
1589a0bf528SMauro Carvalho Chehab 	if (range > 0)
1599a0bf528SMauro Carvalho Chehab 		internal->sub_range = min(internal->srch_range, range);
1609a0bf528SMauro Carvalho Chehab 	else
1619a0bf528SMauro Carvalho Chehab 		internal->sub_range = 0;
1629a0bf528SMauro Carvalho Chehab 
1639a0bf528SMauro Carvalho Chehab 	internal->freq = params->freq;
1649a0bf528SMauro Carvalho Chehab 	internal->tuner_offst = 0L;
1659a0bf528SMauro Carvalho Chehab 	internal->sub_dir = 1;
1669a0bf528SMauro Carvalho Chehab }
1679a0bf528SMauro Carvalho Chehab 
1689a0bf528SMauro Carvalho Chehab /*
1699a0bf528SMauro Carvalho Chehab  * stb0899_check_tmg
1709a0bf528SMauro Carvalho Chehab  * check for timing lock
1719a0bf528SMauro Carvalho Chehab  * internal.Ttiming: time to wait for loop lock
1729a0bf528SMauro Carvalho Chehab  */
1739a0bf528SMauro Carvalho Chehab static enum stb0899_status stb0899_check_tmg(struct stb0899_state *state)
1749a0bf528SMauro Carvalho Chehab {
1759a0bf528SMauro Carvalho Chehab 	struct stb0899_internal *internal = &state->internal;
1769a0bf528SMauro Carvalho Chehab 	int lock;
1779a0bf528SMauro Carvalho Chehab 	u8 reg;
1789a0bf528SMauro Carvalho Chehab 	s8 timing;
1799a0bf528SMauro Carvalho Chehab 
1809a0bf528SMauro Carvalho Chehab 	msleep(internal->t_derot);
1819a0bf528SMauro Carvalho Chehab 
1829a0bf528SMauro Carvalho Chehab 	stb0899_write_reg(state, STB0899_RTF, 0xf2);
1839a0bf528SMauro Carvalho Chehab 	reg = stb0899_read_reg(state, STB0899_TLIR);
1849a0bf528SMauro Carvalho Chehab 	lock = STB0899_GETFIELD(TLIR_TMG_LOCK_IND, reg);
1859a0bf528SMauro Carvalho Chehab 	timing = stb0899_read_reg(state, STB0899_RTF);
1869a0bf528SMauro Carvalho Chehab 
1879a0bf528SMauro Carvalho Chehab 	if (lock >= 42) {
1889a0bf528SMauro Carvalho Chehab 		if ((lock > 48) && (abs(timing) >= 110)) {
1899a0bf528SMauro Carvalho Chehab 			internal->status = ANALOGCARRIER;
1909a0bf528SMauro Carvalho Chehab 			dprintk(state->verbose, FE_DEBUG, 1, "-->ANALOG Carrier !");
1919a0bf528SMauro Carvalho Chehab 		} else {
1929a0bf528SMauro Carvalho Chehab 			internal->status = TIMINGOK;
1939a0bf528SMauro Carvalho Chehab 			dprintk(state->verbose, FE_DEBUG, 1, "------->TIMING OK !");
1949a0bf528SMauro Carvalho Chehab 		}
1959a0bf528SMauro Carvalho Chehab 	} else {
1969a0bf528SMauro Carvalho Chehab 		internal->status = NOTIMING;
1979a0bf528SMauro Carvalho Chehab 		dprintk(state->verbose, FE_DEBUG, 1, "-->NO TIMING !");
1989a0bf528SMauro Carvalho Chehab 	}
1999a0bf528SMauro Carvalho Chehab 	return internal->status;
2009a0bf528SMauro Carvalho Chehab }
2019a0bf528SMauro Carvalho Chehab 
2029a0bf528SMauro Carvalho Chehab /*
2039a0bf528SMauro Carvalho Chehab  * stb0899_search_tmg
2049a0bf528SMauro Carvalho Chehab  * perform a fs/2 zig-zag to find timing
2059a0bf528SMauro Carvalho Chehab  */
2069a0bf528SMauro Carvalho Chehab static enum stb0899_status stb0899_search_tmg(struct stb0899_state *state)
2079a0bf528SMauro Carvalho Chehab {
2089a0bf528SMauro Carvalho Chehab 	struct stb0899_internal *internal = &state->internal;
2099a0bf528SMauro Carvalho Chehab 	struct stb0899_params *params = &state->params;
2109a0bf528SMauro Carvalho Chehab 
2119a0bf528SMauro Carvalho Chehab 	short int derot_step, derot_freq = 0, derot_limit, next_loop = 3;
2129a0bf528SMauro Carvalho Chehab 	int index = 0;
2139a0bf528SMauro Carvalho Chehab 	u8 cfr[2];
2149a0bf528SMauro Carvalho Chehab 
2159a0bf528SMauro Carvalho Chehab 	internal->status = NOTIMING;
2169a0bf528SMauro Carvalho Chehab 
2179a0bf528SMauro Carvalho Chehab 	/* timing loop computation & symbol rate optimisation	*/
2189a0bf528SMauro Carvalho Chehab 	derot_limit = (internal->sub_range / 2L) / internal->mclk;
2199a0bf528SMauro Carvalho Chehab 	derot_step = (params->srate / 2L) / internal->mclk;
2209a0bf528SMauro Carvalho Chehab 
2219a0bf528SMauro Carvalho Chehab 	while ((stb0899_check_tmg(state) != TIMINGOK) && next_loop) {
2229a0bf528SMauro Carvalho Chehab 		index++;
2239a0bf528SMauro Carvalho Chehab 		derot_freq += index * internal->direction * derot_step;	/* next derot zig zag position	*/
2249a0bf528SMauro Carvalho Chehab 
2259a0bf528SMauro Carvalho Chehab 		if (abs(derot_freq) > derot_limit)
2269a0bf528SMauro Carvalho Chehab 			next_loop--;
2279a0bf528SMauro Carvalho Chehab 
2289a0bf528SMauro Carvalho Chehab 		if (next_loop) {
2299a0bf528SMauro Carvalho Chehab 			STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq));
2309a0bf528SMauro Carvalho Chehab 			STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq));
2319a0bf528SMauro Carvalho Chehab 			stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency		*/
2329a0bf528SMauro Carvalho Chehab 		}
2339a0bf528SMauro Carvalho Chehab 		internal->direction = -internal->direction;	/* Change zigzag direction		*/
2349a0bf528SMauro Carvalho Chehab 	}
2359a0bf528SMauro Carvalho Chehab 
2369a0bf528SMauro Carvalho Chehab 	if (internal->status == TIMINGOK) {
2379a0bf528SMauro Carvalho Chehab 		stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency		*/
2389a0bf528SMauro Carvalho Chehab 		internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]);
2399a0bf528SMauro Carvalho Chehab 		dprintk(state->verbose, FE_DEBUG, 1, "------->TIMING OK ! Derot Freq = %d", internal->derot_freq);
2409a0bf528SMauro Carvalho Chehab 	}
2419a0bf528SMauro Carvalho Chehab 
2429a0bf528SMauro Carvalho Chehab 	return internal->status;
2439a0bf528SMauro Carvalho Chehab }
2449a0bf528SMauro Carvalho Chehab 
2459a0bf528SMauro Carvalho Chehab /*
2469a0bf528SMauro Carvalho Chehab  * stb0899_check_carrier
2479a0bf528SMauro Carvalho Chehab  * Check for carrier found
2489a0bf528SMauro Carvalho Chehab  */
2499a0bf528SMauro Carvalho Chehab static enum stb0899_status stb0899_check_carrier(struct stb0899_state *state)
2509a0bf528SMauro Carvalho Chehab {
2519a0bf528SMauro Carvalho Chehab 	struct stb0899_internal *internal = &state->internal;
2529a0bf528SMauro Carvalho Chehab 	u8 reg;
2539a0bf528SMauro Carvalho Chehab 
2549a0bf528SMauro Carvalho Chehab 	msleep(internal->t_derot); /* wait for derotator ok	*/
2559a0bf528SMauro Carvalho Chehab 
2569a0bf528SMauro Carvalho Chehab 	reg = stb0899_read_reg(state, STB0899_CFD);
2579a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(CFD_ON, reg, 1);
2589a0bf528SMauro Carvalho Chehab 	stb0899_write_reg(state, STB0899_CFD, reg);
2599a0bf528SMauro Carvalho Chehab 
2609a0bf528SMauro Carvalho Chehab 	reg = stb0899_read_reg(state, STB0899_DSTATUS);
2619a0bf528SMauro Carvalho Chehab 	dprintk(state->verbose, FE_DEBUG, 1, "--------------------> STB0899_DSTATUS=[0x%02x]", reg);
2629a0bf528SMauro Carvalho Chehab 	if (STB0899_GETFIELD(CARRIER_FOUND, reg)) {
2639a0bf528SMauro Carvalho Chehab 		internal->status = CARRIEROK;
2649a0bf528SMauro Carvalho Chehab 		dprintk(state->verbose, FE_DEBUG, 1, "-------------> CARRIEROK !");
2659a0bf528SMauro Carvalho Chehab 	} else {
2669a0bf528SMauro Carvalho Chehab 		internal->status = NOCARRIER;
2679a0bf528SMauro Carvalho Chehab 		dprintk(state->verbose, FE_DEBUG, 1, "-------------> NOCARRIER !");
2689a0bf528SMauro Carvalho Chehab 	}
2699a0bf528SMauro Carvalho Chehab 
2709a0bf528SMauro Carvalho Chehab 	return internal->status;
2719a0bf528SMauro Carvalho Chehab }
2729a0bf528SMauro Carvalho Chehab 
2739a0bf528SMauro Carvalho Chehab /*
2749a0bf528SMauro Carvalho Chehab  * stb0899_search_carrier
2759a0bf528SMauro Carvalho Chehab  * Search for a QPSK carrier with the derotator
2769a0bf528SMauro Carvalho Chehab  */
2779a0bf528SMauro Carvalho Chehab static enum stb0899_status stb0899_search_carrier(struct stb0899_state *state)
2789a0bf528SMauro Carvalho Chehab {
2799a0bf528SMauro Carvalho Chehab 	struct stb0899_internal *internal = &state->internal;
2809a0bf528SMauro Carvalho Chehab 
2819a0bf528SMauro Carvalho Chehab 	short int derot_freq = 0, last_derot_freq = 0, derot_limit, next_loop = 3;
2829a0bf528SMauro Carvalho Chehab 	int index = 0;
2839a0bf528SMauro Carvalho Chehab 	u8 cfr[2];
2849a0bf528SMauro Carvalho Chehab 	u8 reg;
2859a0bf528SMauro Carvalho Chehab 
2869a0bf528SMauro Carvalho Chehab 	internal->status = NOCARRIER;
2879a0bf528SMauro Carvalho Chehab 	derot_limit = (internal->sub_range / 2L) / internal->mclk;
2889a0bf528SMauro Carvalho Chehab 	derot_freq = internal->derot_freq;
2899a0bf528SMauro Carvalho Chehab 
2909a0bf528SMauro Carvalho Chehab 	reg = stb0899_read_reg(state, STB0899_CFD);
2919a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(CFD_ON, reg, 1);
2929a0bf528SMauro Carvalho Chehab 	stb0899_write_reg(state, STB0899_CFD, reg);
2939a0bf528SMauro Carvalho Chehab 
2949a0bf528SMauro Carvalho Chehab 	do {
2959a0bf528SMauro Carvalho Chehab 		dprintk(state->verbose, FE_DEBUG, 1, "Derot Freq=%d, mclk=%d", derot_freq, internal->mclk);
2969a0bf528SMauro Carvalho Chehab 		if (stb0899_check_carrier(state) == NOCARRIER) {
2979a0bf528SMauro Carvalho Chehab 			index++;
2989a0bf528SMauro Carvalho Chehab 			last_derot_freq = derot_freq;
2999a0bf528SMauro Carvalho Chehab 			derot_freq += index * internal->direction * internal->derot_step; /* next zig zag derotator position */
3009a0bf528SMauro Carvalho Chehab 
3019a0bf528SMauro Carvalho Chehab 			if(abs(derot_freq) > derot_limit)
3029a0bf528SMauro Carvalho Chehab 				next_loop--;
3039a0bf528SMauro Carvalho Chehab 
3049a0bf528SMauro Carvalho Chehab 			if (next_loop) {
3059a0bf528SMauro Carvalho Chehab 				reg = stb0899_read_reg(state, STB0899_CFD);
3069a0bf528SMauro Carvalho Chehab 				STB0899_SETFIELD_VAL(CFD_ON, reg, 1);
3079a0bf528SMauro Carvalho Chehab 				stb0899_write_reg(state, STB0899_CFD, reg);
3089a0bf528SMauro Carvalho Chehab 
3099a0bf528SMauro Carvalho Chehab 				STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq));
3109a0bf528SMauro Carvalho Chehab 				STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq));
3119a0bf528SMauro Carvalho Chehab 				stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency	*/
3129a0bf528SMauro Carvalho Chehab 			}
3139a0bf528SMauro Carvalho Chehab 		}
3149a0bf528SMauro Carvalho Chehab 
3159a0bf528SMauro Carvalho Chehab 		internal->direction = -internal->direction; /* Change zigzag direction */
3169a0bf528SMauro Carvalho Chehab 	} while ((internal->status != CARRIEROK) && next_loop);
3179a0bf528SMauro Carvalho Chehab 
3189a0bf528SMauro Carvalho Chehab 	if (internal->status == CARRIEROK) {
3199a0bf528SMauro Carvalho Chehab 		stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency */
3209a0bf528SMauro Carvalho Chehab 		internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]);
3219a0bf528SMauro Carvalho Chehab 		dprintk(state->verbose, FE_DEBUG, 1, "----> CARRIER OK !, Derot Freq=%d", internal->derot_freq);
3229a0bf528SMauro Carvalho Chehab 	} else {
3239a0bf528SMauro Carvalho Chehab 		internal->derot_freq = last_derot_freq;
3249a0bf528SMauro Carvalho Chehab 	}
3259a0bf528SMauro Carvalho Chehab 
3269a0bf528SMauro Carvalho Chehab 	return internal->status;
3279a0bf528SMauro Carvalho Chehab }
3289a0bf528SMauro Carvalho Chehab 
3299a0bf528SMauro Carvalho Chehab /*
3309a0bf528SMauro Carvalho Chehab  * stb0899_check_data
3319a0bf528SMauro Carvalho Chehab  * Check for data found
3329a0bf528SMauro Carvalho Chehab  */
3339a0bf528SMauro Carvalho Chehab static enum stb0899_status stb0899_check_data(struct stb0899_state *state)
3349a0bf528SMauro Carvalho Chehab {
3359a0bf528SMauro Carvalho Chehab 	struct stb0899_internal *internal = &state->internal;
3369a0bf528SMauro Carvalho Chehab 	struct stb0899_params *params = &state->params;
3379a0bf528SMauro Carvalho Chehab 
3389a0bf528SMauro Carvalho Chehab 	int lock = 0, index = 0, dataTime = 500, loop;
3399a0bf528SMauro Carvalho Chehab 	u8 reg;
3409a0bf528SMauro Carvalho Chehab 
3419a0bf528SMauro Carvalho Chehab 	internal->status = NODATA;
3429a0bf528SMauro Carvalho Chehab 
3439a0bf528SMauro Carvalho Chehab 	/* RESET FEC	*/
3449a0bf528SMauro Carvalho Chehab 	reg = stb0899_read_reg(state, STB0899_TSTRES);
3459a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(FRESACS, reg, 1);
3469a0bf528SMauro Carvalho Chehab 	stb0899_write_reg(state, STB0899_TSTRES, reg);
3479a0bf528SMauro Carvalho Chehab 	msleep(1);
3489a0bf528SMauro Carvalho Chehab 	reg = stb0899_read_reg(state, STB0899_TSTRES);
3499a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(FRESACS, reg, 0);
3509a0bf528SMauro Carvalho Chehab 	stb0899_write_reg(state, STB0899_TSTRES, reg);
3519a0bf528SMauro Carvalho Chehab 
3529a0bf528SMauro Carvalho Chehab 	if (params->srate <= 2000000)
3539a0bf528SMauro Carvalho Chehab 		dataTime = 2000;
3549a0bf528SMauro Carvalho Chehab 	else if (params->srate <= 5000000)
3559a0bf528SMauro Carvalho Chehab 		dataTime = 1500;
3569a0bf528SMauro Carvalho Chehab 	else if (params->srate <= 15000000)
3579a0bf528SMauro Carvalho Chehab 		dataTime = 1000;
3589a0bf528SMauro Carvalho Chehab 	else
3599a0bf528SMauro Carvalho Chehab 		dataTime = 500;
3609a0bf528SMauro Carvalho Chehab 
3619a0bf528SMauro Carvalho Chehab 	/* clear previous failed END_LOOPVIT */
3629a0bf528SMauro Carvalho Chehab 	stb0899_read_reg(state, STB0899_VSTATUS);
3639a0bf528SMauro Carvalho Chehab 
3649a0bf528SMauro Carvalho Chehab 	stb0899_write_reg(state, STB0899_DSTATUS2, 0x00); /* force search loop	*/
3659a0bf528SMauro Carvalho Chehab 	while (1) {
3669a0bf528SMauro Carvalho Chehab 		/* WARNING! VIT LOCKED has to be tested before VIT_END_LOOOP	*/
3679a0bf528SMauro Carvalho Chehab 		reg = stb0899_read_reg(state, STB0899_VSTATUS);
3689a0bf528SMauro Carvalho Chehab 		lock = STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg);
3699a0bf528SMauro Carvalho Chehab 		loop = STB0899_GETFIELD(VSTATUS_END_LOOPVIT, reg);
3709a0bf528SMauro Carvalho Chehab 
3719a0bf528SMauro Carvalho Chehab 		if (lock || loop || (index > dataTime))
3729a0bf528SMauro Carvalho Chehab 			break;
3739a0bf528SMauro Carvalho Chehab 		index++;
3749a0bf528SMauro Carvalho Chehab 	}
3759a0bf528SMauro Carvalho Chehab 
3769a0bf528SMauro Carvalho Chehab 	if (lock) {	/* DATA LOCK indicator	*/
3779a0bf528SMauro Carvalho Chehab 		internal->status = DATAOK;
3789a0bf528SMauro Carvalho Chehab 		dprintk(state->verbose, FE_DEBUG, 1, "-----------------> DATA OK !");
3799a0bf528SMauro Carvalho Chehab 	}
3809a0bf528SMauro Carvalho Chehab 
3819a0bf528SMauro Carvalho Chehab 	return internal->status;
3829a0bf528SMauro Carvalho Chehab }
3839a0bf528SMauro Carvalho Chehab 
3849a0bf528SMauro Carvalho Chehab /*
3859a0bf528SMauro Carvalho Chehab  * stb0899_search_data
3869a0bf528SMauro Carvalho Chehab  * Search for a QPSK carrier with the derotator
3879a0bf528SMauro Carvalho Chehab  */
3889a0bf528SMauro Carvalho Chehab static enum stb0899_status stb0899_search_data(struct stb0899_state *state)
3899a0bf528SMauro Carvalho Chehab {
3909a0bf528SMauro Carvalho Chehab 	short int derot_freq, derot_step, derot_limit, next_loop = 3;
3919a0bf528SMauro Carvalho Chehab 	u8 cfr[2];
3929a0bf528SMauro Carvalho Chehab 	u8 reg;
3939a0bf528SMauro Carvalho Chehab 	int index = 1;
3949a0bf528SMauro Carvalho Chehab 
3959a0bf528SMauro Carvalho Chehab 	struct stb0899_internal *internal = &state->internal;
3969a0bf528SMauro Carvalho Chehab 	struct stb0899_params *params = &state->params;
3979a0bf528SMauro Carvalho Chehab 
3989a0bf528SMauro Carvalho Chehab 	derot_step = (params->srate / 4L) / internal->mclk;
3999a0bf528SMauro Carvalho Chehab 	derot_limit = (internal->sub_range / 2L) / internal->mclk;
4009a0bf528SMauro Carvalho Chehab 	derot_freq = internal->derot_freq;
4019a0bf528SMauro Carvalho Chehab 
4029a0bf528SMauro Carvalho Chehab 	do {
4039a0bf528SMauro Carvalho Chehab 		if ((internal->status != CARRIEROK) || (stb0899_check_data(state) != DATAOK)) {
4049a0bf528SMauro Carvalho Chehab 
4059a0bf528SMauro Carvalho Chehab 			derot_freq += index * internal->direction * derot_step;	/* next zig zag derotator position */
4069a0bf528SMauro Carvalho Chehab 			if (abs(derot_freq) > derot_limit)
4079a0bf528SMauro Carvalho Chehab 				next_loop--;
4089a0bf528SMauro Carvalho Chehab 
4099a0bf528SMauro Carvalho Chehab 			if (next_loop) {
4109a0bf528SMauro Carvalho Chehab 				dprintk(state->verbose, FE_DEBUG, 1, "Derot freq=%d, mclk=%d", derot_freq, internal->mclk);
4119a0bf528SMauro Carvalho Chehab 				reg = stb0899_read_reg(state, STB0899_CFD);
4129a0bf528SMauro Carvalho Chehab 				STB0899_SETFIELD_VAL(CFD_ON, reg, 1);
4139a0bf528SMauro Carvalho Chehab 				stb0899_write_reg(state, STB0899_CFD, reg);
4149a0bf528SMauro Carvalho Chehab 
4159a0bf528SMauro Carvalho Chehab 				STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq));
4169a0bf528SMauro Carvalho Chehab 				STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq));
4179a0bf528SMauro Carvalho Chehab 				stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency	*/
4189a0bf528SMauro Carvalho Chehab 
4199a0bf528SMauro Carvalho Chehab 				stb0899_check_carrier(state);
4209a0bf528SMauro Carvalho Chehab 				index++;
4219a0bf528SMauro Carvalho Chehab 			}
4229a0bf528SMauro Carvalho Chehab 		}
4239a0bf528SMauro Carvalho Chehab 		internal->direction = -internal->direction; /* change zig zag direction */
4249a0bf528SMauro Carvalho Chehab 	} while ((internal->status != DATAOK) && next_loop);
4259a0bf528SMauro Carvalho Chehab 
4269a0bf528SMauro Carvalho Chehab 	if (internal->status == DATAOK) {
4279a0bf528SMauro Carvalho Chehab 		stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency */
4289a0bf528SMauro Carvalho Chehab 		internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]);
4299a0bf528SMauro Carvalho Chehab 		dprintk(state->verbose, FE_DEBUG, 1, "------> DATAOK ! Derot Freq=%d", internal->derot_freq);
4309a0bf528SMauro Carvalho Chehab 	}
4319a0bf528SMauro Carvalho Chehab 
4329a0bf528SMauro Carvalho Chehab 	return internal->status;
4339a0bf528SMauro Carvalho Chehab }
4349a0bf528SMauro Carvalho Chehab 
4359a0bf528SMauro Carvalho Chehab /*
4369a0bf528SMauro Carvalho Chehab  * stb0899_check_range
4379a0bf528SMauro Carvalho Chehab  * check if the found frequency is in the correct range
4389a0bf528SMauro Carvalho Chehab  */
4399a0bf528SMauro Carvalho Chehab static enum stb0899_status stb0899_check_range(struct stb0899_state *state)
4409a0bf528SMauro Carvalho Chehab {
4419a0bf528SMauro Carvalho Chehab 	struct stb0899_internal *internal = &state->internal;
4429a0bf528SMauro Carvalho Chehab 	struct stb0899_params *params = &state->params;
4439a0bf528SMauro Carvalho Chehab 
4449a0bf528SMauro Carvalho Chehab 	int range_offst, tp_freq;
4459a0bf528SMauro Carvalho Chehab 
4469a0bf528SMauro Carvalho Chehab 	range_offst = internal->srch_range / 2000;
4479a0bf528SMauro Carvalho Chehab 	tp_freq = internal->freq + (internal->derot_freq * internal->mclk) / 1000;
4489a0bf528SMauro Carvalho Chehab 
4499a0bf528SMauro Carvalho Chehab 	if ((tp_freq >= params->freq - range_offst) && (tp_freq <= params->freq + range_offst)) {
4509a0bf528SMauro Carvalho Chehab 		internal->status = RANGEOK;
4519a0bf528SMauro Carvalho Chehab 		dprintk(state->verbose, FE_DEBUG, 1, "----> RANGEOK !");
4529a0bf528SMauro Carvalho Chehab 	} else {
4539a0bf528SMauro Carvalho Chehab 		internal->status = OUTOFRANGE;
4549a0bf528SMauro Carvalho Chehab 		dprintk(state->verbose, FE_DEBUG, 1, "----> OUT OF RANGE !");
4559a0bf528SMauro Carvalho Chehab 	}
4569a0bf528SMauro Carvalho Chehab 
4579a0bf528SMauro Carvalho Chehab 	return internal->status;
4589a0bf528SMauro Carvalho Chehab }
4599a0bf528SMauro Carvalho Chehab 
4609a0bf528SMauro Carvalho Chehab /*
4619a0bf528SMauro Carvalho Chehab  * NextSubRange
4629a0bf528SMauro Carvalho Chehab  * Compute the next subrange of the search
4639a0bf528SMauro Carvalho Chehab  */
4649a0bf528SMauro Carvalho Chehab static void next_sub_range(struct stb0899_state *state)
4659a0bf528SMauro Carvalho Chehab {
4669a0bf528SMauro Carvalho Chehab 	struct stb0899_internal *internal = &state->internal;
4679a0bf528SMauro Carvalho Chehab 	struct stb0899_params *params = &state->params;
4689a0bf528SMauro Carvalho Chehab 
4699a0bf528SMauro Carvalho Chehab 	long old_sub_range;
4709a0bf528SMauro Carvalho Chehab 
4719a0bf528SMauro Carvalho Chehab 	if (internal->sub_dir > 0) {
4729a0bf528SMauro Carvalho Chehab 		old_sub_range = internal->sub_range;
4739a0bf528SMauro Carvalho Chehab 		internal->sub_range = min((internal->srch_range / 2) -
4749a0bf528SMauro Carvalho Chehab 					  (internal->tuner_offst + internal->sub_range / 2),
4759a0bf528SMauro Carvalho Chehab 					   internal->sub_range);
4769a0bf528SMauro Carvalho Chehab 
4779a0bf528SMauro Carvalho Chehab 		if (internal->sub_range < 0)
4789a0bf528SMauro Carvalho Chehab 			internal->sub_range = 0;
4799a0bf528SMauro Carvalho Chehab 
4809a0bf528SMauro Carvalho Chehab 		internal->tuner_offst += (old_sub_range + internal->sub_range) / 2;
4819a0bf528SMauro Carvalho Chehab 	}
4829a0bf528SMauro Carvalho Chehab 
4839a0bf528SMauro Carvalho Chehab 	internal->freq = params->freq + (internal->sub_dir * internal->tuner_offst) / 1000;
4849a0bf528SMauro Carvalho Chehab 	internal->sub_dir = -internal->sub_dir;
4859a0bf528SMauro Carvalho Chehab }
4869a0bf528SMauro Carvalho Chehab 
4879a0bf528SMauro Carvalho Chehab /*
4889a0bf528SMauro Carvalho Chehab  * stb0899_dvbs_algo
4899a0bf528SMauro Carvalho Chehab  * Search for a signal, timing, carrier and data for a
4909a0bf528SMauro Carvalho Chehab  * given frequency in a given range
4919a0bf528SMauro Carvalho Chehab  */
4929a0bf528SMauro Carvalho Chehab enum stb0899_status stb0899_dvbs_algo(struct stb0899_state *state)
4939a0bf528SMauro Carvalho Chehab {
4949a0bf528SMauro Carvalho Chehab 	struct stb0899_params *params		= &state->params;
4959a0bf528SMauro Carvalho Chehab 	struct stb0899_internal *internal	= &state->internal;
4969a0bf528SMauro Carvalho Chehab 	struct stb0899_config *config		= state->config;
4979a0bf528SMauro Carvalho Chehab 
4989a0bf528SMauro Carvalho Chehab 	u8 bclc, reg;
4999a0bf528SMauro Carvalho Chehab 	u8 cfr[2];
5009a0bf528SMauro Carvalho Chehab 	u8 eq_const[10];
5019a0bf528SMauro Carvalho Chehab 	s32 clnI = 3;
5029a0bf528SMauro Carvalho Chehab 	u32 bandwidth = 0;
5039a0bf528SMauro Carvalho Chehab 
5049a0bf528SMauro Carvalho Chehab 	/* BETA values rated @ 99MHz	*/
5059a0bf528SMauro Carvalho Chehab 	s32 betaTab[5][4] = {
5069a0bf528SMauro Carvalho Chehab 	       /*  5   10   20   30MBps */
5079a0bf528SMauro Carvalho Chehab 		{ 37,  34,  32,  31 }, /* QPSK 1/2	*/
5089a0bf528SMauro Carvalho Chehab 		{ 37,  35,  33,  31 }, /* QPSK 2/3	*/
5099a0bf528SMauro Carvalho Chehab 		{ 37,  35,  33,  31 }, /* QPSK 3/4	*/
5109a0bf528SMauro Carvalho Chehab 		{ 37,  36,  33,	 32 }, /* QPSK 5/6	*/
5119a0bf528SMauro Carvalho Chehab 		{ 37,  36,  33,	 32 }  /* QPSK 7/8	*/
5129a0bf528SMauro Carvalho Chehab 	};
5139a0bf528SMauro Carvalho Chehab 
5149a0bf528SMauro Carvalho Chehab 	internal->direction = 1;
5159a0bf528SMauro Carvalho Chehab 
5169a0bf528SMauro Carvalho Chehab 	stb0899_set_srate(state, internal->master_clk, params->srate);
5179a0bf528SMauro Carvalho Chehab 	/* Carrier loop optimization versus symbol rate for acquisition*/
5189a0bf528SMauro Carvalho Chehab 	if (params->srate <= 5000000) {
5199a0bf528SMauro Carvalho Chehab 		stb0899_write_reg(state, STB0899_ACLC, 0x89);
5209a0bf528SMauro Carvalho Chehab 		bclc = stb0899_read_reg(state, STB0899_BCLC);
5219a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(BETA, bclc, 0x1c);
5229a0bf528SMauro Carvalho Chehab 		stb0899_write_reg(state, STB0899_BCLC, bclc);
5239a0bf528SMauro Carvalho Chehab 		clnI = 0;
5249a0bf528SMauro Carvalho Chehab 	} else if (params->srate <= 15000000) {
5259a0bf528SMauro Carvalho Chehab 		stb0899_write_reg(state, STB0899_ACLC, 0xc9);
5269a0bf528SMauro Carvalho Chehab 		bclc = stb0899_read_reg(state, STB0899_BCLC);
5279a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(BETA, bclc, 0x22);
5289a0bf528SMauro Carvalho Chehab 		stb0899_write_reg(state, STB0899_BCLC, bclc);
5299a0bf528SMauro Carvalho Chehab 		clnI = 1;
5309a0bf528SMauro Carvalho Chehab 	} else if(params->srate <= 25000000) {
5319a0bf528SMauro Carvalho Chehab 		stb0899_write_reg(state, STB0899_ACLC, 0x89);
5329a0bf528SMauro Carvalho Chehab 		bclc = stb0899_read_reg(state, STB0899_BCLC);
5339a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(BETA, bclc, 0x27);
5349a0bf528SMauro Carvalho Chehab 		stb0899_write_reg(state, STB0899_BCLC, bclc);
5359a0bf528SMauro Carvalho Chehab 		clnI = 2;
5369a0bf528SMauro Carvalho Chehab 	} else {
5379a0bf528SMauro Carvalho Chehab 		stb0899_write_reg(state, STB0899_ACLC, 0xc8);
5389a0bf528SMauro Carvalho Chehab 		bclc = stb0899_read_reg(state, STB0899_BCLC);
5399a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(BETA, bclc, 0x29);
5409a0bf528SMauro Carvalho Chehab 		stb0899_write_reg(state, STB0899_BCLC, bclc);
5419a0bf528SMauro Carvalho Chehab 		clnI = 3;
5429a0bf528SMauro Carvalho Chehab 	}
5439a0bf528SMauro Carvalho Chehab 
5449a0bf528SMauro Carvalho Chehab 	dprintk(state->verbose, FE_DEBUG, 1, "Set the timing loop to acquisition");
5459a0bf528SMauro Carvalho Chehab 	/* Set the timing loop to acquisition	*/
5469a0bf528SMauro Carvalho Chehab 	stb0899_write_reg(state, STB0899_RTC, 0x46);
5479a0bf528SMauro Carvalho Chehab 	stb0899_write_reg(state, STB0899_CFD, 0xee);
5489a0bf528SMauro Carvalho Chehab 
5499a0bf528SMauro Carvalho Chehab 	/* !! WARNING !!
5509a0bf528SMauro Carvalho Chehab 	 * Do not read any status variables while acquisition,
5519a0bf528SMauro Carvalho Chehab 	 * If any needed, read before the acquisition starts
5529a0bf528SMauro Carvalho Chehab 	 * querying status while acquiring causes the
5539a0bf528SMauro Carvalho Chehab 	 * acquisition to go bad and hence no locks.
5549a0bf528SMauro Carvalho Chehab 	 */
5559a0bf528SMauro Carvalho Chehab 	dprintk(state->verbose, FE_DEBUG, 1, "Derot Percent=%d Srate=%d mclk=%d",
5569a0bf528SMauro Carvalho Chehab 		internal->derot_percent, params->srate, internal->mclk);
5579a0bf528SMauro Carvalho Chehab 
5589a0bf528SMauro Carvalho Chehab 	/* Initial calculations	*/
5599a0bf528SMauro Carvalho Chehab 	internal->derot_step = internal->derot_percent * (params->srate / 1000L) / internal->mclk; /* DerotStep/1000 * Fsymbol	*/
5609a0bf528SMauro Carvalho Chehab 	internal->t_derot = stb0899_calc_derot_time(params->srate);
5619a0bf528SMauro Carvalho Chehab 	internal->t_data = 500;
5629a0bf528SMauro Carvalho Chehab 
5639a0bf528SMauro Carvalho Chehab 	dprintk(state->verbose, FE_DEBUG, 1, "RESET stream merger");
5649a0bf528SMauro Carvalho Chehab 	/* RESET Stream merger	*/
5659a0bf528SMauro Carvalho Chehab 	reg = stb0899_read_reg(state, STB0899_TSTRES);
5669a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(FRESRS, reg, 1);
5679a0bf528SMauro Carvalho Chehab 	stb0899_write_reg(state, STB0899_TSTRES, reg);
5689a0bf528SMauro Carvalho Chehab 
5699a0bf528SMauro Carvalho Chehab 	/*
5709a0bf528SMauro Carvalho Chehab 	 * Set KDIVIDER to an intermediate value between
5719a0bf528SMauro Carvalho Chehab 	 * 1/2 and 7/8 for acquisition
5729a0bf528SMauro Carvalho Chehab 	 */
5739a0bf528SMauro Carvalho Chehab 	reg = stb0899_read_reg(state, STB0899_DEMAPVIT);
5749a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(DEMAPVIT_KDIVIDER, reg, 60);
5759a0bf528SMauro Carvalho Chehab 	stb0899_write_reg(state, STB0899_DEMAPVIT, reg);
5769a0bf528SMauro Carvalho Chehab 
5779a0bf528SMauro Carvalho Chehab 	stb0899_write_reg(state, STB0899_EQON, 0x01); /* Equalizer OFF while acquiring */
5789a0bf528SMauro Carvalho Chehab 	stb0899_write_reg(state, STB0899_VITSYNC, 0x19);
5799a0bf528SMauro Carvalho Chehab 
5809a0bf528SMauro Carvalho Chehab 	stb0899_first_subrange(state);
5819a0bf528SMauro Carvalho Chehab 	do {
5829a0bf528SMauro Carvalho Chehab 		/* Initialisations */
5839a0bf528SMauro Carvalho Chehab 		cfr[0] = cfr[1] = 0;
5849a0bf528SMauro Carvalho Chehab 		stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* RESET derotator frequency	*/
5859a0bf528SMauro Carvalho Chehab 
5869a0bf528SMauro Carvalho Chehab 		stb0899_write_reg(state, STB0899_RTF, 0);
5879a0bf528SMauro Carvalho Chehab 		reg = stb0899_read_reg(state, STB0899_CFD);
5889a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(CFD_ON, reg, 1);
5899a0bf528SMauro Carvalho Chehab 		stb0899_write_reg(state, STB0899_CFD, reg);
5909a0bf528SMauro Carvalho Chehab 
5919a0bf528SMauro Carvalho Chehab 		internal->derot_freq = 0;
5929a0bf528SMauro Carvalho Chehab 		internal->status = NOAGC1;
5939a0bf528SMauro Carvalho Chehab 
5949a0bf528SMauro Carvalho Chehab 		/* enable tuner I/O */
5959a0bf528SMauro Carvalho Chehab 		stb0899_i2c_gate_ctrl(&state->frontend, 1);
5969a0bf528SMauro Carvalho Chehab 
5979a0bf528SMauro Carvalho Chehab 		/* Move tuner to frequency */
5989a0bf528SMauro Carvalho Chehab 		dprintk(state->verbose, FE_DEBUG, 1, "Tuner set frequency");
5999a0bf528SMauro Carvalho Chehab 		if (state->config->tuner_set_frequency)
6009a0bf528SMauro Carvalho Chehab 			state->config->tuner_set_frequency(&state->frontend, internal->freq);
6019a0bf528SMauro Carvalho Chehab 
6029a0bf528SMauro Carvalho Chehab 		if (state->config->tuner_get_frequency)
6039a0bf528SMauro Carvalho Chehab 			state->config->tuner_get_frequency(&state->frontend, &internal->freq);
6049a0bf528SMauro Carvalho Chehab 
6059a0bf528SMauro Carvalho Chehab 		msleep(internal->t_agc1 + internal->t_agc2 + internal->t_derot); /* AGC1, AGC2 and timing loop	*/
6069a0bf528SMauro Carvalho Chehab 		dprintk(state->verbose, FE_DEBUG, 1, "current derot freq=%d", internal->derot_freq);
6079a0bf528SMauro Carvalho Chehab 		internal->status = AGC1OK;
6089a0bf528SMauro Carvalho Chehab 
6099a0bf528SMauro Carvalho Chehab 		/* There is signal in the band	*/
6109a0bf528SMauro Carvalho Chehab 		if (config->tuner_get_bandwidth)
6119a0bf528SMauro Carvalho Chehab 			config->tuner_get_bandwidth(&state->frontend, &bandwidth);
6129a0bf528SMauro Carvalho Chehab 
6139a0bf528SMauro Carvalho Chehab 		/* disable tuner I/O */
6149a0bf528SMauro Carvalho Chehab 		stb0899_i2c_gate_ctrl(&state->frontend, 0);
6159a0bf528SMauro Carvalho Chehab 
6169a0bf528SMauro Carvalho Chehab 		if (params->srate <= bandwidth / 2)
6179a0bf528SMauro Carvalho Chehab 			stb0899_search_tmg(state); /* For low rates (SCPC)	*/
6189a0bf528SMauro Carvalho Chehab 		else
6199a0bf528SMauro Carvalho Chehab 			stb0899_check_tmg(state); /* For high rates (MCPC)	*/
6209a0bf528SMauro Carvalho Chehab 
6219a0bf528SMauro Carvalho Chehab 		if (internal->status == TIMINGOK) {
6229a0bf528SMauro Carvalho Chehab 			dprintk(state->verbose, FE_DEBUG, 1,
6239a0bf528SMauro Carvalho Chehab 				"TIMING OK ! Derot freq=%d, mclk=%d",
6249a0bf528SMauro Carvalho Chehab 				internal->derot_freq, internal->mclk);
6259a0bf528SMauro Carvalho Chehab 
6269a0bf528SMauro Carvalho Chehab 			if (stb0899_search_carrier(state) == CARRIEROK) {	/* Search for carrier	*/
6279a0bf528SMauro Carvalho Chehab 				dprintk(state->verbose, FE_DEBUG, 1,
6289a0bf528SMauro Carvalho Chehab 					"CARRIER OK ! Derot freq=%d, mclk=%d",
6299a0bf528SMauro Carvalho Chehab 					internal->derot_freq, internal->mclk);
6309a0bf528SMauro Carvalho Chehab 
6319a0bf528SMauro Carvalho Chehab 				if (stb0899_search_data(state) == DATAOK) {	/* Check for data	*/
6329a0bf528SMauro Carvalho Chehab 					dprintk(state->verbose, FE_DEBUG, 1,
6339a0bf528SMauro Carvalho Chehab 						"DATA OK ! Derot freq=%d, mclk=%d",
6349a0bf528SMauro Carvalho Chehab 						internal->derot_freq, internal->mclk);
6359a0bf528SMauro Carvalho Chehab 
6369a0bf528SMauro Carvalho Chehab 					if (stb0899_check_range(state) == RANGEOK) {
6379a0bf528SMauro Carvalho Chehab 						dprintk(state->verbose, FE_DEBUG, 1,
6389a0bf528SMauro Carvalho Chehab 							"RANGE OK ! derot freq=%d, mclk=%d",
6399a0bf528SMauro Carvalho Chehab 							internal->derot_freq, internal->mclk);
6409a0bf528SMauro Carvalho Chehab 
6419a0bf528SMauro Carvalho Chehab 						internal->freq = params->freq + ((internal->derot_freq * internal->mclk) / 1000);
6429a0bf528SMauro Carvalho Chehab 						reg = stb0899_read_reg(state, STB0899_PLPARM);
6439a0bf528SMauro Carvalho Chehab 						internal->fecrate = STB0899_GETFIELD(VITCURPUN, reg);
6449a0bf528SMauro Carvalho Chehab 						dprintk(state->verbose, FE_DEBUG, 1,
6459a0bf528SMauro Carvalho Chehab 							"freq=%d, internal resultant freq=%d",
6469a0bf528SMauro Carvalho Chehab 							params->freq, internal->freq);
6479a0bf528SMauro Carvalho Chehab 
6489a0bf528SMauro Carvalho Chehab 						dprintk(state->verbose, FE_DEBUG, 1,
6499a0bf528SMauro Carvalho Chehab 							"internal puncture rate=%d",
6509a0bf528SMauro Carvalho Chehab 							internal->fecrate);
6519a0bf528SMauro Carvalho Chehab 					}
6529a0bf528SMauro Carvalho Chehab 				}
6539a0bf528SMauro Carvalho Chehab 			}
6549a0bf528SMauro Carvalho Chehab 		}
6559a0bf528SMauro Carvalho Chehab 		if (internal->status != RANGEOK)
6569a0bf528SMauro Carvalho Chehab 			next_sub_range(state);
6579a0bf528SMauro Carvalho Chehab 
6589a0bf528SMauro Carvalho Chehab 	} while (internal->sub_range && internal->status != RANGEOK);
6599a0bf528SMauro Carvalho Chehab 
6609a0bf528SMauro Carvalho Chehab 	/* Set the timing loop to tracking	*/
6619a0bf528SMauro Carvalho Chehab 	stb0899_write_reg(state, STB0899_RTC, 0x33);
6629a0bf528SMauro Carvalho Chehab 	stb0899_write_reg(state, STB0899_CFD, 0xf7);
6639a0bf528SMauro Carvalho Chehab 	/* if locked and range ok, set Kdiv	*/
6649a0bf528SMauro Carvalho Chehab 	if (internal->status == RANGEOK) {
6659a0bf528SMauro Carvalho Chehab 		dprintk(state->verbose, FE_DEBUG, 1, "Locked & Range OK !");
6669a0bf528SMauro Carvalho Chehab 		stb0899_write_reg(state, STB0899_EQON, 0x41);		/* Equalizer OFF while acquiring	*/
6679a0bf528SMauro Carvalho Chehab 		stb0899_write_reg(state, STB0899_VITSYNC, 0x39);	/* SN to b'11 for acquisition		*/
6689a0bf528SMauro Carvalho Chehab 
6699a0bf528SMauro Carvalho Chehab 		/*
6709a0bf528SMauro Carvalho Chehab 		 * Carrier loop optimization versus
6719a0bf528SMauro Carvalho Chehab 		 * symbol Rate/Puncture Rate for Tracking
6729a0bf528SMauro Carvalho Chehab 		 */
6739a0bf528SMauro Carvalho Chehab 		reg = stb0899_read_reg(state, STB0899_BCLC);
6749a0bf528SMauro Carvalho Chehab 		switch (internal->fecrate) {
6759a0bf528SMauro Carvalho Chehab 		case STB0899_FEC_1_2:		/* 13	*/
6769a0bf528SMauro Carvalho Chehab 			stb0899_write_reg(state, STB0899_DEMAPVIT, 0x1a);
6779a0bf528SMauro Carvalho Chehab 			STB0899_SETFIELD_VAL(BETA, reg, betaTab[0][clnI]);
6789a0bf528SMauro Carvalho Chehab 			stb0899_write_reg(state, STB0899_BCLC, reg);
6799a0bf528SMauro Carvalho Chehab 			break;
6809a0bf528SMauro Carvalho Chehab 		case STB0899_FEC_2_3:		/* 18	*/
6819a0bf528SMauro Carvalho Chehab 			stb0899_write_reg(state, STB0899_DEMAPVIT, 44);
6829a0bf528SMauro Carvalho Chehab 			STB0899_SETFIELD_VAL(BETA, reg, betaTab[1][clnI]);
6839a0bf528SMauro Carvalho Chehab 			stb0899_write_reg(state, STB0899_BCLC, reg);
6849a0bf528SMauro Carvalho Chehab 			break;
6859a0bf528SMauro Carvalho Chehab 		case STB0899_FEC_3_4:		/* 21	*/
6869a0bf528SMauro Carvalho Chehab 			stb0899_write_reg(state, STB0899_DEMAPVIT, 60);
6879a0bf528SMauro Carvalho Chehab 			STB0899_SETFIELD_VAL(BETA, reg, betaTab[2][clnI]);
6889a0bf528SMauro Carvalho Chehab 			stb0899_write_reg(state, STB0899_BCLC, reg);
6899a0bf528SMauro Carvalho Chehab 			break;
6909a0bf528SMauro Carvalho Chehab 		case STB0899_FEC_5_6:		/* 24	*/
6919a0bf528SMauro Carvalho Chehab 			stb0899_write_reg(state, STB0899_DEMAPVIT, 75);
6929a0bf528SMauro Carvalho Chehab 			STB0899_SETFIELD_VAL(BETA, reg, betaTab[3][clnI]);
6939a0bf528SMauro Carvalho Chehab 			stb0899_write_reg(state, STB0899_BCLC, reg);
6949a0bf528SMauro Carvalho Chehab 			break;
6959a0bf528SMauro Carvalho Chehab 		case STB0899_FEC_6_7:		/* 25	*/
6969a0bf528SMauro Carvalho Chehab 			stb0899_write_reg(state, STB0899_DEMAPVIT, 88);
6979a0bf528SMauro Carvalho Chehab 			stb0899_write_reg(state, STB0899_ACLC, 0x88);
6989a0bf528SMauro Carvalho Chehab 			stb0899_write_reg(state, STB0899_BCLC, 0x9a);
6999a0bf528SMauro Carvalho Chehab 			break;
7009a0bf528SMauro Carvalho Chehab 		case STB0899_FEC_7_8:		/* 26	*/
7019a0bf528SMauro Carvalho Chehab 			stb0899_write_reg(state, STB0899_DEMAPVIT, 94);
7029a0bf528SMauro Carvalho Chehab 			STB0899_SETFIELD_VAL(BETA, reg, betaTab[4][clnI]);
7039a0bf528SMauro Carvalho Chehab 			stb0899_write_reg(state, STB0899_BCLC, reg);
7049a0bf528SMauro Carvalho Chehab 			break;
7059a0bf528SMauro Carvalho Chehab 		default:
7069a0bf528SMauro Carvalho Chehab 			dprintk(state->verbose, FE_DEBUG, 1, "Unsupported Puncture Rate");
7079a0bf528SMauro Carvalho Chehab 			break;
7089a0bf528SMauro Carvalho Chehab 		}
7099a0bf528SMauro Carvalho Chehab 		/* release stream merger RESET	*/
7109a0bf528SMauro Carvalho Chehab 		reg = stb0899_read_reg(state, STB0899_TSTRES);
7119a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(FRESRS, reg, 0);
7129a0bf528SMauro Carvalho Chehab 		stb0899_write_reg(state, STB0899_TSTRES, reg);
7139a0bf528SMauro Carvalho Chehab 
7149a0bf528SMauro Carvalho Chehab 		/* disable carrier detector	*/
7159a0bf528SMauro Carvalho Chehab 		reg = stb0899_read_reg(state, STB0899_CFD);
7169a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(CFD_ON, reg, 0);
7179a0bf528SMauro Carvalho Chehab 		stb0899_write_reg(state, STB0899_CFD, reg);
7189a0bf528SMauro Carvalho Chehab 
7199a0bf528SMauro Carvalho Chehab 		stb0899_read_regs(state, STB0899_EQUAI1, eq_const, 10);
7209a0bf528SMauro Carvalho Chehab 	}
7219a0bf528SMauro Carvalho Chehab 
7229a0bf528SMauro Carvalho Chehab 	return internal->status;
7239a0bf528SMauro Carvalho Chehab }
7249a0bf528SMauro Carvalho Chehab 
7259a0bf528SMauro Carvalho Chehab /*
7269a0bf528SMauro Carvalho Chehab  * stb0899_dvbs2_config_uwp
7279a0bf528SMauro Carvalho Chehab  * Configure UWP state machine
7289a0bf528SMauro Carvalho Chehab  */
7299a0bf528SMauro Carvalho Chehab static void stb0899_dvbs2_config_uwp(struct stb0899_state *state)
7309a0bf528SMauro Carvalho Chehab {
7319a0bf528SMauro Carvalho Chehab 	struct stb0899_internal *internal = &state->internal;
7329a0bf528SMauro Carvalho Chehab 	struct stb0899_config *config = state->config;
7339a0bf528SMauro Carvalho Chehab 	u32 uwp1, uwp2, uwp3, reg;
7349a0bf528SMauro Carvalho Chehab 
7359a0bf528SMauro Carvalho Chehab 	uwp1 = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL1);
7369a0bf528SMauro Carvalho Chehab 	uwp2 = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL2);
7379a0bf528SMauro Carvalho Chehab 	uwp3 = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL3);
7389a0bf528SMauro Carvalho Chehab 
7399a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(UWP_ESN0_AVE, uwp1, config->esno_ave);
7409a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(UWP_ESN0_QUANT, uwp1, config->esno_quant);
7419a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(UWP_TH_SOF, uwp1, config->uwp_threshold_sof);
7429a0bf528SMauro Carvalho Chehab 
7439a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(FE_COARSE_TRK, uwp2, internal->av_frame_coarse);
7449a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(FE_FINE_TRK, uwp2, internal->av_frame_fine);
7459a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(UWP_MISS_TH, uwp2, config->miss_threshold);
7469a0bf528SMauro Carvalho Chehab 
7479a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(UWP_TH_ACQ, uwp3, config->uwp_threshold_acq);
7489a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(UWP_TH_TRACK, uwp3, config->uwp_threshold_track);
7499a0bf528SMauro Carvalho Chehab 
7509a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_UWP_CNTRL1, STB0899_OFF0_UWP_CNTRL1, uwp1);
7519a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_UWP_CNTRL2, STB0899_OFF0_UWP_CNTRL2, uwp2);
7529a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_UWP_CNTRL3, STB0899_OFF0_UWP_CNTRL3, uwp3);
7539a0bf528SMauro Carvalho Chehab 
7549a0bf528SMauro Carvalho Chehab 	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, SOF_SRCH_TO);
7559a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(SOF_SEARCH_TIMEOUT, reg, config->sof_search_timeout);
7569a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_SOF_SRCH_TO, STB0899_OFF0_SOF_SRCH_TO, reg);
7579a0bf528SMauro Carvalho Chehab }
7589a0bf528SMauro Carvalho Chehab 
7599a0bf528SMauro Carvalho Chehab /*
7609a0bf528SMauro Carvalho Chehab  * stb0899_dvbs2_config_csm_auto
7619a0bf528SMauro Carvalho Chehab  * Set CSM to AUTO mode
7629a0bf528SMauro Carvalho Chehab  */
7639a0bf528SMauro Carvalho Chehab static void stb0899_dvbs2_config_csm_auto(struct stb0899_state *state)
7649a0bf528SMauro Carvalho Chehab {
7659a0bf528SMauro Carvalho Chehab 	u32 reg;
7669a0bf528SMauro Carvalho Chehab 
7679a0bf528SMauro Carvalho Chehab 	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1);
7689a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(CSM_AUTO_PARAM, reg, 1);
7699a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, reg);
7709a0bf528SMauro Carvalho Chehab }
7719a0bf528SMauro Carvalho Chehab 
7729a0bf528SMauro Carvalho Chehab static long Log2Int(int number)
7739a0bf528SMauro Carvalho Chehab {
7749a0bf528SMauro Carvalho Chehab 	int i;
7759a0bf528SMauro Carvalho Chehab 
7769a0bf528SMauro Carvalho Chehab 	i = 0;
7779a0bf528SMauro Carvalho Chehab 	while ((1 << i) <= abs(number))
7789a0bf528SMauro Carvalho Chehab 		i++;
7799a0bf528SMauro Carvalho Chehab 
7809a0bf528SMauro Carvalho Chehab 	if (number == 0)
7819a0bf528SMauro Carvalho Chehab 		i = 1;
7829a0bf528SMauro Carvalho Chehab 
7839a0bf528SMauro Carvalho Chehab 	return i - 1;
7849a0bf528SMauro Carvalho Chehab }
7859a0bf528SMauro Carvalho Chehab 
7869a0bf528SMauro Carvalho Chehab /*
7879a0bf528SMauro Carvalho Chehab  * stb0899_dvbs2_calc_srate
7889a0bf528SMauro Carvalho Chehab  * compute BTR_NOM_FREQ for the symbol rate
7899a0bf528SMauro Carvalho Chehab  */
7909a0bf528SMauro Carvalho Chehab static u32 stb0899_dvbs2_calc_srate(struct stb0899_state *state)
7919a0bf528SMauro Carvalho Chehab {
7929a0bf528SMauro Carvalho Chehab 	struct stb0899_internal *internal	= &state->internal;
7939a0bf528SMauro Carvalho Chehab 	struct stb0899_config *config		= state->config;
7949a0bf528SMauro Carvalho Chehab 
7959a0bf528SMauro Carvalho Chehab 	u32 dec_ratio, dec_rate, decim, remain, intval, btr_nom_freq;
7969a0bf528SMauro Carvalho Chehab 	u32 master_clk, srate;
7979a0bf528SMauro Carvalho Chehab 
7989a0bf528SMauro Carvalho Chehab 	dec_ratio = (internal->master_clk * 2) / (5 * internal->srate);
7999a0bf528SMauro Carvalho Chehab 	dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio;
8009a0bf528SMauro Carvalho Chehab 	dec_rate = Log2Int(dec_ratio);
8019a0bf528SMauro Carvalho Chehab 	decim = 1 << dec_rate;
8029a0bf528SMauro Carvalho Chehab 	master_clk = internal->master_clk / 1000;
8039a0bf528SMauro Carvalho Chehab 	srate = internal->srate / 1000;
8049a0bf528SMauro Carvalho Chehab 
8059a0bf528SMauro Carvalho Chehab 	if (decim <= 4) {
8069a0bf528SMauro Carvalho Chehab 		intval = (decim * (1 << (config->btr_nco_bits - 1))) / master_clk;
8079a0bf528SMauro Carvalho Chehab 		remain = (decim * (1 << (config->btr_nco_bits - 1))) % master_clk;
8089a0bf528SMauro Carvalho Chehab 	} else {
8099a0bf528SMauro Carvalho Chehab 		intval = (1 << (config->btr_nco_bits - 1)) / (master_clk / 100) * decim / 100;
8109a0bf528SMauro Carvalho Chehab 		remain = (decim * (1 << (config->btr_nco_bits - 1))) % master_clk;
8119a0bf528SMauro Carvalho Chehab 	}
8129a0bf528SMauro Carvalho Chehab 	btr_nom_freq = (intval * srate) + ((remain * srate) / master_clk);
8139a0bf528SMauro Carvalho Chehab 
8149a0bf528SMauro Carvalho Chehab 	return btr_nom_freq;
8159a0bf528SMauro Carvalho Chehab }
8169a0bf528SMauro Carvalho Chehab 
8179a0bf528SMauro Carvalho Chehab /*
8189a0bf528SMauro Carvalho Chehab  * stb0899_dvbs2_calc_dev
8199a0bf528SMauro Carvalho Chehab  * compute the correction to be applied to symbol rate
8209a0bf528SMauro Carvalho Chehab  */
8219a0bf528SMauro Carvalho Chehab static u32 stb0899_dvbs2_calc_dev(struct stb0899_state *state)
8229a0bf528SMauro Carvalho Chehab {
8239a0bf528SMauro Carvalho Chehab 	struct stb0899_internal *internal = &state->internal;
8249a0bf528SMauro Carvalho Chehab 	u32 dec_ratio, correction, master_clk, srate;
8259a0bf528SMauro Carvalho Chehab 
8269a0bf528SMauro Carvalho Chehab 	dec_ratio = (internal->master_clk * 2) / (5 * internal->srate);
8279a0bf528SMauro Carvalho Chehab 	dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio;
8289a0bf528SMauro Carvalho Chehab 
8299a0bf528SMauro Carvalho Chehab 	master_clk = internal->master_clk / 1000;	/* for integer Caculation*/
8309a0bf528SMauro Carvalho Chehab 	srate = internal->srate / 1000;	/* for integer Caculation*/
8319a0bf528SMauro Carvalho Chehab 	correction = (512 * master_clk) / (2 * dec_ratio * srate);
8329a0bf528SMauro Carvalho Chehab 
8339a0bf528SMauro Carvalho Chehab 	return	correction;
8349a0bf528SMauro Carvalho Chehab }
8359a0bf528SMauro Carvalho Chehab 
8369a0bf528SMauro Carvalho Chehab /*
8379a0bf528SMauro Carvalho Chehab  * stb0899_dvbs2_set_srate
8389a0bf528SMauro Carvalho Chehab  * Set DVBS2 symbol rate
8399a0bf528SMauro Carvalho Chehab  */
8409a0bf528SMauro Carvalho Chehab static void stb0899_dvbs2_set_srate(struct stb0899_state *state)
8419a0bf528SMauro Carvalho Chehab {
8429a0bf528SMauro Carvalho Chehab 	struct stb0899_internal *internal = &state->internal;
8439a0bf528SMauro Carvalho Chehab 
8449a0bf528SMauro Carvalho Chehab 	u32 dec_ratio, dec_rate, win_sel, decim, f_sym, btr_nom_freq;
8459a0bf528SMauro Carvalho Chehab 	u32 correction, freq_adj, band_lim, decim_cntrl, reg;
8469a0bf528SMauro Carvalho Chehab 	u8 anti_alias;
8479a0bf528SMauro Carvalho Chehab 
8489a0bf528SMauro Carvalho Chehab 	/*set decimation to 1*/
8499a0bf528SMauro Carvalho Chehab 	dec_ratio = (internal->master_clk * 2) / (5 * internal->srate);
8509a0bf528SMauro Carvalho Chehab 	dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio;
8519a0bf528SMauro Carvalho Chehab 	dec_rate = Log2Int(dec_ratio);
8529a0bf528SMauro Carvalho Chehab 
8539a0bf528SMauro Carvalho Chehab 	win_sel = 0;
8549a0bf528SMauro Carvalho Chehab 	if (dec_rate >= 5)
8559a0bf528SMauro Carvalho Chehab 		win_sel = dec_rate - 4;
8569a0bf528SMauro Carvalho Chehab 
8579a0bf528SMauro Carvalho Chehab 	decim = (1 << dec_rate);
8589a0bf528SMauro Carvalho Chehab 	/* (FSamp/Fsymbol *100) for integer Caculation */
8599a0bf528SMauro Carvalho Chehab 	f_sym = internal->master_clk / ((decim * internal->srate) / 1000);
8609a0bf528SMauro Carvalho Chehab 
8619a0bf528SMauro Carvalho Chehab 	if (f_sym <= 2250)	/* don't band limit signal going into btr block*/
8629a0bf528SMauro Carvalho Chehab 		band_lim = 1;
8639a0bf528SMauro Carvalho Chehab 	else
8649a0bf528SMauro Carvalho Chehab 		band_lim = 0;	/* band limit signal going into btr block*/
8659a0bf528SMauro Carvalho Chehab 
8669a0bf528SMauro Carvalho Chehab 	decim_cntrl = ((win_sel << 3) & 0x18) + ((band_lim << 5) & 0x20) + (dec_rate & 0x7);
8679a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DECIM_CNTRL, STB0899_OFF0_DECIM_CNTRL, decim_cntrl);
8689a0bf528SMauro Carvalho Chehab 
8699a0bf528SMauro Carvalho Chehab 	if (f_sym <= 3450)
8709a0bf528SMauro Carvalho Chehab 		anti_alias = 0;
8719a0bf528SMauro Carvalho Chehab 	else if (f_sym <= 4250)
8729a0bf528SMauro Carvalho Chehab 		anti_alias = 1;
8739a0bf528SMauro Carvalho Chehab 	else
8749a0bf528SMauro Carvalho Chehab 		anti_alias = 2;
8759a0bf528SMauro Carvalho Chehab 
8769a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_ANTI_ALIAS_SEL, STB0899_OFF0_ANTI_ALIAS_SEL, anti_alias);
8779a0bf528SMauro Carvalho Chehab 	btr_nom_freq = stb0899_dvbs2_calc_srate(state);
8789a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_NOM_FREQ, STB0899_OFF0_BTR_NOM_FREQ, btr_nom_freq);
8799a0bf528SMauro Carvalho Chehab 
8809a0bf528SMauro Carvalho Chehab 	correction = stb0899_dvbs2_calc_dev(state);
8819a0bf528SMauro Carvalho Chehab 	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_CNTRL);
8829a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(BTR_FREQ_CORR, reg, correction);
8839a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_CNTRL, STB0899_OFF0_BTR_CNTRL, reg);
8849a0bf528SMauro Carvalho Chehab 
8859a0bf528SMauro Carvalho Chehab 	/* scale UWP+CSM frequency to sample rate*/
8869a0bf528SMauro Carvalho Chehab 	freq_adj =  internal->srate / (internal->master_clk / 4096);
8879a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_FREQ_ADJ_SCALE, STB0899_OFF0_FREQ_ADJ_SCALE, freq_adj);
8889a0bf528SMauro Carvalho Chehab }
8899a0bf528SMauro Carvalho Chehab 
8909a0bf528SMauro Carvalho Chehab /*
8919a0bf528SMauro Carvalho Chehab  * stb0899_dvbs2_set_btr_loopbw
8929a0bf528SMauro Carvalho Chehab  * set bit timing loop bandwidth as a percentage of the symbol rate
8939a0bf528SMauro Carvalho Chehab  */
8949a0bf528SMauro Carvalho Chehab static void stb0899_dvbs2_set_btr_loopbw(struct stb0899_state *state)
8959a0bf528SMauro Carvalho Chehab {
8969a0bf528SMauro Carvalho Chehab 	struct stb0899_internal *internal	= &state->internal;
8979a0bf528SMauro Carvalho Chehab 	struct stb0899_config *config		= state->config;
8989a0bf528SMauro Carvalho Chehab 
8999a0bf528SMauro Carvalho Chehab 	u32 sym_peak = 23, zeta = 707, loopbw_percent = 60;
9009a0bf528SMauro Carvalho Chehab 	s32 dec_ratio, dec_rate, k_btr1_rshft, k_btr1, k_btr0_rshft;
9019a0bf528SMauro Carvalho Chehab 	s32 k_btr0, k_btr2_rshft, k_direct_shift, k_indirect_shift;
9029a0bf528SMauro Carvalho Chehab 	u32 decim, K, wn, k_direct, k_indirect;
9039a0bf528SMauro Carvalho Chehab 	u32 reg;
9049a0bf528SMauro Carvalho Chehab 
9059a0bf528SMauro Carvalho Chehab 	dec_ratio = (internal->master_clk * 2) / (5 * internal->srate);
9069a0bf528SMauro Carvalho Chehab 	dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio;
9079a0bf528SMauro Carvalho Chehab 	dec_rate = Log2Int(dec_ratio);
9089a0bf528SMauro Carvalho Chehab 	decim = (1 << dec_rate);
9099a0bf528SMauro Carvalho Chehab 
9109a0bf528SMauro Carvalho Chehab 	sym_peak *= 576000;
9119a0bf528SMauro Carvalho Chehab 	K = (1 << config->btr_nco_bits) / (internal->master_clk / 1000);
9129a0bf528SMauro Carvalho Chehab 	K *= (internal->srate / 1000000) * decim; /*k=k 10^-8*/
9139a0bf528SMauro Carvalho Chehab 
9149a0bf528SMauro Carvalho Chehab 	if (K != 0) {
9159a0bf528SMauro Carvalho Chehab 		K = sym_peak / K;
9169a0bf528SMauro Carvalho Chehab 		wn = (4 * zeta * zeta) + 1000000;
9179a0bf528SMauro Carvalho Chehab 		wn = (2 * (loopbw_percent * 1000) * 40 * zeta) /wn;  /*wn =wn 10^-8*/
9189a0bf528SMauro Carvalho Chehab 
9199a0bf528SMauro Carvalho Chehab 		k_indirect = (wn * wn) / K;
9209a0bf528SMauro Carvalho Chehab 		k_indirect = k_indirect;	  /*kindirect = kindirect 10^-6*/
9219a0bf528SMauro Carvalho Chehab 		k_direct   = (2 * wn * zeta) / K;	/*kDirect = kDirect 10^-2*/
9229a0bf528SMauro Carvalho Chehab 		k_direct  *= 100;
9239a0bf528SMauro Carvalho Chehab 
9249a0bf528SMauro Carvalho Chehab 		k_direct_shift = Log2Int(k_direct) - Log2Int(10000) - 2;
9259a0bf528SMauro Carvalho Chehab 		k_btr1_rshft = (-1 * k_direct_shift) + config->btr_gain_shift_offset;
9269a0bf528SMauro Carvalho Chehab 		k_btr1 = k_direct / (1 << k_direct_shift);
9279a0bf528SMauro Carvalho Chehab 		k_btr1 /= 10000;
9289a0bf528SMauro Carvalho Chehab 
9299a0bf528SMauro Carvalho Chehab 		k_indirect_shift = Log2Int(k_indirect + 15) - 20 /*- 2*/;
9309a0bf528SMauro Carvalho Chehab 		k_btr0_rshft = (-1 * k_indirect_shift) + config->btr_gain_shift_offset;
9319a0bf528SMauro Carvalho Chehab 		k_btr0 = k_indirect * (1 << (-k_indirect_shift));
9329a0bf528SMauro Carvalho Chehab 		k_btr0 /= 1000000;
9339a0bf528SMauro Carvalho Chehab 
9349a0bf528SMauro Carvalho Chehab 		k_btr2_rshft = 0;
9359a0bf528SMauro Carvalho Chehab 		if (k_btr0_rshft > 15) {
9369a0bf528SMauro Carvalho Chehab 			k_btr2_rshft = k_btr0_rshft - 15;
9379a0bf528SMauro Carvalho Chehab 			k_btr0_rshft = 15;
9389a0bf528SMauro Carvalho Chehab 		}
9399a0bf528SMauro Carvalho Chehab 		reg = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_LOOP_GAIN);
9409a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(KBTR0_RSHFT, reg, k_btr0_rshft);
9419a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(KBTR0, reg, k_btr0);
9429a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(KBTR1_RSHFT, reg, k_btr1_rshft);
9439a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(KBTR1, reg, k_btr1);
9449a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(KBTR2_RSHFT, reg, k_btr2_rshft);
9459a0bf528SMauro Carvalho Chehab 		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_LOOP_GAIN, STB0899_OFF0_BTR_LOOP_GAIN, reg);
9469a0bf528SMauro Carvalho Chehab 	} else
9479a0bf528SMauro Carvalho Chehab 		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_LOOP_GAIN, STB0899_OFF0_BTR_LOOP_GAIN, 0xc4c4f);
9489a0bf528SMauro Carvalho Chehab }
9499a0bf528SMauro Carvalho Chehab 
9509a0bf528SMauro Carvalho Chehab /*
9519a0bf528SMauro Carvalho Chehab  * stb0899_dvbs2_set_carr_freq
9529a0bf528SMauro Carvalho Chehab  * set nominal frequency for carrier search
9539a0bf528SMauro Carvalho Chehab  */
9549a0bf528SMauro Carvalho Chehab static void stb0899_dvbs2_set_carr_freq(struct stb0899_state *state, s32 carr_freq, u32 master_clk)
9559a0bf528SMauro Carvalho Chehab {
9569a0bf528SMauro Carvalho Chehab 	struct stb0899_config *config = state->config;
9579a0bf528SMauro Carvalho Chehab 	s32 crl_nom_freq;
9589a0bf528SMauro Carvalho Chehab 	u32 reg;
9599a0bf528SMauro Carvalho Chehab 
9609a0bf528SMauro Carvalho Chehab 	crl_nom_freq = (1 << config->crl_nco_bits) / master_clk;
9619a0bf528SMauro Carvalho Chehab 	crl_nom_freq *= carr_freq;
9629a0bf528SMauro Carvalho Chehab 	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_NOM_FREQ);
9639a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(CRL_NOM_FREQ, reg, crl_nom_freq);
9649a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_NOM_FREQ, STB0899_OFF0_CRL_NOM_FREQ, reg);
9659a0bf528SMauro Carvalho Chehab }
9669a0bf528SMauro Carvalho Chehab 
9679a0bf528SMauro Carvalho Chehab /*
9689a0bf528SMauro Carvalho Chehab  * stb0899_dvbs2_init_calc
9699a0bf528SMauro Carvalho Chehab  * Initialize DVBS2 UWP, CSM, carrier and timing loops
9709a0bf528SMauro Carvalho Chehab  */
9719a0bf528SMauro Carvalho Chehab static void stb0899_dvbs2_init_calc(struct stb0899_state *state)
9729a0bf528SMauro Carvalho Chehab {
9739a0bf528SMauro Carvalho Chehab 	struct stb0899_internal *internal = &state->internal;
9749a0bf528SMauro Carvalho Chehab 	s32 steps, step_size;
9759a0bf528SMauro Carvalho Chehab 	u32 range, reg;
9769a0bf528SMauro Carvalho Chehab 
9779a0bf528SMauro Carvalho Chehab 	/* config uwp and csm */
9789a0bf528SMauro Carvalho Chehab 	stb0899_dvbs2_config_uwp(state);
9799a0bf528SMauro Carvalho Chehab 	stb0899_dvbs2_config_csm_auto(state);
9809a0bf528SMauro Carvalho Chehab 
9819a0bf528SMauro Carvalho Chehab 	/* initialize BTR	*/
9829a0bf528SMauro Carvalho Chehab 	stb0899_dvbs2_set_srate(state);
9839a0bf528SMauro Carvalho Chehab 	stb0899_dvbs2_set_btr_loopbw(state);
9849a0bf528SMauro Carvalho Chehab 
9859a0bf528SMauro Carvalho Chehab 	if (internal->srate / 1000000 >= 15)
9869a0bf528SMauro Carvalho Chehab 		step_size = (1 << 17) / 5;
9879a0bf528SMauro Carvalho Chehab 	else if (internal->srate / 1000000 >= 10)
9889a0bf528SMauro Carvalho Chehab 		step_size = (1 << 17) / 7;
9899a0bf528SMauro Carvalho Chehab 	else if (internal->srate / 1000000 >= 5)
9909a0bf528SMauro Carvalho Chehab 		step_size = (1 << 17) / 10;
9919a0bf528SMauro Carvalho Chehab 	else
9929a0bf528SMauro Carvalho Chehab 		step_size = (1 << 17) / 4;
9939a0bf528SMauro Carvalho Chehab 
9949a0bf528SMauro Carvalho Chehab 	range = internal->srch_range / 1000000;
9959a0bf528SMauro Carvalho Chehab 	steps = (10 * range * (1 << 17)) / (step_size * (internal->srate / 1000000));
9969a0bf528SMauro Carvalho Chehab 	steps = (steps + 6) / 10;
9979a0bf528SMauro Carvalho Chehab 	steps = (steps == 0) ? 1 : steps;
9989a0bf528SMauro Carvalho Chehab 	if (steps % 2 == 0)
9999a0bf528SMauro Carvalho Chehab 		stb0899_dvbs2_set_carr_freq(state, internal->center_freq -
10009a0bf528SMauro Carvalho Chehab 					   (internal->step_size * (internal->srate / 20000000)),
10019a0bf528SMauro Carvalho Chehab 					   (internal->master_clk) / 1000000);
10029a0bf528SMauro Carvalho Chehab 	else
10039a0bf528SMauro Carvalho Chehab 		stb0899_dvbs2_set_carr_freq(state, internal->center_freq, (internal->master_clk) / 1000000);
10049a0bf528SMauro Carvalho Chehab 
10059a0bf528SMauro Carvalho Chehab 	/*Set Carrier Search params (zigzag, num steps and freq step size*/
10069a0bf528SMauro Carvalho Chehab 	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, ACQ_CNTRL2);
10079a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(ZIGZAG, reg, 1);
10089a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(NUM_STEPS, reg, steps);
10099a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(FREQ_STEPSIZE, reg, step_size);
10109a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_ACQ_CNTRL2, STB0899_OFF0_ACQ_CNTRL2, reg);
10119a0bf528SMauro Carvalho Chehab }
10129a0bf528SMauro Carvalho Chehab 
10139a0bf528SMauro Carvalho Chehab /*
10149a0bf528SMauro Carvalho Chehab  * stb0899_dvbs2_btr_init
10159a0bf528SMauro Carvalho Chehab  * initialize the timing loop
10169a0bf528SMauro Carvalho Chehab  */
10179a0bf528SMauro Carvalho Chehab static void stb0899_dvbs2_btr_init(struct stb0899_state *state)
10189a0bf528SMauro Carvalho Chehab {
10199a0bf528SMauro Carvalho Chehab 	u32 reg;
10209a0bf528SMauro Carvalho Chehab 
10219a0bf528SMauro Carvalho Chehab 	/* set enable BTR loopback	*/
10229a0bf528SMauro Carvalho Chehab 	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_CNTRL);
10239a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(INTRP_PHS_SENSE, reg, 1);
10249a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(BTR_ERR_ENA, reg, 1);
10259a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_CNTRL, STB0899_OFF0_BTR_CNTRL, reg);
10269a0bf528SMauro Carvalho Chehab 
10279a0bf528SMauro Carvalho Chehab 	/* fix btr freq accum at 0	*/
10289a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_FREQ_INIT, STB0899_OFF0_BTR_FREQ_INIT, 0x10000000);
10299a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_FREQ_INIT, STB0899_OFF0_BTR_FREQ_INIT, 0x00000000);
10309a0bf528SMauro Carvalho Chehab 
10319a0bf528SMauro Carvalho Chehab 	/* fix btr freq accum at 0	*/
10329a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_PHS_INIT, STB0899_OFF0_BTR_PHS_INIT, 0x10000000);
10339a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_PHS_INIT, STB0899_OFF0_BTR_PHS_INIT, 0x00000000);
10349a0bf528SMauro Carvalho Chehab }
10359a0bf528SMauro Carvalho Chehab 
10369a0bf528SMauro Carvalho Chehab /*
10379a0bf528SMauro Carvalho Chehab  * stb0899_dvbs2_reacquire
10389a0bf528SMauro Carvalho Chehab  * trigger a DVB-S2 acquisition
10399a0bf528SMauro Carvalho Chehab  */
10409a0bf528SMauro Carvalho Chehab static void stb0899_dvbs2_reacquire(struct stb0899_state *state)
10419a0bf528SMauro Carvalho Chehab {
10429a0bf528SMauro Carvalho Chehab 	u32 reg = 0;
10439a0bf528SMauro Carvalho Chehab 
10449a0bf528SMauro Carvalho Chehab 	/* demod soft reset	*/
10459a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(DVBS2_RESET, reg, 1);
10469a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_RESET_CNTRL, STB0899_OFF0_RESET_CNTRL, reg);
10479a0bf528SMauro Carvalho Chehab 
10489a0bf528SMauro Carvalho Chehab 	/*Reset Timing Loop	*/
10499a0bf528SMauro Carvalho Chehab 	stb0899_dvbs2_btr_init(state);
10509a0bf528SMauro Carvalho Chehab 
10519a0bf528SMauro Carvalho Chehab 	/* reset Carrier loop	*/
10529a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_FREQ_INIT, STB0899_OFF0_CRL_FREQ_INIT, (1 << 30));
10539a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_FREQ_INIT, STB0899_OFF0_CRL_FREQ_INIT, 0);
10549a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_LOOP_GAIN, STB0899_OFF0_CRL_LOOP_GAIN, 0);
10559a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_PHS_INIT, STB0899_OFF0_CRL_PHS_INIT, (1 << 30));
10569a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_PHS_INIT, STB0899_OFF0_CRL_PHS_INIT, 0);
10579a0bf528SMauro Carvalho Chehab 
10589a0bf528SMauro Carvalho Chehab 	/*release demod soft reset	*/
10599a0bf528SMauro Carvalho Chehab 	reg = 0;
10609a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(DVBS2_RESET, reg, 0);
10619a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_RESET_CNTRL, STB0899_OFF0_RESET_CNTRL, reg);
10629a0bf528SMauro Carvalho Chehab 
10639a0bf528SMauro Carvalho Chehab 	/* start acquisition process	*/
10649a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_ACQUIRE_TRIG, STB0899_OFF0_ACQUIRE_TRIG, 1);
10659a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_LOCK_LOST, STB0899_OFF0_LOCK_LOST, 0);
10669a0bf528SMauro Carvalho Chehab 
10679a0bf528SMauro Carvalho Chehab 	/* equalizer Init	*/
10689a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQUALIZER_INIT, STB0899_OFF0_EQUALIZER_INIT, 1);
10699a0bf528SMauro Carvalho Chehab 
10709a0bf528SMauro Carvalho Chehab 	/*Start equilizer	*/
10719a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQUALIZER_INIT, STB0899_OFF0_EQUALIZER_INIT, 0);
10729a0bf528SMauro Carvalho Chehab 
10739a0bf528SMauro Carvalho Chehab 	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, EQ_CNTRL);
10749a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(EQ_SHIFT, reg, 0);
10759a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(EQ_DISABLE_UPDATE, reg, 0);
10769a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(EQ_DELAY, reg, 0x05);
10779a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(EQ_ADAPT_MODE, reg, 0x01);
10789a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQ_CNTRL, STB0899_OFF0_EQ_CNTRL, reg);
10799a0bf528SMauro Carvalho Chehab 
10809a0bf528SMauro Carvalho Chehab 	/* RESET Packet delineator	*/
10819a0bf528SMauro Carvalho Chehab 	stb0899_write_reg(state, STB0899_PDELCTRL, 0x4a);
10829a0bf528SMauro Carvalho Chehab }
10839a0bf528SMauro Carvalho Chehab 
10849a0bf528SMauro Carvalho Chehab /*
10859a0bf528SMauro Carvalho Chehab  * stb0899_dvbs2_get_dmd_status
10869a0bf528SMauro Carvalho Chehab  * get DVB-S2 Demod LOCK status
10879a0bf528SMauro Carvalho Chehab  */
10889a0bf528SMauro Carvalho Chehab static enum stb0899_status stb0899_dvbs2_get_dmd_status(struct stb0899_state *state, int timeout)
10899a0bf528SMauro Carvalho Chehab {
10909a0bf528SMauro Carvalho Chehab 	int time = -10, lock = 0, uwp, csm;
10919a0bf528SMauro Carvalho Chehab 	u32 reg;
10929a0bf528SMauro Carvalho Chehab 
10939a0bf528SMauro Carvalho Chehab 	do {
10949a0bf528SMauro Carvalho Chehab 		reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_STATUS);
10959a0bf528SMauro Carvalho Chehab 		dprintk(state->verbose, FE_DEBUG, 1, "DMD_STATUS=[0x%02x]", reg);
10969a0bf528SMauro Carvalho Chehab 		if (STB0899_GETFIELD(IF_AGC_LOCK, reg))
10979a0bf528SMauro Carvalho Chehab 			dprintk(state->verbose, FE_DEBUG, 1, "------------->IF AGC LOCKED !");
10989a0bf528SMauro Carvalho Chehab 		reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_STAT2);
10999a0bf528SMauro Carvalho Chehab 		dprintk(state->verbose, FE_DEBUG, 1, "----------->DMD STAT2=[0x%02x]", reg);
11009a0bf528SMauro Carvalho Chehab 		uwp = STB0899_GETFIELD(UWP_LOCK, reg);
11019a0bf528SMauro Carvalho Chehab 		csm = STB0899_GETFIELD(CSM_LOCK, reg);
11029a0bf528SMauro Carvalho Chehab 		if (uwp && csm)
11039a0bf528SMauro Carvalho Chehab 			lock = 1;
11049a0bf528SMauro Carvalho Chehab 
11059a0bf528SMauro Carvalho Chehab 		time += 10;
11069a0bf528SMauro Carvalho Chehab 		msleep(10);
11079a0bf528SMauro Carvalho Chehab 
11089a0bf528SMauro Carvalho Chehab 	} while ((!lock) && (time <= timeout));
11099a0bf528SMauro Carvalho Chehab 
11109a0bf528SMauro Carvalho Chehab 	if (lock) {
11119a0bf528SMauro Carvalho Chehab 		dprintk(state->verbose, FE_DEBUG, 1, "----------------> DVB-S2 LOCK !");
11129a0bf528SMauro Carvalho Chehab 		return DVBS2_DEMOD_LOCK;
11139a0bf528SMauro Carvalho Chehab 	} else {
11149a0bf528SMauro Carvalho Chehab 		return DVBS2_DEMOD_NOLOCK;
11159a0bf528SMauro Carvalho Chehab 	}
11169a0bf528SMauro Carvalho Chehab }
11179a0bf528SMauro Carvalho Chehab 
11189a0bf528SMauro Carvalho Chehab /*
11199a0bf528SMauro Carvalho Chehab  * stb0899_dvbs2_get_data_lock
11209a0bf528SMauro Carvalho Chehab  * get FEC status
11219a0bf528SMauro Carvalho Chehab  */
11229a0bf528SMauro Carvalho Chehab static int stb0899_dvbs2_get_data_lock(struct stb0899_state *state, int timeout)
11239a0bf528SMauro Carvalho Chehab {
11249a0bf528SMauro Carvalho Chehab 	int time = 0, lock = 0;
11259a0bf528SMauro Carvalho Chehab 	u8 reg;
11269a0bf528SMauro Carvalho Chehab 
11279a0bf528SMauro Carvalho Chehab 	while ((!lock) && (time < timeout)) {
11289a0bf528SMauro Carvalho Chehab 		reg = stb0899_read_reg(state, STB0899_CFGPDELSTATUS1);
11299a0bf528SMauro Carvalho Chehab 		dprintk(state->verbose, FE_DEBUG, 1, "---------> CFGPDELSTATUS=[0x%02x]", reg);
11309a0bf528SMauro Carvalho Chehab 		lock = STB0899_GETFIELD(CFGPDELSTATUS_LOCK, reg);
11319a0bf528SMauro Carvalho Chehab 		time++;
11329a0bf528SMauro Carvalho Chehab 	}
11339a0bf528SMauro Carvalho Chehab 
11349a0bf528SMauro Carvalho Chehab 	return lock;
11359a0bf528SMauro Carvalho Chehab }
11369a0bf528SMauro Carvalho Chehab 
11379a0bf528SMauro Carvalho Chehab /*
11389a0bf528SMauro Carvalho Chehab  * stb0899_dvbs2_get_fec_status
11399a0bf528SMauro Carvalho Chehab  * get DVB-S2 FEC LOCK status
11409a0bf528SMauro Carvalho Chehab  */
11419a0bf528SMauro Carvalho Chehab static enum stb0899_status stb0899_dvbs2_get_fec_status(struct stb0899_state *state, int timeout)
11429a0bf528SMauro Carvalho Chehab {
11439a0bf528SMauro Carvalho Chehab 	int time = 0, Locked;
11449a0bf528SMauro Carvalho Chehab 
11459a0bf528SMauro Carvalho Chehab 	do {
11469a0bf528SMauro Carvalho Chehab 		Locked = stb0899_dvbs2_get_data_lock(state, 1);
11479a0bf528SMauro Carvalho Chehab 		time++;
11489a0bf528SMauro Carvalho Chehab 		msleep(1);
11499a0bf528SMauro Carvalho Chehab 
11509a0bf528SMauro Carvalho Chehab 	} while ((!Locked) && (time < timeout));
11519a0bf528SMauro Carvalho Chehab 
11529a0bf528SMauro Carvalho Chehab 	if (Locked) {
11539a0bf528SMauro Carvalho Chehab 		dprintk(state->verbose, FE_DEBUG, 1, "---------->DVB-S2 FEC LOCK !");
11549a0bf528SMauro Carvalho Chehab 		return DVBS2_FEC_LOCK;
11559a0bf528SMauro Carvalho Chehab 	} else {
11569a0bf528SMauro Carvalho Chehab 		return DVBS2_FEC_NOLOCK;
11579a0bf528SMauro Carvalho Chehab 	}
11589a0bf528SMauro Carvalho Chehab }
11599a0bf528SMauro Carvalho Chehab 
11609a0bf528SMauro Carvalho Chehab 
11619a0bf528SMauro Carvalho Chehab /*
11629a0bf528SMauro Carvalho Chehab  * stb0899_dvbs2_init_csm
11639a0bf528SMauro Carvalho Chehab  * set parameters for manual mode
11649a0bf528SMauro Carvalho Chehab  */
11659a0bf528SMauro Carvalho Chehab static void stb0899_dvbs2_init_csm(struct stb0899_state *state, int pilots, enum stb0899_modcod modcod)
11669a0bf528SMauro Carvalho Chehab {
11679a0bf528SMauro Carvalho Chehab 	struct stb0899_internal *internal = &state->internal;
11689a0bf528SMauro Carvalho Chehab 
11699a0bf528SMauro Carvalho Chehab 	s32 dvt_tbl = 1, two_pass = 0, agc_gain = 6, agc_shift = 0, loop_shift = 0, phs_diff_thr = 0x80;
11709a0bf528SMauro Carvalho Chehab 	s32 gamma_acq, gamma_rho_acq, gamma_trk, gamma_rho_trk, lock_count_thr;
11719a0bf528SMauro Carvalho Chehab 	u32 csm1, csm2, csm3, csm4;
11729a0bf528SMauro Carvalho Chehab 
11739a0bf528SMauro Carvalho Chehab 	if (((internal->master_clk / internal->srate) <= 4) && (modcod <= 11) && (pilots == 1)) {
11749a0bf528SMauro Carvalho Chehab 		switch (modcod) {
11759a0bf528SMauro Carvalho Chehab 		case STB0899_QPSK_12:
11769a0bf528SMauro Carvalho Chehab 			gamma_acq		= 25;
11779a0bf528SMauro Carvalho Chehab 			gamma_rho_acq		= 2700;
11789a0bf528SMauro Carvalho Chehab 			gamma_trk		= 12;
11799a0bf528SMauro Carvalho Chehab 			gamma_rho_trk		= 180;
11809a0bf528SMauro Carvalho Chehab 			lock_count_thr		= 8;
11819a0bf528SMauro Carvalho Chehab 			break;
11829a0bf528SMauro Carvalho Chehab 		case STB0899_QPSK_35:
11839a0bf528SMauro Carvalho Chehab 			gamma_acq		= 38;
11849a0bf528SMauro Carvalho Chehab 			gamma_rho_acq		= 7182;
11859a0bf528SMauro Carvalho Chehab 			gamma_trk		= 14;
11869a0bf528SMauro Carvalho Chehab 			gamma_rho_trk		= 308;
11879a0bf528SMauro Carvalho Chehab 			lock_count_thr		= 8;
11889a0bf528SMauro Carvalho Chehab 			break;
11899a0bf528SMauro Carvalho Chehab 		case STB0899_QPSK_23:
11909a0bf528SMauro Carvalho Chehab 			gamma_acq		= 42;
11919a0bf528SMauro Carvalho Chehab 			gamma_rho_acq		= 9408;
11929a0bf528SMauro Carvalho Chehab 			gamma_trk		= 17;
11939a0bf528SMauro Carvalho Chehab 			gamma_rho_trk		= 476;
11949a0bf528SMauro Carvalho Chehab 			lock_count_thr		= 8;
11959a0bf528SMauro Carvalho Chehab 			break;
11969a0bf528SMauro Carvalho Chehab 		case STB0899_QPSK_34:
11979a0bf528SMauro Carvalho Chehab 			gamma_acq		= 53;
11989a0bf528SMauro Carvalho Chehab 			gamma_rho_acq		= 16642;
11999a0bf528SMauro Carvalho Chehab 			gamma_trk		= 19;
12009a0bf528SMauro Carvalho Chehab 			gamma_rho_trk		= 646;
12019a0bf528SMauro Carvalho Chehab 			lock_count_thr		= 8;
12029a0bf528SMauro Carvalho Chehab 			break;
12039a0bf528SMauro Carvalho Chehab 		case STB0899_QPSK_45:
12049a0bf528SMauro Carvalho Chehab 			gamma_acq		= 53;
12059a0bf528SMauro Carvalho Chehab 			gamma_rho_acq		= 17119;
12069a0bf528SMauro Carvalho Chehab 			gamma_trk		= 22;
12079a0bf528SMauro Carvalho Chehab 			gamma_rho_trk		= 880;
12089a0bf528SMauro Carvalho Chehab 			lock_count_thr		= 8;
12099a0bf528SMauro Carvalho Chehab 			break;
12109a0bf528SMauro Carvalho Chehab 		case STB0899_QPSK_56:
12119a0bf528SMauro Carvalho Chehab 			gamma_acq		= 55;
12129a0bf528SMauro Carvalho Chehab 			gamma_rho_acq		= 19250;
12139a0bf528SMauro Carvalho Chehab 			gamma_trk		= 23;
12149a0bf528SMauro Carvalho Chehab 			gamma_rho_trk		= 989;
12159a0bf528SMauro Carvalho Chehab 			lock_count_thr		= 8;
12169a0bf528SMauro Carvalho Chehab 			break;
12179a0bf528SMauro Carvalho Chehab 		case STB0899_QPSK_89:
12189a0bf528SMauro Carvalho Chehab 			gamma_acq		= 60;
12199a0bf528SMauro Carvalho Chehab 			gamma_rho_acq		= 24240;
12209a0bf528SMauro Carvalho Chehab 			gamma_trk		= 24;
12219a0bf528SMauro Carvalho Chehab 			gamma_rho_trk		= 1176;
12229a0bf528SMauro Carvalho Chehab 			lock_count_thr		= 8;
12239a0bf528SMauro Carvalho Chehab 			break;
12249a0bf528SMauro Carvalho Chehab 		case STB0899_QPSK_910:
12259a0bf528SMauro Carvalho Chehab 			gamma_acq		= 66;
12269a0bf528SMauro Carvalho Chehab 			gamma_rho_acq		= 29634;
12279a0bf528SMauro Carvalho Chehab 			gamma_trk		= 24;
12289a0bf528SMauro Carvalho Chehab 			gamma_rho_trk		= 1176;
12299a0bf528SMauro Carvalho Chehab 			lock_count_thr		= 8;
12309a0bf528SMauro Carvalho Chehab 			break;
12319a0bf528SMauro Carvalho Chehab 		default:
12329a0bf528SMauro Carvalho Chehab 			gamma_acq		= 66;
12339a0bf528SMauro Carvalho Chehab 			gamma_rho_acq		= 29634;
12349a0bf528SMauro Carvalho Chehab 			gamma_trk		= 24;
12359a0bf528SMauro Carvalho Chehab 			gamma_rho_trk		= 1176;
12369a0bf528SMauro Carvalho Chehab 			lock_count_thr		= 8;
12379a0bf528SMauro Carvalho Chehab 			break;
12389a0bf528SMauro Carvalho Chehab 		}
12399a0bf528SMauro Carvalho Chehab 
12409a0bf528SMauro Carvalho Chehab 		csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1);
12419a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(CSM_AUTO_PARAM, csm1, 0);
12429a0bf528SMauro Carvalho Chehab 		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1);
12439a0bf528SMauro Carvalho Chehab 
12449a0bf528SMauro Carvalho Chehab 		csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1);
12459a0bf528SMauro Carvalho Chehab 		csm2 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL2);
12469a0bf528SMauro Carvalho Chehab 		csm3 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL3);
12479a0bf528SMauro Carvalho Chehab 		csm4 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL4);
12489a0bf528SMauro Carvalho Chehab 
12499a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(CSM_DVT_TABLE, csm1, dvt_tbl);
12509a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(CSM_TWO_PASS, csm1, two_pass);
12519a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(CSM_AGC_GAIN, csm1, agc_gain);
12529a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(CSM_AGC_SHIFT, csm1, agc_shift);
12539a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(FE_LOOP_SHIFT, csm1, loop_shift);
12549a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(CSM_GAMMA_ACQ, csm2, gamma_acq);
12559a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(CSM_GAMMA_RHOACQ, csm2, gamma_rho_acq);
12569a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(CSM_GAMMA_TRACK, csm3, gamma_trk);
12579a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(CSM_GAMMA_RHOTRACK, csm3, gamma_rho_trk);
12589a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(CSM_LOCKCOUNT_THRESH, csm4, lock_count_thr);
12599a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(CSM_PHASEDIFF_THRESH, csm4, phs_diff_thr);
12609a0bf528SMauro Carvalho Chehab 
12619a0bf528SMauro Carvalho Chehab 		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1);
12629a0bf528SMauro Carvalho Chehab 		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL2, STB0899_OFF0_CSM_CNTRL2, csm2);
12639a0bf528SMauro Carvalho Chehab 		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL3, STB0899_OFF0_CSM_CNTRL3, csm3);
12649a0bf528SMauro Carvalho Chehab 		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL4, STB0899_OFF0_CSM_CNTRL4, csm4);
12659a0bf528SMauro Carvalho Chehab 	}
12669a0bf528SMauro Carvalho Chehab }
12679a0bf528SMauro Carvalho Chehab 
12689a0bf528SMauro Carvalho Chehab /*
12699a0bf528SMauro Carvalho Chehab  * stb0899_dvbs2_get_srate
12709a0bf528SMauro Carvalho Chehab  * get DVB-S2 Symbol Rate
12719a0bf528SMauro Carvalho Chehab  */
12729a0bf528SMauro Carvalho Chehab static u32 stb0899_dvbs2_get_srate(struct stb0899_state *state)
12739a0bf528SMauro Carvalho Chehab {
12749a0bf528SMauro Carvalho Chehab 	struct stb0899_internal *internal = &state->internal;
12759a0bf528SMauro Carvalho Chehab 	struct stb0899_config *config = state->config;
12769a0bf528SMauro Carvalho Chehab 
12779a0bf528SMauro Carvalho Chehab 	u32 bTrNomFreq, srate, decimRate, intval1, intval2, reg;
12789a0bf528SMauro Carvalho Chehab 	int div1, div2, rem1, rem2;
12799a0bf528SMauro Carvalho Chehab 
12809a0bf528SMauro Carvalho Chehab 	div1 = config->btr_nco_bits / 2;
12819a0bf528SMauro Carvalho Chehab 	div2 = config->btr_nco_bits - div1 - 1;
12829a0bf528SMauro Carvalho Chehab 
12839a0bf528SMauro Carvalho Chehab 	bTrNomFreq = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_NOM_FREQ);
12849a0bf528SMauro Carvalho Chehab 
12859a0bf528SMauro Carvalho Chehab 	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DECIM_CNTRL);
12869a0bf528SMauro Carvalho Chehab 	decimRate = STB0899_GETFIELD(DECIM_RATE, reg);
12879a0bf528SMauro Carvalho Chehab 	decimRate = (1 << decimRate);
12889a0bf528SMauro Carvalho Chehab 
12899a0bf528SMauro Carvalho Chehab 	intval1 = internal->master_clk / (1 << div1);
12909a0bf528SMauro Carvalho Chehab 	intval2 = bTrNomFreq / (1 << div2);
12919a0bf528SMauro Carvalho Chehab 
12929a0bf528SMauro Carvalho Chehab 	rem1 = internal->master_clk % (1 << div1);
12939a0bf528SMauro Carvalho Chehab 	rem2 = bTrNomFreq % (1 << div2);
12949a0bf528SMauro Carvalho Chehab 	/* only for integer calculation	*/
12959a0bf528SMauro Carvalho Chehab 	srate = (intval1 * intval2) + ((intval1 * rem2) / (1 << div2)) + ((intval2 * rem1) / (1 << div1));
12969a0bf528SMauro Carvalho Chehab 	srate /= decimRate;	/*symbrate = (btrnomfreq_register_val*MasterClock)/2^(27+decim_rate_field) */
12979a0bf528SMauro Carvalho Chehab 
12989a0bf528SMauro Carvalho Chehab 	return	srate;
12999a0bf528SMauro Carvalho Chehab }
13009a0bf528SMauro Carvalho Chehab 
13019a0bf528SMauro Carvalho Chehab /*
13029a0bf528SMauro Carvalho Chehab  * stb0899_dvbs2_algo
13039a0bf528SMauro Carvalho Chehab  * Search for signal, timing, carrier and data for a given
13049a0bf528SMauro Carvalho Chehab  * frequency in a given range
13059a0bf528SMauro Carvalho Chehab  */
13069a0bf528SMauro Carvalho Chehab enum stb0899_status stb0899_dvbs2_algo(struct stb0899_state *state)
13079a0bf528SMauro Carvalho Chehab {
13089a0bf528SMauro Carvalho Chehab 	struct stb0899_internal *internal = &state->internal;
13099a0bf528SMauro Carvalho Chehab 	enum stb0899_modcod modcod;
13109a0bf528SMauro Carvalho Chehab 
13119a0bf528SMauro Carvalho Chehab 	s32 offsetfreq, searchTime, FecLockTime, pilots, iqSpectrum;
13129a0bf528SMauro Carvalho Chehab 	int i = 0;
13139a0bf528SMauro Carvalho Chehab 	u32 reg, csm1;
13149a0bf528SMauro Carvalho Chehab 
13159a0bf528SMauro Carvalho Chehab 	if (internal->srate <= 2000000) {
13169a0bf528SMauro Carvalho Chehab 		searchTime	= 5000;	/* 5000 ms max time to lock UWP and CSM, SYMB <= 2Mbs		*/
13179a0bf528SMauro Carvalho Chehab 		FecLockTime	= 350;	/* 350  ms max time to lock FEC, SYMB <= 2Mbs			*/
13189a0bf528SMauro Carvalho Chehab 	} else if (internal->srate <= 5000000) {
13199a0bf528SMauro Carvalho Chehab 		searchTime	= 2500;	/* 2500 ms max time to lock UWP and CSM, 2Mbs < SYMB <= 5Mbs	*/
13209a0bf528SMauro Carvalho Chehab 		FecLockTime	= 170;	/* 170  ms max time to lock FEC, 2Mbs< SYMB <= 5Mbs		*/
13219a0bf528SMauro Carvalho Chehab 	} else if (internal->srate <= 10000000) {
13229a0bf528SMauro Carvalho Chehab 		searchTime	= 1500;	/* 1500 ms max time to lock UWP and CSM, 5Mbs <SYMB <= 10Mbs	*/
13239a0bf528SMauro Carvalho Chehab 		FecLockTime	= 80;	/* 80  ms max time to lock FEC, 5Mbs< SYMB <= 10Mbs		*/
13249a0bf528SMauro Carvalho Chehab 	} else if (internal->srate <= 15000000) {
13259a0bf528SMauro Carvalho Chehab 		searchTime	= 500;	/* 500 ms max time to lock UWP and CSM, 10Mbs <SYMB <= 15Mbs	*/
13269a0bf528SMauro Carvalho Chehab 		FecLockTime	= 50;	/* 50  ms max time to lock FEC, 10Mbs< SYMB <= 15Mbs		*/
13279a0bf528SMauro Carvalho Chehab 	} else if (internal->srate <= 20000000) {
13289a0bf528SMauro Carvalho Chehab 		searchTime	= 300;	/* 300 ms max time to lock UWP and CSM, 15Mbs < SYMB <= 20Mbs	*/
13299a0bf528SMauro Carvalho Chehab 		FecLockTime	= 30;	/* 50  ms max time to lock FEC, 15Mbs< SYMB <= 20Mbs		*/
13309a0bf528SMauro Carvalho Chehab 	} else if (internal->srate <= 25000000) {
13319a0bf528SMauro Carvalho Chehab 		searchTime	= 250;	/* 250 ms max time to lock UWP and CSM, 20 Mbs < SYMB <= 25Mbs	*/
13329a0bf528SMauro Carvalho Chehab 		FecLockTime	= 25;	/* 25 ms max time to lock FEC, 20Mbs< SYMB <= 25Mbs		*/
13339a0bf528SMauro Carvalho Chehab 	} else {
13349a0bf528SMauro Carvalho Chehab 		searchTime	= 150;	/* 150 ms max time to lock UWP and CSM, SYMB > 25Mbs		*/
13359a0bf528SMauro Carvalho Chehab 		FecLockTime	= 20;	/* 20 ms max time to lock FEC, 20Mbs< SYMB <= 25Mbs		*/
13369a0bf528SMauro Carvalho Chehab 	}
13379a0bf528SMauro Carvalho Chehab 
13389a0bf528SMauro Carvalho Chehab 	/* Maintain Stream Merger in reset during acquisition	*/
13399a0bf528SMauro Carvalho Chehab 	reg = stb0899_read_reg(state, STB0899_TSTRES);
13409a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(FRESRS, reg, 1);
13419a0bf528SMauro Carvalho Chehab 	stb0899_write_reg(state, STB0899_TSTRES, reg);
13429a0bf528SMauro Carvalho Chehab 
13439a0bf528SMauro Carvalho Chehab 	/* enable tuner I/O */
13449a0bf528SMauro Carvalho Chehab 	stb0899_i2c_gate_ctrl(&state->frontend, 1);
13459a0bf528SMauro Carvalho Chehab 
13469a0bf528SMauro Carvalho Chehab 	/* Move tuner to frequency	*/
13479a0bf528SMauro Carvalho Chehab 	if (state->config->tuner_set_frequency)
13489a0bf528SMauro Carvalho Chehab 		state->config->tuner_set_frequency(&state->frontend, internal->freq);
13499a0bf528SMauro Carvalho Chehab 	if (state->config->tuner_get_frequency)
13509a0bf528SMauro Carvalho Chehab 		state->config->tuner_get_frequency(&state->frontend, &internal->freq);
13519a0bf528SMauro Carvalho Chehab 
13529a0bf528SMauro Carvalho Chehab 	/* disable tuner I/O */
13539a0bf528SMauro Carvalho Chehab 	stb0899_i2c_gate_ctrl(&state->frontend, 0);
13549a0bf528SMauro Carvalho Chehab 
13559a0bf528SMauro Carvalho Chehab 	/* Set IF AGC to acquisition	*/
13569a0bf528SMauro Carvalho Chehab 	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL);
13579a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(IF_LOOP_GAIN, reg,  4);
13589a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(IF_AGC_REF, reg, 32);
13599a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL, STB0899_OFF0_IF_AGC_CNTRL, reg);
13609a0bf528SMauro Carvalho Chehab 
13619a0bf528SMauro Carvalho Chehab 	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL2);
13629a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(IF_AGC_DUMP_PER, reg, 0);
13639a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL2, STB0899_OFF0_IF_AGC_CNTRL2, reg);
13649a0bf528SMauro Carvalho Chehab 
13659a0bf528SMauro Carvalho Chehab 	/* Initialisation	*/
13669a0bf528SMauro Carvalho Chehab 	stb0899_dvbs2_init_calc(state);
13679a0bf528SMauro Carvalho Chehab 
13689a0bf528SMauro Carvalho Chehab 	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2);
13699a0bf528SMauro Carvalho Chehab 	switch (internal->inversion) {
13709a0bf528SMauro Carvalho Chehab 	case IQ_SWAP_OFF:
13719a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, 0);
13729a0bf528SMauro Carvalho Chehab 		break;
13739a0bf528SMauro Carvalho Chehab 	case IQ_SWAP_ON:
13749a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, 1);
13759a0bf528SMauro Carvalho Chehab 		break;
13769a0bf528SMauro Carvalho Chehab 	case IQ_SWAP_AUTO:	/* use last successful search first	*/
13779a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, 1);
13789a0bf528SMauro Carvalho Chehab 		break;
13799a0bf528SMauro Carvalho Chehab 	}
13809a0bf528SMauro Carvalho Chehab 	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DMD_CNTRL2, STB0899_OFF0_DMD_CNTRL2, reg);
13819a0bf528SMauro Carvalho Chehab 	stb0899_dvbs2_reacquire(state);
13829a0bf528SMauro Carvalho Chehab 
13839a0bf528SMauro Carvalho Chehab 	/* Wait for demod lock (UWP and CSM)	*/
13849a0bf528SMauro Carvalho Chehab 	internal->status = stb0899_dvbs2_get_dmd_status(state, searchTime);
13859a0bf528SMauro Carvalho Chehab 
13869a0bf528SMauro Carvalho Chehab 	if (internal->status == DVBS2_DEMOD_LOCK) {
13879a0bf528SMauro Carvalho Chehab 		dprintk(state->verbose, FE_DEBUG, 1, "------------> DVB-S2 DEMOD LOCK !");
13889a0bf528SMauro Carvalho Chehab 		i = 0;
13899a0bf528SMauro Carvalho Chehab 		/* Demod Locked, check FEC status	*/
13909a0bf528SMauro Carvalho Chehab 		internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime);
13919a0bf528SMauro Carvalho Chehab 
13929a0bf528SMauro Carvalho Chehab 		/*If false lock (UWP and CSM Locked but no FEC) try 3 time max*/
13939a0bf528SMauro Carvalho Chehab 		while ((internal->status != DVBS2_FEC_LOCK) && (i < 3)) {
13949a0bf528SMauro Carvalho Chehab 			/*	Read the frequency offset*/
13959a0bf528SMauro Carvalho Chehab 			offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ);
13969a0bf528SMauro Carvalho Chehab 
13979a0bf528SMauro Carvalho Chehab 			/* Set the Nominal frequency to the found frequency offset for the next reacquire*/
13989a0bf528SMauro Carvalho Chehab 			reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_NOM_FREQ);
13999a0bf528SMauro Carvalho Chehab 			STB0899_SETFIELD_VAL(CRL_NOM_FREQ, reg, offsetfreq);
14009a0bf528SMauro Carvalho Chehab 			stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_NOM_FREQ, STB0899_OFF0_CRL_NOM_FREQ, reg);
14019a0bf528SMauro Carvalho Chehab 			stb0899_dvbs2_reacquire(state);
14029a0bf528SMauro Carvalho Chehab 			internal->status = stb0899_dvbs2_get_fec_status(state, searchTime);
14039a0bf528SMauro Carvalho Chehab 			i++;
14049a0bf528SMauro Carvalho Chehab 		}
14059a0bf528SMauro Carvalho Chehab 	}
14069a0bf528SMauro Carvalho Chehab 
14079a0bf528SMauro Carvalho Chehab 	if (internal->status != DVBS2_FEC_LOCK) {
14089a0bf528SMauro Carvalho Chehab 		if (internal->inversion == IQ_SWAP_AUTO) {
14099a0bf528SMauro Carvalho Chehab 			reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2);
14109a0bf528SMauro Carvalho Chehab 			iqSpectrum = STB0899_GETFIELD(SPECTRUM_INVERT, reg);
14119a0bf528SMauro Carvalho Chehab 			/* IQ Spectrum Inversion	*/
14129a0bf528SMauro Carvalho Chehab 			STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, !iqSpectrum);
14139a0bf528SMauro Carvalho Chehab 			stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DMD_CNTRL2, STB0899_OFF0_DMD_CNTRL2, reg);
14149a0bf528SMauro Carvalho Chehab 			/* start acquistion process	*/
14159a0bf528SMauro Carvalho Chehab 			stb0899_dvbs2_reacquire(state);
14169a0bf528SMauro Carvalho Chehab 
14179a0bf528SMauro Carvalho Chehab 			/* Wait for demod lock (UWP and CSM)	*/
14189a0bf528SMauro Carvalho Chehab 			internal->status = stb0899_dvbs2_get_dmd_status(state, searchTime);
14199a0bf528SMauro Carvalho Chehab 			if (internal->status == DVBS2_DEMOD_LOCK) {
14209a0bf528SMauro Carvalho Chehab 				i = 0;
14219a0bf528SMauro Carvalho Chehab 				/* Demod Locked, check FEC	*/
14229a0bf528SMauro Carvalho Chehab 				internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime);
14239a0bf528SMauro Carvalho Chehab 				/*try thrice for false locks, (UWP and CSM Locked but no FEC)	*/
14249a0bf528SMauro Carvalho Chehab 				while ((internal->status != DVBS2_FEC_LOCK) && (i < 3)) {
14259a0bf528SMauro Carvalho Chehab 					/*	Read the frequency offset*/
14269a0bf528SMauro Carvalho Chehab 					offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ);
14279a0bf528SMauro Carvalho Chehab 
14289a0bf528SMauro Carvalho Chehab 					/* Set the Nominal frequency to the found frequency offset for the next reacquire*/
14299a0bf528SMauro Carvalho Chehab 					reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_NOM_FREQ);
14309a0bf528SMauro Carvalho Chehab 					STB0899_SETFIELD_VAL(CRL_NOM_FREQ, reg, offsetfreq);
14319a0bf528SMauro Carvalho Chehab 					stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_NOM_FREQ, STB0899_OFF0_CRL_NOM_FREQ, reg);
14329a0bf528SMauro Carvalho Chehab 
14339a0bf528SMauro Carvalho Chehab 					stb0899_dvbs2_reacquire(state);
14349a0bf528SMauro Carvalho Chehab 					internal->status = stb0899_dvbs2_get_fec_status(state, searchTime);
14359a0bf528SMauro Carvalho Chehab 					i++;
14369a0bf528SMauro Carvalho Chehab 				}
14379a0bf528SMauro Carvalho Chehab 			}
14389a0bf528SMauro Carvalho Chehab /*
14399a0bf528SMauro Carvalho Chehab 			if (pParams->DVBS2State == FE_DVBS2_FEC_LOCKED)
14409a0bf528SMauro Carvalho Chehab 				pParams->IQLocked = !iqSpectrum;
14419a0bf528SMauro Carvalho Chehab */
14429a0bf528SMauro Carvalho Chehab 		}
14439a0bf528SMauro Carvalho Chehab 	}
14449a0bf528SMauro Carvalho Chehab 	if (internal->status == DVBS2_FEC_LOCK) {
14459a0bf528SMauro Carvalho Chehab 		dprintk(state->verbose, FE_DEBUG, 1, "----------------> DVB-S2 FEC Lock !");
14469a0bf528SMauro Carvalho Chehab 		reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_STAT2);
14479a0bf528SMauro Carvalho Chehab 		modcod = STB0899_GETFIELD(UWP_DECODE_MOD, reg) >> 2;
14489a0bf528SMauro Carvalho Chehab 		pilots = STB0899_GETFIELD(UWP_DECODE_MOD, reg) & 0x01;
14499a0bf528SMauro Carvalho Chehab 
14509a0bf528SMauro Carvalho Chehab 		if ((((10 * internal->master_clk) / (internal->srate / 10)) <= 410) &&
14519a0bf528SMauro Carvalho Chehab 		      (INRANGE(STB0899_QPSK_23, modcod, STB0899_QPSK_910)) &&
14529a0bf528SMauro Carvalho Chehab 		      (pilots == 1)) {
14539a0bf528SMauro Carvalho Chehab 
14549a0bf528SMauro Carvalho Chehab 			stb0899_dvbs2_init_csm(state, pilots, modcod);
14559a0bf528SMauro Carvalho Chehab 			/* Wait for UWP,CSM and data LOCK 20ms max	*/
14569a0bf528SMauro Carvalho Chehab 			internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime);
14579a0bf528SMauro Carvalho Chehab 
14589a0bf528SMauro Carvalho Chehab 			i = 0;
14599a0bf528SMauro Carvalho Chehab 			while ((internal->status != DVBS2_FEC_LOCK) && (i < 3)) {
14609a0bf528SMauro Carvalho Chehab 				csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1);
14619a0bf528SMauro Carvalho Chehab 				STB0899_SETFIELD_VAL(CSM_TWO_PASS, csm1, 1);
14629a0bf528SMauro Carvalho Chehab 				stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1);
14639a0bf528SMauro Carvalho Chehab 				csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1);
14649a0bf528SMauro Carvalho Chehab 				STB0899_SETFIELD_VAL(CSM_TWO_PASS, csm1, 0);
14659a0bf528SMauro Carvalho Chehab 				stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1);
14669a0bf528SMauro Carvalho Chehab 
14679a0bf528SMauro Carvalho Chehab 				internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime);
14689a0bf528SMauro Carvalho Chehab 				i++;
14699a0bf528SMauro Carvalho Chehab 			}
14709a0bf528SMauro Carvalho Chehab 		}
14719a0bf528SMauro Carvalho Chehab 
14729a0bf528SMauro Carvalho Chehab 		if ((((10 * internal->master_clk) / (internal->srate / 10)) <= 410) &&
14739a0bf528SMauro Carvalho Chehab 		      (INRANGE(STB0899_QPSK_12, modcod, STB0899_QPSK_35)) &&
14749a0bf528SMauro Carvalho Chehab 		      (pilots == 1)) {
14759a0bf528SMauro Carvalho Chehab 
14769a0bf528SMauro Carvalho Chehab 			/* Equalizer Disable update	 */
14779a0bf528SMauro Carvalho Chehab 			reg = STB0899_READ_S2REG(STB0899_S2DEMOD, EQ_CNTRL);
14789a0bf528SMauro Carvalho Chehab 			STB0899_SETFIELD_VAL(EQ_DISABLE_UPDATE, reg, 1);
14799a0bf528SMauro Carvalho Chehab 			stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQ_CNTRL, STB0899_OFF0_EQ_CNTRL, reg);
14809a0bf528SMauro Carvalho Chehab 		}
14819a0bf528SMauro Carvalho Chehab 
14829a0bf528SMauro Carvalho Chehab 		/* slow down the Equalizer once locked	*/
14839a0bf528SMauro Carvalho Chehab 		reg = STB0899_READ_S2REG(STB0899_S2DEMOD, EQ_CNTRL);
14849a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(EQ_SHIFT, reg, 0x02);
14859a0bf528SMauro Carvalho Chehab 		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQ_CNTRL, STB0899_OFF0_EQ_CNTRL, reg);
14869a0bf528SMauro Carvalho Chehab 
14879a0bf528SMauro Carvalho Chehab 		/* Store signal parameters	*/
14889a0bf528SMauro Carvalho Chehab 		offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ);
14899a0bf528SMauro Carvalho Chehab 
14909a0bf528SMauro Carvalho Chehab 		offsetfreq = offsetfreq / ((1 << 30) / 1000);
14919a0bf528SMauro Carvalho Chehab 		offsetfreq *= (internal->master_clk / 1000000);
14929a0bf528SMauro Carvalho Chehab 		reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2);
14939a0bf528SMauro Carvalho Chehab 		if (STB0899_GETFIELD(SPECTRUM_INVERT, reg))
14949a0bf528SMauro Carvalho Chehab 			offsetfreq *= -1;
14959a0bf528SMauro Carvalho Chehab 
14969a0bf528SMauro Carvalho Chehab 		internal->freq = internal->freq - offsetfreq;
14979a0bf528SMauro Carvalho Chehab 		internal->srate = stb0899_dvbs2_get_srate(state);
14989a0bf528SMauro Carvalho Chehab 
14999a0bf528SMauro Carvalho Chehab 		reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_STAT2);
15009a0bf528SMauro Carvalho Chehab 		internal->modcod = STB0899_GETFIELD(UWP_DECODE_MOD, reg) >> 2;
15019a0bf528SMauro Carvalho Chehab 		internal->pilots = STB0899_GETFIELD(UWP_DECODE_MOD, reg) & 0x01;
15029a0bf528SMauro Carvalho Chehab 		internal->frame_length = (STB0899_GETFIELD(UWP_DECODE_MOD, reg) >> 1) & 0x01;
15039a0bf528SMauro Carvalho Chehab 
15049a0bf528SMauro Carvalho Chehab 		 /* Set IF AGC to tracking	*/
15059a0bf528SMauro Carvalho Chehab 		reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL);
15069a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(IF_LOOP_GAIN, reg,  3);
15079a0bf528SMauro Carvalho Chehab 
15089a0bf528SMauro Carvalho Chehab 		/* if QPSK 1/2,QPSK 3/5 or QPSK 2/3 set IF AGC reference to 16 otherwise 32*/
15099a0bf528SMauro Carvalho Chehab 		if (INRANGE(STB0899_QPSK_12, internal->modcod, STB0899_QPSK_23))
15109a0bf528SMauro Carvalho Chehab 			STB0899_SETFIELD_VAL(IF_AGC_REF, reg, 16);
15119a0bf528SMauro Carvalho Chehab 
15129a0bf528SMauro Carvalho Chehab 		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL, STB0899_OFF0_IF_AGC_CNTRL, reg);
15139a0bf528SMauro Carvalho Chehab 
15149a0bf528SMauro Carvalho Chehab 		reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL2);
15159a0bf528SMauro Carvalho Chehab 		STB0899_SETFIELD_VAL(IF_AGC_DUMP_PER, reg, 7);
15169a0bf528SMauro Carvalho Chehab 		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL2, STB0899_OFF0_IF_AGC_CNTRL2, reg);
15179a0bf528SMauro Carvalho Chehab 	}
15189a0bf528SMauro Carvalho Chehab 
15199a0bf528SMauro Carvalho Chehab 	/* Release Stream Merger Reset		*/
15209a0bf528SMauro Carvalho Chehab 	reg = stb0899_read_reg(state, STB0899_TSTRES);
15219a0bf528SMauro Carvalho Chehab 	STB0899_SETFIELD_VAL(FRESRS, reg, 0);
15229a0bf528SMauro Carvalho Chehab 	stb0899_write_reg(state, STB0899_TSTRES, reg);
15239a0bf528SMauro Carvalho Chehab 
15249a0bf528SMauro Carvalho Chehab 	return internal->status;
15259a0bf528SMauro Carvalho Chehab }
1526