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