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