18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Linux-DVB Driver for DiBcom's DiB7000M and 48c2ecf20Sopenharmony_ci * first generation DiB7000P-demodulator-family. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/i2c.h> 148c2ecf20Sopenharmony_ci#include <linux/mutex.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "dib7000m.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic int debug; 218c2ecf20Sopenharmony_cimodule_param(debug, int, 0644); 228c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define dprintk(fmt, arg...) do { \ 258c2ecf20Sopenharmony_ci if (debug) \ 268c2ecf20Sopenharmony_ci printk(KERN_DEBUG pr_fmt("%s: " fmt), \ 278c2ecf20Sopenharmony_ci __func__, ##arg); \ 288c2ecf20Sopenharmony_ci} while (0) 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistruct dib7000m_state { 318c2ecf20Sopenharmony_ci struct dvb_frontend demod; 328c2ecf20Sopenharmony_ci struct dib7000m_config cfg; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci u8 i2c_addr; 358c2ecf20Sopenharmony_ci struct i2c_adapter *i2c_adap; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci struct dibx000_i2c_master i2c_master; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* offset is 1 in case of the 7000MC */ 408c2ecf20Sopenharmony_ci u8 reg_offs; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci u16 wbd_ref; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci u8 current_band; 458c2ecf20Sopenharmony_ci u32 current_bandwidth; 468c2ecf20Sopenharmony_ci struct dibx000_agc_config *current_agc; 478c2ecf20Sopenharmony_ci u32 timf; 488c2ecf20Sopenharmony_ci u32 timf_default; 498c2ecf20Sopenharmony_ci u32 internal_clk; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci u8 div_force_off : 1; 528c2ecf20Sopenharmony_ci u8 div_state : 1; 538c2ecf20Sopenharmony_ci u16 div_sync_wait; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci u16 revision; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci u8 agc_state; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci /* for the I2C transfer */ 608c2ecf20Sopenharmony_ci struct i2c_msg msg[2]; 618c2ecf20Sopenharmony_ci u8 i2c_write_buffer[4]; 628c2ecf20Sopenharmony_ci u8 i2c_read_buffer[2]; 638c2ecf20Sopenharmony_ci struct mutex i2c_buffer_lock; 648c2ecf20Sopenharmony_ci}; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cienum dib7000m_power_mode { 678c2ecf20Sopenharmony_ci DIB7000M_POWER_ALL = 0, 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci DIB7000M_POWER_NO, 708c2ecf20Sopenharmony_ci DIB7000M_POWER_INTERF_ANALOG_AGC, 718c2ecf20Sopenharmony_ci DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD, 728c2ecf20Sopenharmony_ci DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD, 738c2ecf20Sopenharmony_ci DIB7000M_POWER_INTERFACE_ONLY, 748c2ecf20Sopenharmony_ci}; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci u16 ret; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { 818c2ecf20Sopenharmony_ci dprintk("could not acquire lock\n"); 828c2ecf20Sopenharmony_ci return 0; 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci state->i2c_write_buffer[0] = (reg >> 8) | 0x80; 868c2ecf20Sopenharmony_ci state->i2c_write_buffer[1] = reg & 0xff; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci memset(state->msg, 0, 2 * sizeof(struct i2c_msg)); 898c2ecf20Sopenharmony_ci state->msg[0].addr = state->i2c_addr >> 1; 908c2ecf20Sopenharmony_ci state->msg[0].flags = 0; 918c2ecf20Sopenharmony_ci state->msg[0].buf = state->i2c_write_buffer; 928c2ecf20Sopenharmony_ci state->msg[0].len = 2; 938c2ecf20Sopenharmony_ci state->msg[1].addr = state->i2c_addr >> 1; 948c2ecf20Sopenharmony_ci state->msg[1].flags = I2C_M_RD; 958c2ecf20Sopenharmony_ci state->msg[1].buf = state->i2c_read_buffer; 968c2ecf20Sopenharmony_ci state->msg[1].len = 2; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2) 998c2ecf20Sopenharmony_ci dprintk("i2c read error on %d\n", reg); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; 1028c2ecf20Sopenharmony_ci mutex_unlock(&state->i2c_buffer_lock); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci return ret; 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci int ret; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { 1128c2ecf20Sopenharmony_ci dprintk("could not acquire lock\n"); 1138c2ecf20Sopenharmony_ci return -EINVAL; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci state->i2c_write_buffer[0] = (reg >> 8) & 0xff; 1178c2ecf20Sopenharmony_ci state->i2c_write_buffer[1] = reg & 0xff; 1188c2ecf20Sopenharmony_ci state->i2c_write_buffer[2] = (val >> 8) & 0xff; 1198c2ecf20Sopenharmony_ci state->i2c_write_buffer[3] = val & 0xff; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci memset(&state->msg[0], 0, sizeof(struct i2c_msg)); 1228c2ecf20Sopenharmony_ci state->msg[0].addr = state->i2c_addr >> 1; 1238c2ecf20Sopenharmony_ci state->msg[0].flags = 0; 1248c2ecf20Sopenharmony_ci state->msg[0].buf = state->i2c_write_buffer; 1258c2ecf20Sopenharmony_ci state->msg[0].len = 4; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? 1288c2ecf20Sopenharmony_ci -EREMOTEIO : 0); 1298c2ecf20Sopenharmony_ci mutex_unlock(&state->i2c_buffer_lock); 1308c2ecf20Sopenharmony_ci return ret; 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_cistatic void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci u16 l = 0, r, *n; 1358c2ecf20Sopenharmony_ci n = buf; 1368c2ecf20Sopenharmony_ci l = *n++; 1378c2ecf20Sopenharmony_ci while (l) { 1388c2ecf20Sopenharmony_ci r = *n++; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if (state->reg_offs && (r >= 112 && r <= 331)) // compensate for 7000MC 1418c2ecf20Sopenharmony_ci r++; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci do { 1448c2ecf20Sopenharmony_ci dib7000m_write_word(state, r, *n++); 1458c2ecf20Sopenharmony_ci r++; 1468c2ecf20Sopenharmony_ci } while (--l); 1478c2ecf20Sopenharmony_ci l = *n++; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic int dib7000m_set_output_mode(struct dib7000m_state *state, int mode) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci int ret = 0; 1548c2ecf20Sopenharmony_ci u16 outreg, fifo_threshold, smo_mode, 1558c2ecf20Sopenharmony_ci sram = 0x0005; /* by default SRAM output is disabled */ 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci outreg = 0; 1588c2ecf20Sopenharmony_ci fifo_threshold = 1792; 1598c2ecf20Sopenharmony_ci smo_mode = (dib7000m_read_word(state, 294 + state->reg_offs) & 0x0010) | (1 << 1); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci dprintk("setting output mode for demod %p to %d\n", &state->demod, mode); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci switch (mode) { 1648c2ecf20Sopenharmony_ci case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock 1658c2ecf20Sopenharmony_ci outreg = (1 << 10); /* 0x0400 */ 1668c2ecf20Sopenharmony_ci break; 1678c2ecf20Sopenharmony_ci case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock 1688c2ecf20Sopenharmony_ci outreg = (1 << 10) | (1 << 6); /* 0x0440 */ 1698c2ecf20Sopenharmony_ci break; 1708c2ecf20Sopenharmony_ci case OUTMODE_MPEG2_SERIAL: // STBs with serial input 1718c2ecf20Sopenharmony_ci outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */ 1728c2ecf20Sopenharmony_ci break; 1738c2ecf20Sopenharmony_ci case OUTMODE_DIVERSITY: 1748c2ecf20Sopenharmony_ci if (state->cfg.hostbus_diversity) 1758c2ecf20Sopenharmony_ci outreg = (1 << 10) | (4 << 6); /* 0x0500 */ 1768c2ecf20Sopenharmony_ci else 1778c2ecf20Sopenharmony_ci sram |= 0x0c00; 1788c2ecf20Sopenharmony_ci break; 1798c2ecf20Sopenharmony_ci case OUTMODE_MPEG2_FIFO: // e.g. USB feeding 1808c2ecf20Sopenharmony_ci smo_mode |= (3 << 1); 1818c2ecf20Sopenharmony_ci fifo_threshold = 512; 1828c2ecf20Sopenharmony_ci outreg = (1 << 10) | (5 << 6); 1838c2ecf20Sopenharmony_ci break; 1848c2ecf20Sopenharmony_ci case OUTMODE_HIGH_Z: // disable 1858c2ecf20Sopenharmony_ci outreg = 0; 1868c2ecf20Sopenharmony_ci break; 1878c2ecf20Sopenharmony_ci default: 1888c2ecf20Sopenharmony_ci dprintk("Unhandled output_mode passed to be set for demod %p\n", &state->demod); 1898c2ecf20Sopenharmony_ci break; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (state->cfg.output_mpeg2_in_188_bytes) 1938c2ecf20Sopenharmony_ci smo_mode |= (1 << 5) ; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci ret |= dib7000m_write_word(state, 294 + state->reg_offs, smo_mode); 1968c2ecf20Sopenharmony_ci ret |= dib7000m_write_word(state, 295 + state->reg_offs, fifo_threshold); /* synchronous fread */ 1978c2ecf20Sopenharmony_ci ret |= dib7000m_write_word(state, 1795, outreg); 1988c2ecf20Sopenharmony_ci ret |= dib7000m_write_word(state, 1805, sram); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (state->revision == 0x4003) { 2018c2ecf20Sopenharmony_ci u16 clk_cfg1 = dib7000m_read_word(state, 909) & 0xfffd; 2028c2ecf20Sopenharmony_ci if (mode == OUTMODE_DIVERSITY) 2038c2ecf20Sopenharmony_ci clk_cfg1 |= (1 << 1); // P_O_CLK_en 2048c2ecf20Sopenharmony_ci dib7000m_write_word(state, 909, clk_cfg1); 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci return ret; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic void dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci /* by default everything is going to be powered off */ 2128c2ecf20Sopenharmony_ci u16 reg_903 = 0xffff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906 = 0x3fff; 2138c2ecf20Sopenharmony_ci u8 offset = 0; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci /* now, depending on the requested mode, we power on */ 2168c2ecf20Sopenharmony_ci switch (mode) { 2178c2ecf20Sopenharmony_ci /* power up everything in the demod */ 2188c2ecf20Sopenharmony_ci case DIB7000M_POWER_ALL: 2198c2ecf20Sopenharmony_ci reg_903 = 0x0000; reg_904 = 0x0000; reg_905 = 0x0000; reg_906 = 0x0000; 2208c2ecf20Sopenharmony_ci break; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci /* just leave power on the control-interfaces: GPIO and (I2C or SDIO or SRAM) */ 2238c2ecf20Sopenharmony_ci case DIB7000M_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C or SRAM */ 2248c2ecf20Sopenharmony_ci reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 2)); 2258c2ecf20Sopenharmony_ci break; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci case DIB7000M_POWER_INTERF_ANALOG_AGC: 2288c2ecf20Sopenharmony_ci reg_903 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10)); 2298c2ecf20Sopenharmony_ci reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 2)); 2308c2ecf20Sopenharmony_ci reg_906 &= ~((1 << 0)); 2318c2ecf20Sopenharmony_ci break; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci case DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD: 2348c2ecf20Sopenharmony_ci reg_903 = 0x0000; reg_904 = 0x801f; reg_905 = 0x0000; reg_906 = 0x0000; 2358c2ecf20Sopenharmony_ci break; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci case DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD: 2388c2ecf20Sopenharmony_ci reg_903 = 0x0000; reg_904 = 0x8000; reg_905 = 0x010b; reg_906 = 0x0000; 2398c2ecf20Sopenharmony_ci break; 2408c2ecf20Sopenharmony_ci case DIB7000M_POWER_NO: 2418c2ecf20Sopenharmony_ci break; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* always power down unused parts */ 2458c2ecf20Sopenharmony_ci if (!state->cfg.mobile_mode) 2468c2ecf20Sopenharmony_ci reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* P_sdio_select_clk = 0 on MC and after*/ 2498c2ecf20Sopenharmony_ci if (state->revision != 0x4000) 2508c2ecf20Sopenharmony_ci reg_906 <<= 1; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci if (state->revision == 0x4003) 2538c2ecf20Sopenharmony_ci offset = 1; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci dib7000m_write_word(state, 903 + offset, reg_903); 2568c2ecf20Sopenharmony_ci dib7000m_write_word(state, 904 + offset, reg_904); 2578c2ecf20Sopenharmony_ci dib7000m_write_word(state, 905 + offset, reg_905); 2588c2ecf20Sopenharmony_ci dib7000m_write_word(state, 906 + offset, reg_906); 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc_states no) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci int ret = 0; 2648c2ecf20Sopenharmony_ci u16 reg_913 = dib7000m_read_word(state, 913), 2658c2ecf20Sopenharmony_ci reg_914 = dib7000m_read_word(state, 914); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci switch (no) { 2688c2ecf20Sopenharmony_ci case DIBX000_SLOW_ADC_ON: 2698c2ecf20Sopenharmony_ci reg_914 |= (1 << 1) | (1 << 0); 2708c2ecf20Sopenharmony_ci ret |= dib7000m_write_word(state, 914, reg_914); 2718c2ecf20Sopenharmony_ci reg_914 &= ~(1 << 1); 2728c2ecf20Sopenharmony_ci break; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci case DIBX000_SLOW_ADC_OFF: 2758c2ecf20Sopenharmony_ci reg_914 |= (1 << 1) | (1 << 0); 2768c2ecf20Sopenharmony_ci break; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci case DIBX000_ADC_ON: 2798c2ecf20Sopenharmony_ci if (state->revision == 0x4000) { // workaround for PA/MA 2808c2ecf20Sopenharmony_ci // power-up ADC 2818c2ecf20Sopenharmony_ci dib7000m_write_word(state, 913, 0); 2828c2ecf20Sopenharmony_ci dib7000m_write_word(state, 914, reg_914 & 0x3); 2838c2ecf20Sopenharmony_ci // power-down bandgag 2848c2ecf20Sopenharmony_ci dib7000m_write_word(state, 913, (1 << 15)); 2858c2ecf20Sopenharmony_ci dib7000m_write_word(state, 914, reg_914 & 0x3); 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci reg_913 &= 0x0fff; 2898c2ecf20Sopenharmony_ci reg_914 &= 0x0003; 2908c2ecf20Sopenharmony_ci break; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci case DIBX000_ADC_OFF: // leave the VBG voltage on 2938c2ecf20Sopenharmony_ci reg_913 |= (1 << 14) | (1 << 13) | (1 << 12); 2948c2ecf20Sopenharmony_ci reg_914 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2); 2958c2ecf20Sopenharmony_ci break; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci case DIBX000_VBG_ENABLE: 2988c2ecf20Sopenharmony_ci reg_913 &= ~(1 << 15); 2998c2ecf20Sopenharmony_ci break; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci case DIBX000_VBG_DISABLE: 3028c2ecf20Sopenharmony_ci reg_913 |= (1 << 15); 3038c2ecf20Sopenharmony_ci break; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci default: 3068c2ecf20Sopenharmony_ci break; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci// dprintk("913: %x, 914: %x\n", reg_913, reg_914); 3108c2ecf20Sopenharmony_ci ret |= dib7000m_write_word(state, 913, reg_913); 3118c2ecf20Sopenharmony_ci ret |= dib7000m_write_word(state, 914, reg_914); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci return ret; 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic int dib7000m_set_bandwidth(struct dib7000m_state *state, u32 bw) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci u32 timf; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (!bw) 3218c2ecf20Sopenharmony_ci bw = 8000; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci // store the current bandwidth for later use 3248c2ecf20Sopenharmony_ci state->current_bandwidth = bw; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (state->timf == 0) { 3278c2ecf20Sopenharmony_ci dprintk("using default timf\n"); 3288c2ecf20Sopenharmony_ci timf = state->timf_default; 3298c2ecf20Sopenharmony_ci } else { 3308c2ecf20Sopenharmony_ci dprintk("using updated timf\n"); 3318c2ecf20Sopenharmony_ci timf = state->timf; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci timf = timf * (bw / 50) / 160; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci dib7000m_write_word(state, 23, (u16) ((timf >> 16) & 0xffff)); 3378c2ecf20Sopenharmony_ci dib7000m_write_word(state, 24, (u16) ((timf ) & 0xffff)); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci return 0; 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic int dib7000m_set_diversity_in(struct dvb_frontend *demod, int onoff) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci struct dib7000m_state *state = demod->demodulator_priv; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci if (state->div_force_off) { 3478c2ecf20Sopenharmony_ci dprintk("diversity combination deactivated - forced by COFDM parameters\n"); 3488c2ecf20Sopenharmony_ci onoff = 0; 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci state->div_state = (u8)onoff; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci if (onoff) { 3538c2ecf20Sopenharmony_ci dib7000m_write_word(state, 263 + state->reg_offs, 6); 3548c2ecf20Sopenharmony_ci dib7000m_write_word(state, 264 + state->reg_offs, 6); 3558c2ecf20Sopenharmony_ci dib7000m_write_word(state, 266 + state->reg_offs, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0)); 3568c2ecf20Sopenharmony_ci } else { 3578c2ecf20Sopenharmony_ci dib7000m_write_word(state, 263 + state->reg_offs, 1); 3588c2ecf20Sopenharmony_ci dib7000m_write_word(state, 264 + state->reg_offs, 0); 3598c2ecf20Sopenharmony_ci dib7000m_write_word(state, 266 + state->reg_offs, 0); 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci return 0; 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic int dib7000m_sad_calib(struct dib7000m_state *state) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci/* internal */ 3698c2ecf20Sopenharmony_ci// dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writing in set_bandwidth 3708c2ecf20Sopenharmony_ci dib7000m_write_word(state, 929, (0 << 1) | (0 << 0)); 3718c2ecf20Sopenharmony_ci dib7000m_write_word(state, 930, 776); // 0.625*3.3 / 4096 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci /* do the calibration */ 3748c2ecf20Sopenharmony_ci dib7000m_write_word(state, 929, (1 << 0)); 3758c2ecf20Sopenharmony_ci dib7000m_write_word(state, 929, (0 << 0)); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci msleep(1); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci return 0; 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_cistatic void dib7000m_reset_pll_common(struct dib7000m_state *state, const struct dibx000_bandwidth_config *bw) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci dib7000m_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff)); 3858c2ecf20Sopenharmony_ci dib7000m_write_word(state, 19, (u16) ( (bw->internal*1000) & 0xffff)); 3868c2ecf20Sopenharmony_ci dib7000m_write_word(state, 21, (u16) ( (bw->ifreq >> 16) & 0xffff)); 3878c2ecf20Sopenharmony_ci dib7000m_write_word(state, 22, (u16) ( bw->ifreq & 0xffff)); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci dib7000m_write_word(state, 928, bw->sad_cfg); 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic void dib7000m_reset_pll(struct dib7000m_state *state) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci const struct dibx000_bandwidth_config *bw = state->cfg.bw; 3958c2ecf20Sopenharmony_ci u16 reg_907,reg_910; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci /* default */ 3988c2ecf20Sopenharmony_ci reg_907 = (bw->pll_bypass << 15) | (bw->modulo << 7) | 3998c2ecf20Sopenharmony_ci (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | 4008c2ecf20Sopenharmony_ci (bw->enable_refdiv << 1) | (0 << 0); 4018c2ecf20Sopenharmony_ci reg_910 = (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci // for this oscillator frequency should be 30 MHz for the Master (default values in the board_parameters give that value) 4048c2ecf20Sopenharmony_ci // this is only working only for 30 MHz crystals 4058c2ecf20Sopenharmony_ci if (!state->cfg.quartz_direct) { 4068c2ecf20Sopenharmony_ci reg_910 |= (1 << 5); // forcing the predivider to 1 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci // if the previous front-end is baseband, its output frequency is 15 MHz (prev freq divided by 2) 4098c2ecf20Sopenharmony_ci if(state->cfg.input_clk_is_div_2) 4108c2ecf20Sopenharmony_ci reg_907 |= (16 << 9); 4118c2ecf20Sopenharmony_ci else // otherwise the previous front-end puts out its input (default 30MHz) - no extra division necessary 4128c2ecf20Sopenharmony_ci reg_907 |= (8 << 9); 4138c2ecf20Sopenharmony_ci } else { 4148c2ecf20Sopenharmony_ci reg_907 |= (bw->pll_ratio & 0x3f) << 9; 4158c2ecf20Sopenharmony_ci reg_910 |= (bw->pll_prediv << 5); 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci dib7000m_write_word(state, 910, reg_910); // pll cfg 4198c2ecf20Sopenharmony_ci dib7000m_write_word(state, 907, reg_907); // clk cfg0 4208c2ecf20Sopenharmony_ci dib7000m_write_word(state, 908, 0x0006); // clk_cfg1 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci dib7000m_reset_pll_common(state, bw); 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic void dib7000mc_reset_pll(struct dib7000m_state *state) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci const struct dibx000_bandwidth_config *bw = state->cfg.bw; 4288c2ecf20Sopenharmony_ci u16 clk_cfg1; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci // clk_cfg0 4318c2ecf20Sopenharmony_ci dib7000m_write_word(state, 907, (bw->pll_prediv << 8) | (bw->pll_ratio << 0)); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci // clk_cfg1 4348c2ecf20Sopenharmony_ci //dib7000m_write_word(state, 908, (1 << 14) | (3 << 12) |(0 << 11) | 4358c2ecf20Sopenharmony_ci clk_cfg1 = (0 << 14) | (3 << 12) |(0 << 11) | 4368c2ecf20Sopenharmony_ci (bw->IO_CLK_en_core << 10) | (bw->bypclk_div << 5) | (bw->enable_refdiv << 4) | 4378c2ecf20Sopenharmony_ci (1 << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0); 4388c2ecf20Sopenharmony_ci dib7000m_write_word(state, 908, clk_cfg1); 4398c2ecf20Sopenharmony_ci clk_cfg1 = (clk_cfg1 & 0xfff7) | (bw->pll_bypass << 3); 4408c2ecf20Sopenharmony_ci dib7000m_write_word(state, 908, clk_cfg1); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci // smpl_cfg 4438c2ecf20Sopenharmony_ci dib7000m_write_word(state, 910, (1 << 12) | (2 << 10) | (bw->modulo << 8) | (bw->ADClkSrc << 7)); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci dib7000m_reset_pll_common(state, bw); 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistatic int dib7000m_reset_gpio(struct dib7000m_state *st) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci /* reset the GPIOs */ 4518c2ecf20Sopenharmony_ci dib7000m_write_word(st, 773, st->cfg.gpio_dir); 4528c2ecf20Sopenharmony_ci dib7000m_write_word(st, 774, st->cfg.gpio_val); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci /* TODO 782 is P_gpio_od */ 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci dib7000m_write_word(st, 775, st->cfg.gpio_pwm_pos); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci dib7000m_write_word(st, 780, st->cfg.pwm_freq_div); 4598c2ecf20Sopenharmony_ci return 0; 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_cistatic u16 dib7000m_defaults_common[] = 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci // auto search configuration 4668c2ecf20Sopenharmony_ci 3, 2, 4678c2ecf20Sopenharmony_ci 0x0004, 4688c2ecf20Sopenharmony_ci 0x1000, 4698c2ecf20Sopenharmony_ci 0x0814, 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci 12, 6, 4728c2ecf20Sopenharmony_ci 0x001b, 4738c2ecf20Sopenharmony_ci 0x7740, 4748c2ecf20Sopenharmony_ci 0x005b, 4758c2ecf20Sopenharmony_ci 0x8d80, 4768c2ecf20Sopenharmony_ci 0x01c9, 4778c2ecf20Sopenharmony_ci 0xc380, 4788c2ecf20Sopenharmony_ci 0x0000, 4798c2ecf20Sopenharmony_ci 0x0080, 4808c2ecf20Sopenharmony_ci 0x0000, 4818c2ecf20Sopenharmony_ci 0x0090, 4828c2ecf20Sopenharmony_ci 0x0001, 4838c2ecf20Sopenharmony_ci 0xd4c0, 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci 1, 26, 4868c2ecf20Sopenharmony_ci 0x6680, // P_corm_thres Lock algorithms configuration 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci 1, 170, 4898c2ecf20Sopenharmony_ci 0x0410, // P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci 8, 173, 4928c2ecf20Sopenharmony_ci 0, 4938c2ecf20Sopenharmony_ci 0, 4948c2ecf20Sopenharmony_ci 0, 4958c2ecf20Sopenharmony_ci 0, 4968c2ecf20Sopenharmony_ci 0, 4978c2ecf20Sopenharmony_ci 0, 4988c2ecf20Sopenharmony_ci 0, 4998c2ecf20Sopenharmony_ci 0, 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci 1, 182, 5028c2ecf20Sopenharmony_ci 8192, // P_fft_nb_to_cut 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci 2, 195, 5058c2ecf20Sopenharmony_ci 0x0ccd, // P_pha3_thres 5068c2ecf20Sopenharmony_ci 0, // P_cti_use_cpe, P_cti_use_prog 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci 1, 205, 5098c2ecf20Sopenharmony_ci 0x200f, // P_cspu_regul, P_cspu_win_cut 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci 5, 214, 5128c2ecf20Sopenharmony_ci 0x023d, // P_adp_regul_cnt 5138c2ecf20Sopenharmony_ci 0x00a4, // P_adp_noise_cnt 5148c2ecf20Sopenharmony_ci 0x00a4, // P_adp_regul_ext 5158c2ecf20Sopenharmony_ci 0x7ff0, // P_adp_noise_ext 5168c2ecf20Sopenharmony_ci 0x3ccc, // P_adp_fil 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci 1, 226, 5198c2ecf20Sopenharmony_ci 0, // P_2d_byp_ti_num 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci 1, 255, 5228c2ecf20Sopenharmony_ci 0x800, // P_equal_thres_wgn 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci 1, 263, 5258c2ecf20Sopenharmony_ci 0x0001, 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci 1, 281, 5288c2ecf20Sopenharmony_ci 0x0010, // P_fec_* 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci 1, 294, 5318c2ecf20Sopenharmony_ci 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci 0 5348c2ecf20Sopenharmony_ci}; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_cistatic u16 dib7000m_defaults[] = 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci /* set ADC level to -16 */ 5408c2ecf20Sopenharmony_ci 11, 76, 5418c2ecf20Sopenharmony_ci (1 << 13) - 825 - 117, 5428c2ecf20Sopenharmony_ci (1 << 13) - 837 - 117, 5438c2ecf20Sopenharmony_ci (1 << 13) - 811 - 117, 5448c2ecf20Sopenharmony_ci (1 << 13) - 766 - 117, 5458c2ecf20Sopenharmony_ci (1 << 13) - 737 - 117, 5468c2ecf20Sopenharmony_ci (1 << 13) - 693 - 117, 5478c2ecf20Sopenharmony_ci (1 << 13) - 648 - 117, 5488c2ecf20Sopenharmony_ci (1 << 13) - 619 - 117, 5498c2ecf20Sopenharmony_ci (1 << 13) - 575 - 117, 5508c2ecf20Sopenharmony_ci (1 << 13) - 531 - 117, 5518c2ecf20Sopenharmony_ci (1 << 13) - 501 - 117, 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci // Tuner IO bank: max drive (14mA) 5548c2ecf20Sopenharmony_ci 1, 912, 5558c2ecf20Sopenharmony_ci 0x2c8a, 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci 1, 1817, 5588c2ecf20Sopenharmony_ci 1, 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci 0, 5618c2ecf20Sopenharmony_ci}; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_cistatic int dib7000m_demod_reset(struct dib7000m_state *state) 5648c2ecf20Sopenharmony_ci{ 5658c2ecf20Sopenharmony_ci dib7000m_set_power_mode(state, DIB7000M_POWER_ALL); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci /* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */ 5688c2ecf20Sopenharmony_ci dib7000m_set_adc_state(state, DIBX000_VBG_ENABLE); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci /* restart all parts */ 5718c2ecf20Sopenharmony_ci dib7000m_write_word(state, 898, 0xffff); 5728c2ecf20Sopenharmony_ci dib7000m_write_word(state, 899, 0xffff); 5738c2ecf20Sopenharmony_ci dib7000m_write_word(state, 900, 0xff0f); 5748c2ecf20Sopenharmony_ci dib7000m_write_word(state, 901, 0xfffc); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci dib7000m_write_word(state, 898, 0); 5778c2ecf20Sopenharmony_ci dib7000m_write_word(state, 899, 0); 5788c2ecf20Sopenharmony_ci dib7000m_write_word(state, 900, 0); 5798c2ecf20Sopenharmony_ci dib7000m_write_word(state, 901, 0); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci if (state->revision == 0x4000) 5828c2ecf20Sopenharmony_ci dib7000m_reset_pll(state); 5838c2ecf20Sopenharmony_ci else 5848c2ecf20Sopenharmony_ci dib7000mc_reset_pll(state); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci if (dib7000m_reset_gpio(state) != 0) 5878c2ecf20Sopenharmony_ci dprintk("GPIO reset was not successful.\n"); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci if (dib7000m_set_output_mode(state, OUTMODE_HIGH_Z) != 0) 5908c2ecf20Sopenharmony_ci dprintk("OUTPUT_MODE could not be reset.\n"); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci /* unforce divstr regardless whether i2c enumeration was done or not */ 5938c2ecf20Sopenharmony_ci dib7000m_write_word(state, 1794, dib7000m_read_word(state, 1794) & ~(1 << 1) ); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci dib7000m_set_bandwidth(state, 8000); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON); 5988c2ecf20Sopenharmony_ci dib7000m_sad_calib(state); 5998c2ecf20Sopenharmony_ci dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_OFF); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci if (state->cfg.dvbt_mode) 6028c2ecf20Sopenharmony_ci dib7000m_write_word(state, 1796, 0x0); // select DVB-T output 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci if (state->cfg.mobile_mode) 6058c2ecf20Sopenharmony_ci dib7000m_write_word(state, 261 + state->reg_offs, 2); 6068c2ecf20Sopenharmony_ci else 6078c2ecf20Sopenharmony_ci dib7000m_write_word(state, 224 + state->reg_offs, 1); 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ... 6108c2ecf20Sopenharmony_ci if(state->cfg.tuner_is_baseband) 6118c2ecf20Sopenharmony_ci dib7000m_write_word(state, 36, 0x0755); 6128c2ecf20Sopenharmony_ci else 6138c2ecf20Sopenharmony_ci dib7000m_write_word(state, 36, 0x1f55); 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci // P_divclksel=3 P_divbitsel=1 6168c2ecf20Sopenharmony_ci if (state->revision == 0x4000) 6178c2ecf20Sopenharmony_ci dib7000m_write_word(state, 909, (3 << 10) | (1 << 6)); 6188c2ecf20Sopenharmony_ci else 6198c2ecf20Sopenharmony_ci dib7000m_write_word(state, 909, (3 << 4) | 1); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci dib7000m_write_tab(state, dib7000m_defaults_common); 6228c2ecf20Sopenharmony_ci dib7000m_write_tab(state, dib7000m_defaults); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci dib7000m_set_power_mode(state, DIB7000M_POWER_INTERFACE_ONLY); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci state->internal_clk = state->cfg.bw->internal; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci return 0; 6298c2ecf20Sopenharmony_ci} 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_cistatic void dib7000m_restart_agc(struct dib7000m_state *state) 6328c2ecf20Sopenharmony_ci{ 6338c2ecf20Sopenharmony_ci // P_restart_iqc & P_restart_agc 6348c2ecf20Sopenharmony_ci dib7000m_write_word(state, 898, 0x0c00); 6358c2ecf20Sopenharmony_ci dib7000m_write_word(state, 898, 0x0000); 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_cistatic int dib7000m_agc_soft_split(struct dib7000m_state *state) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci u16 agc,split_offset; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if(!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0) 6438c2ecf20Sopenharmony_ci return 0; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci // n_agc_global 6468c2ecf20Sopenharmony_ci agc = dib7000m_read_word(state, 390); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci if (agc > state->current_agc->split.min_thres) 6498c2ecf20Sopenharmony_ci split_offset = state->current_agc->split.min; 6508c2ecf20Sopenharmony_ci else if (agc < state->current_agc->split.max_thres) 6518c2ecf20Sopenharmony_ci split_offset = state->current_agc->split.max; 6528c2ecf20Sopenharmony_ci else 6538c2ecf20Sopenharmony_ci split_offset = state->current_agc->split.max * 6548c2ecf20Sopenharmony_ci (agc - state->current_agc->split.min_thres) / 6558c2ecf20Sopenharmony_ci (state->current_agc->split.max_thres - state->current_agc->split.min_thres); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci dprintk("AGC split_offset: %d\n", split_offset); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci // P_agc_force_split and P_agc_split_offset 6608c2ecf20Sopenharmony_ci return dib7000m_write_word(state, 103, (dib7000m_read_word(state, 103) & 0xff00) | split_offset); 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_cistatic int dib7000m_update_lna(struct dib7000m_state *state) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci u16 dyn_gain; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci if (state->cfg.update_lna) { 6688c2ecf20Sopenharmony_ci // read dyn_gain here (because it is demod-dependent and not fe) 6698c2ecf20Sopenharmony_ci dyn_gain = dib7000m_read_word(state, 390); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed 6728c2ecf20Sopenharmony_ci dib7000m_restart_agc(state); 6738c2ecf20Sopenharmony_ci return 1; 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci } 6768c2ecf20Sopenharmony_ci return 0; 6778c2ecf20Sopenharmony_ci} 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_cistatic int dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) 6808c2ecf20Sopenharmony_ci{ 6818c2ecf20Sopenharmony_ci struct dibx000_agc_config *agc = NULL; 6828c2ecf20Sopenharmony_ci int i; 6838c2ecf20Sopenharmony_ci if (state->current_band == band && state->current_agc != NULL) 6848c2ecf20Sopenharmony_ci return 0; 6858c2ecf20Sopenharmony_ci state->current_band = band; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci for (i = 0; i < state->cfg.agc_config_count; i++) 6888c2ecf20Sopenharmony_ci if (state->cfg.agc[i].band_caps & band) { 6898c2ecf20Sopenharmony_ci agc = &state->cfg.agc[i]; 6908c2ecf20Sopenharmony_ci break; 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci if (agc == NULL) { 6948c2ecf20Sopenharmony_ci dprintk("no valid AGC configuration found for band 0x%02x\n", band); 6958c2ecf20Sopenharmony_ci return -EINVAL; 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci state->current_agc = agc; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci /* AGC */ 7018c2ecf20Sopenharmony_ci dib7000m_write_word(state, 72 , agc->setup); 7028c2ecf20Sopenharmony_ci dib7000m_write_word(state, 73 , agc->inv_gain); 7038c2ecf20Sopenharmony_ci dib7000m_write_word(state, 74 , agc->time_stabiliz); 7048c2ecf20Sopenharmony_ci dib7000m_write_word(state, 97 , (agc->alpha_level << 12) | agc->thlock); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci // Demod AGC loop configuration 7078c2ecf20Sopenharmony_ci dib7000m_write_word(state, 98, (agc->alpha_mant << 5) | agc->alpha_exp); 7088c2ecf20Sopenharmony_ci dib7000m_write_word(state, 99, (agc->beta_mant << 6) | agc->beta_exp); 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d\n", 7118c2ecf20Sopenharmony_ci state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci /* AGC continued */ 7148c2ecf20Sopenharmony_ci if (state->wbd_ref != 0) 7158c2ecf20Sopenharmony_ci dib7000m_write_word(state, 102, state->wbd_ref); 7168c2ecf20Sopenharmony_ci else // use default 7178c2ecf20Sopenharmony_ci dib7000m_write_word(state, 102, agc->wbd_ref); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci dib7000m_write_word(state, 103, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8) ); 7208c2ecf20Sopenharmony_ci dib7000m_write_word(state, 104, agc->agc1_max); 7218c2ecf20Sopenharmony_ci dib7000m_write_word(state, 105, agc->agc1_min); 7228c2ecf20Sopenharmony_ci dib7000m_write_word(state, 106, agc->agc2_max); 7238c2ecf20Sopenharmony_ci dib7000m_write_word(state, 107, agc->agc2_min); 7248c2ecf20Sopenharmony_ci dib7000m_write_word(state, 108, (agc->agc1_pt1 << 8) | agc->agc1_pt2 ); 7258c2ecf20Sopenharmony_ci dib7000m_write_word(state, 109, (agc->agc1_slope1 << 8) | agc->agc1_slope2); 7268c2ecf20Sopenharmony_ci dib7000m_write_word(state, 110, (agc->agc2_pt1 << 8) | agc->agc2_pt2); 7278c2ecf20Sopenharmony_ci dib7000m_write_word(state, 111, (agc->agc2_slope1 << 8) | agc->agc2_slope2); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci if (state->revision > 0x4000) { // settings for the MC 7308c2ecf20Sopenharmony_ci dib7000m_write_word(state, 71, agc->agc1_pt3); 7318c2ecf20Sopenharmony_ci// dprintk("929: %x %d %d\n", 7328c2ecf20Sopenharmony_ci// (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2), agc->wbd_inv, agc->wbd_sel); 7338c2ecf20Sopenharmony_ci dib7000m_write_word(state, 929, (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2)); 7348c2ecf20Sopenharmony_ci } else { 7358c2ecf20Sopenharmony_ci // wrong default values 7368c2ecf20Sopenharmony_ci u16 b[9] = { 676, 696, 717, 737, 758, 778, 799, 819, 840 }; 7378c2ecf20Sopenharmony_ci for (i = 0; i < 9; i++) 7388c2ecf20Sopenharmony_ci dib7000m_write_word(state, 88 + i, b[i]); 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci return 0; 7418c2ecf20Sopenharmony_ci} 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_cistatic void dib7000m_update_timf(struct dib7000m_state *state) 7448c2ecf20Sopenharmony_ci{ 7458c2ecf20Sopenharmony_ci u32 timf = (dib7000m_read_word(state, 436) << 16) | dib7000m_read_word(state, 437); 7468c2ecf20Sopenharmony_ci state->timf = timf * 160 / (state->current_bandwidth / 50); 7478c2ecf20Sopenharmony_ci dib7000m_write_word(state, 23, (u16) (timf >> 16)); 7488c2ecf20Sopenharmony_ci dib7000m_write_word(state, 24, (u16) (timf & 0xffff)); 7498c2ecf20Sopenharmony_ci dprintk("updated timf_frequency: %d (default: %d)\n", state->timf, state->timf_default); 7508c2ecf20Sopenharmony_ci} 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_cistatic int dib7000m_agc_startup(struct dvb_frontend *demod) 7538c2ecf20Sopenharmony_ci{ 7548c2ecf20Sopenharmony_ci struct dtv_frontend_properties *ch = &demod->dtv_property_cache; 7558c2ecf20Sopenharmony_ci struct dib7000m_state *state = demod->demodulator_priv; 7568c2ecf20Sopenharmony_ci u16 cfg_72 = dib7000m_read_word(state, 72); 7578c2ecf20Sopenharmony_ci int ret = -1; 7588c2ecf20Sopenharmony_ci u8 *agc_state = &state->agc_state; 7598c2ecf20Sopenharmony_ci u8 agc_split; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci switch (state->agc_state) { 7628c2ecf20Sopenharmony_ci case 0: 7638c2ecf20Sopenharmony_ci // set power-up level: interf+analog+AGC 7648c2ecf20Sopenharmony_ci dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC); 7658c2ecf20Sopenharmony_ci dib7000m_set_adc_state(state, DIBX000_ADC_ON); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci if (dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0) 7688c2ecf20Sopenharmony_ci return -1; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci ret = 7; /* ADC power up */ 7718c2ecf20Sopenharmony_ci (*agc_state)++; 7728c2ecf20Sopenharmony_ci break; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci case 1: 7758c2ecf20Sopenharmony_ci /* AGC initialization */ 7768c2ecf20Sopenharmony_ci if (state->cfg.agc_control) 7778c2ecf20Sopenharmony_ci state->cfg.agc_control(&state->demod, 1); 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci dib7000m_write_word(state, 75, 32768); 7808c2ecf20Sopenharmony_ci if (!state->current_agc->perform_agc_softsplit) { 7818c2ecf20Sopenharmony_ci /* we are using the wbd - so slow AGC startup */ 7828c2ecf20Sopenharmony_ci dib7000m_write_word(state, 103, 1 << 8); /* force 0 split on WBD and restart AGC */ 7838c2ecf20Sopenharmony_ci (*agc_state)++; 7848c2ecf20Sopenharmony_ci ret = 5; 7858c2ecf20Sopenharmony_ci } else { 7868c2ecf20Sopenharmony_ci /* default AGC startup */ 7878c2ecf20Sopenharmony_ci (*agc_state) = 4; 7888c2ecf20Sopenharmony_ci /* wait AGC rough lock time */ 7898c2ecf20Sopenharmony_ci ret = 7; 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci dib7000m_restart_agc(state); 7938c2ecf20Sopenharmony_ci break; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci case 2: /* fast split search path after 5sec */ 7968c2ecf20Sopenharmony_ci dib7000m_write_word(state, 72, cfg_72 | (1 << 4)); /* freeze AGC loop */ 7978c2ecf20Sopenharmony_ci dib7000m_write_word(state, 103, 2 << 9); /* fast split search 0.25kHz */ 7988c2ecf20Sopenharmony_ci (*agc_state)++; 7998c2ecf20Sopenharmony_ci ret = 14; 8008c2ecf20Sopenharmony_ci break; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci case 3: /* split search ended */ 8038c2ecf20Sopenharmony_ci agc_split = (u8)dib7000m_read_word(state, 392); /* store the split value for the next time */ 8048c2ecf20Sopenharmony_ci dib7000m_write_word(state, 75, dib7000m_read_word(state, 390)); /* set AGC gain start value */ 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci dib7000m_write_word(state, 72, cfg_72 & ~(1 << 4)); /* std AGC loop */ 8078c2ecf20Sopenharmony_ci dib7000m_write_word(state, 103, (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */ 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci dib7000m_restart_agc(state); 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci dprintk("SPLIT %p: %u\n", demod, agc_split); 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci (*agc_state)++; 8148c2ecf20Sopenharmony_ci ret = 5; 8158c2ecf20Sopenharmony_ci break; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci case 4: /* LNA startup */ 8188c2ecf20Sopenharmony_ci /* wait AGC accurate lock time */ 8198c2ecf20Sopenharmony_ci ret = 7; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci if (dib7000m_update_lna(state)) 8228c2ecf20Sopenharmony_ci // wait only AGC rough lock time 8238c2ecf20Sopenharmony_ci ret = 5; 8248c2ecf20Sopenharmony_ci else 8258c2ecf20Sopenharmony_ci (*agc_state)++; 8268c2ecf20Sopenharmony_ci break; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci case 5: 8298c2ecf20Sopenharmony_ci dib7000m_agc_soft_split(state); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci if (state->cfg.agc_control) 8328c2ecf20Sopenharmony_ci state->cfg.agc_control(&state->demod, 0); 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci (*agc_state)++; 8358c2ecf20Sopenharmony_ci break; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci default: 8388c2ecf20Sopenharmony_ci break; 8398c2ecf20Sopenharmony_ci } 8408c2ecf20Sopenharmony_ci return ret; 8418c2ecf20Sopenharmony_ci} 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_cistatic void dib7000m_set_channel(struct dib7000m_state *state, struct dtv_frontend_properties *ch, 8448c2ecf20Sopenharmony_ci u8 seq) 8458c2ecf20Sopenharmony_ci{ 8468c2ecf20Sopenharmony_ci u16 value, est[4]; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz)); 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci /* nfft, guard, qam, alpha */ 8518c2ecf20Sopenharmony_ci value = 0; 8528c2ecf20Sopenharmony_ci switch (ch->transmission_mode) { 8538c2ecf20Sopenharmony_ci case TRANSMISSION_MODE_2K: value |= (0 << 7); break; 8548c2ecf20Sopenharmony_ci case TRANSMISSION_MODE_4K: value |= (2 << 7); break; 8558c2ecf20Sopenharmony_ci default: 8568c2ecf20Sopenharmony_ci case TRANSMISSION_MODE_8K: value |= (1 << 7); break; 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci switch (ch->guard_interval) { 8598c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_32: value |= (0 << 5); break; 8608c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_16: value |= (1 << 5); break; 8618c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_4: value |= (3 << 5); break; 8628c2ecf20Sopenharmony_ci default: 8638c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_8: value |= (2 << 5); break; 8648c2ecf20Sopenharmony_ci } 8658c2ecf20Sopenharmony_ci switch (ch->modulation) { 8668c2ecf20Sopenharmony_ci case QPSK: value |= (0 << 3); break; 8678c2ecf20Sopenharmony_ci case QAM_16: value |= (1 << 3); break; 8688c2ecf20Sopenharmony_ci default: 8698c2ecf20Sopenharmony_ci case QAM_64: value |= (2 << 3); break; 8708c2ecf20Sopenharmony_ci } 8718c2ecf20Sopenharmony_ci switch (HIERARCHY_1) { 8728c2ecf20Sopenharmony_ci case HIERARCHY_2: value |= 2; break; 8738c2ecf20Sopenharmony_ci case HIERARCHY_4: value |= 4; break; 8748c2ecf20Sopenharmony_ci default: 8758c2ecf20Sopenharmony_ci case HIERARCHY_1: value |= 1; break; 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci dib7000m_write_word(state, 0, value); 8788c2ecf20Sopenharmony_ci dib7000m_write_word(state, 5, (seq << 4)); 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */ 8818c2ecf20Sopenharmony_ci value = 0; 8828c2ecf20Sopenharmony_ci if (1 != 0) 8838c2ecf20Sopenharmony_ci value |= (1 << 6); 8848c2ecf20Sopenharmony_ci if (ch->hierarchy == 1) 8858c2ecf20Sopenharmony_ci value |= (1 << 4); 8868c2ecf20Sopenharmony_ci if (1 == 1) 8878c2ecf20Sopenharmony_ci value |= 1; 8888c2ecf20Sopenharmony_ci switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) { 8898c2ecf20Sopenharmony_ci case FEC_2_3: value |= (2 << 1); break; 8908c2ecf20Sopenharmony_ci case FEC_3_4: value |= (3 << 1); break; 8918c2ecf20Sopenharmony_ci case FEC_5_6: value |= (5 << 1); break; 8928c2ecf20Sopenharmony_ci case FEC_7_8: value |= (7 << 1); break; 8938c2ecf20Sopenharmony_ci default: 8948c2ecf20Sopenharmony_ci case FEC_1_2: value |= (1 << 1); break; 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci dib7000m_write_word(state, 267 + state->reg_offs, value); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci /* offset loop parameters */ 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci /* P_timf_alpha = 6, P_corm_alpha=6, P_corm_thres=0x80 */ 9018c2ecf20Sopenharmony_ci dib7000m_write_word(state, 26, (6 << 12) | (6 << 8) | 0x80); 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=1, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */ 9048c2ecf20Sopenharmony_ci dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (1 << 9) | (3 << 5) | (1 << 4) | (0x3)); 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max=3 */ 9078c2ecf20Sopenharmony_ci dib7000m_write_word(state, 32, (0 << 4) | 0x3); 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step=5 */ 9108c2ecf20Sopenharmony_ci dib7000m_write_word(state, 33, (0 << 4) | 0x5); 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci /* P_dvsy_sync_wait */ 9138c2ecf20Sopenharmony_ci switch (ch->transmission_mode) { 9148c2ecf20Sopenharmony_ci case TRANSMISSION_MODE_8K: value = 256; break; 9158c2ecf20Sopenharmony_ci case TRANSMISSION_MODE_4K: value = 128; break; 9168c2ecf20Sopenharmony_ci case TRANSMISSION_MODE_2K: 9178c2ecf20Sopenharmony_ci default: value = 64; break; 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci switch (ch->guard_interval) { 9208c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_16: value *= 2; break; 9218c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_8: value *= 4; break; 9228c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_4: value *= 8; break; 9238c2ecf20Sopenharmony_ci default: 9248c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_32: value *= 1; break; 9258c2ecf20Sopenharmony_ci } 9268c2ecf20Sopenharmony_ci state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci /* deactivate the possibility of diversity reception if extended interleave - not for 7000MC */ 9298c2ecf20Sopenharmony_ci /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */ 9308c2ecf20Sopenharmony_ci if (1 == 1 || state->revision > 0x4000) 9318c2ecf20Sopenharmony_ci state->div_force_off = 0; 9328c2ecf20Sopenharmony_ci else 9338c2ecf20Sopenharmony_ci state->div_force_off = 1; 9348c2ecf20Sopenharmony_ci dib7000m_set_diversity_in(&state->demod, state->div_state); 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci /* channel estimation fine configuration */ 9378c2ecf20Sopenharmony_ci switch (ch->modulation) { 9388c2ecf20Sopenharmony_ci case QAM_64: 9398c2ecf20Sopenharmony_ci est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */ 9408c2ecf20Sopenharmony_ci est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */ 9418c2ecf20Sopenharmony_ci est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ 9428c2ecf20Sopenharmony_ci est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */ 9438c2ecf20Sopenharmony_ci break; 9448c2ecf20Sopenharmony_ci case QAM_16: 9458c2ecf20Sopenharmony_ci est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */ 9468c2ecf20Sopenharmony_ci est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */ 9478c2ecf20Sopenharmony_ci est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ 9488c2ecf20Sopenharmony_ci est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */ 9498c2ecf20Sopenharmony_ci break; 9508c2ecf20Sopenharmony_ci default: 9518c2ecf20Sopenharmony_ci est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */ 9528c2ecf20Sopenharmony_ci est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */ 9538c2ecf20Sopenharmony_ci est[2] = 0x0333; /* P_adp_regul_ext 0.1 */ 9548c2ecf20Sopenharmony_ci est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */ 9558c2ecf20Sopenharmony_ci break; 9568c2ecf20Sopenharmony_ci } 9578c2ecf20Sopenharmony_ci for (value = 0; value < 4; value++) 9588c2ecf20Sopenharmony_ci dib7000m_write_word(state, 214 + value + state->reg_offs, est[value]); 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci // set power-up level: autosearch 9618c2ecf20Sopenharmony_ci dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD); 9628c2ecf20Sopenharmony_ci} 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_cistatic int dib7000m_autosearch_start(struct dvb_frontend *demod) 9658c2ecf20Sopenharmony_ci{ 9668c2ecf20Sopenharmony_ci struct dtv_frontend_properties *ch = &demod->dtv_property_cache; 9678c2ecf20Sopenharmony_ci struct dib7000m_state *state = demod->demodulator_priv; 9688c2ecf20Sopenharmony_ci struct dtv_frontend_properties schan; 9698c2ecf20Sopenharmony_ci int ret = 0; 9708c2ecf20Sopenharmony_ci u32 value, factor; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci schan = *ch; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci schan.modulation = QAM_64; 9758c2ecf20Sopenharmony_ci schan.guard_interval = GUARD_INTERVAL_1_32; 9768c2ecf20Sopenharmony_ci schan.transmission_mode = TRANSMISSION_MODE_8K; 9778c2ecf20Sopenharmony_ci schan.code_rate_HP = FEC_2_3; 9788c2ecf20Sopenharmony_ci schan.code_rate_LP = FEC_3_4; 9798c2ecf20Sopenharmony_ci schan.hierarchy = 0; 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci dib7000m_set_channel(state, &schan, 7); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci factor = BANDWIDTH_TO_KHZ(schan.bandwidth_hz); 9848c2ecf20Sopenharmony_ci if (factor >= 5000) 9858c2ecf20Sopenharmony_ci factor = 1; 9868c2ecf20Sopenharmony_ci else 9878c2ecf20Sopenharmony_ci factor = 6; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci // always use the setting for 8MHz here lock_time for 7,6 MHz are longer 9908c2ecf20Sopenharmony_ci value = 30 * state->internal_clk * factor; 9918c2ecf20Sopenharmony_ci ret |= dib7000m_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time 9928c2ecf20Sopenharmony_ci ret |= dib7000m_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time 9938c2ecf20Sopenharmony_ci value = 100 * state->internal_clk * factor; 9948c2ecf20Sopenharmony_ci ret |= dib7000m_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time 9958c2ecf20Sopenharmony_ci ret |= dib7000m_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time 9968c2ecf20Sopenharmony_ci value = 500 * state->internal_clk * factor; 9978c2ecf20Sopenharmony_ci ret |= dib7000m_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time 9988c2ecf20Sopenharmony_ci ret |= dib7000m_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci // start search 10018c2ecf20Sopenharmony_ci value = dib7000m_read_word(state, 0); 10028c2ecf20Sopenharmony_ci ret |= dib7000m_write_word(state, 0, (u16) (value | (1 << 9))); 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci /* clear n_irq_pending */ 10058c2ecf20Sopenharmony_ci if (state->revision == 0x4000) 10068c2ecf20Sopenharmony_ci dib7000m_write_word(state, 1793, 0); 10078c2ecf20Sopenharmony_ci else 10088c2ecf20Sopenharmony_ci dib7000m_read_word(state, 537); 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci ret |= dib7000m_write_word(state, 0, (u16) value); 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci return ret; 10138c2ecf20Sopenharmony_ci} 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_cistatic int dib7000m_autosearch_irq(struct dib7000m_state *state, u16 reg) 10168c2ecf20Sopenharmony_ci{ 10178c2ecf20Sopenharmony_ci u16 irq_pending = dib7000m_read_word(state, reg); 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci if (irq_pending & 0x1) { // failed 10208c2ecf20Sopenharmony_ci dprintk("autosearch failed\n"); 10218c2ecf20Sopenharmony_ci return 1; 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci if (irq_pending & 0x2) { // succeeded 10258c2ecf20Sopenharmony_ci dprintk("autosearch succeeded\n"); 10268c2ecf20Sopenharmony_ci return 2; 10278c2ecf20Sopenharmony_ci } 10288c2ecf20Sopenharmony_ci return 0; // still pending 10298c2ecf20Sopenharmony_ci} 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_cistatic int dib7000m_autosearch_is_irq(struct dvb_frontend *demod) 10328c2ecf20Sopenharmony_ci{ 10338c2ecf20Sopenharmony_ci struct dib7000m_state *state = demod->demodulator_priv; 10348c2ecf20Sopenharmony_ci if (state->revision == 0x4000) 10358c2ecf20Sopenharmony_ci return dib7000m_autosearch_irq(state, 1793); 10368c2ecf20Sopenharmony_ci else 10378c2ecf20Sopenharmony_ci return dib7000m_autosearch_irq(state, 537); 10388c2ecf20Sopenharmony_ci} 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_cistatic int dib7000m_tune(struct dvb_frontend *demod) 10418c2ecf20Sopenharmony_ci{ 10428c2ecf20Sopenharmony_ci struct dtv_frontend_properties *ch = &demod->dtv_property_cache; 10438c2ecf20Sopenharmony_ci struct dib7000m_state *state = demod->demodulator_priv; 10448c2ecf20Sopenharmony_ci int ret = 0; 10458c2ecf20Sopenharmony_ci u16 value; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci // we are already tuned - just resuming from suspend 10488c2ecf20Sopenharmony_ci dib7000m_set_channel(state, ch, 0); 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci // restart demod 10518c2ecf20Sopenharmony_ci ret |= dib7000m_write_word(state, 898, 0x4000); 10528c2ecf20Sopenharmony_ci ret |= dib7000m_write_word(state, 898, 0x0000); 10538c2ecf20Sopenharmony_ci msleep(45); 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD); 10568c2ecf20Sopenharmony_ci /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */ 10578c2ecf20Sopenharmony_ci ret |= dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3)); 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci // never achieved a lock before - wait for timfreq to update 10608c2ecf20Sopenharmony_ci if (state->timf == 0) 10618c2ecf20Sopenharmony_ci msleep(200); 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci //dump_reg(state); 10648c2ecf20Sopenharmony_ci /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */ 10658c2ecf20Sopenharmony_ci value = (6 << 8) | 0x80; 10668c2ecf20Sopenharmony_ci switch (ch->transmission_mode) { 10678c2ecf20Sopenharmony_ci case TRANSMISSION_MODE_2K: value |= (7 << 12); break; 10688c2ecf20Sopenharmony_ci case TRANSMISSION_MODE_4K: value |= (8 << 12); break; 10698c2ecf20Sopenharmony_ci default: 10708c2ecf20Sopenharmony_ci case TRANSMISSION_MODE_8K: value |= (9 << 12); break; 10718c2ecf20Sopenharmony_ci } 10728c2ecf20Sopenharmony_ci ret |= dib7000m_write_word(state, 26, value); 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */ 10758c2ecf20Sopenharmony_ci value = (0 << 4); 10768c2ecf20Sopenharmony_ci switch (ch->transmission_mode) { 10778c2ecf20Sopenharmony_ci case TRANSMISSION_MODE_2K: value |= 0x6; break; 10788c2ecf20Sopenharmony_ci case TRANSMISSION_MODE_4K: value |= 0x7; break; 10798c2ecf20Sopenharmony_ci default: 10808c2ecf20Sopenharmony_ci case TRANSMISSION_MODE_8K: value |= 0x8; break; 10818c2ecf20Sopenharmony_ci } 10828c2ecf20Sopenharmony_ci ret |= dib7000m_write_word(state, 32, value); 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */ 10858c2ecf20Sopenharmony_ci value = (0 << 4); 10868c2ecf20Sopenharmony_ci switch (ch->transmission_mode) { 10878c2ecf20Sopenharmony_ci case TRANSMISSION_MODE_2K: value |= 0x6; break; 10888c2ecf20Sopenharmony_ci case TRANSMISSION_MODE_4K: value |= 0x7; break; 10898c2ecf20Sopenharmony_ci default: 10908c2ecf20Sopenharmony_ci case TRANSMISSION_MODE_8K: value |= 0x8; break; 10918c2ecf20Sopenharmony_ci } 10928c2ecf20Sopenharmony_ci ret |= dib7000m_write_word(state, 33, value); 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci // we achieved a lock - it's time to update the timf freq 10958c2ecf20Sopenharmony_ci if ((dib7000m_read_word(state, 535) >> 6) & 0x1) 10968c2ecf20Sopenharmony_ci dib7000m_update_timf(state); 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz)); 10998c2ecf20Sopenharmony_ci return ret; 11008c2ecf20Sopenharmony_ci} 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_cistatic int dib7000m_wakeup(struct dvb_frontend *demod) 11038c2ecf20Sopenharmony_ci{ 11048c2ecf20Sopenharmony_ci struct dib7000m_state *state = demod->demodulator_priv; 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci dib7000m_set_power_mode(state, DIB7000M_POWER_ALL); 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci if (dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0) 11098c2ecf20Sopenharmony_ci dprintk("could not start Slow ADC\n"); 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci return 0; 11128c2ecf20Sopenharmony_ci} 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_cistatic int dib7000m_sleep(struct dvb_frontend *demod) 11158c2ecf20Sopenharmony_ci{ 11168c2ecf20Sopenharmony_ci struct dib7000m_state *st = demod->demodulator_priv; 11178c2ecf20Sopenharmony_ci dib7000m_set_output_mode(st, OUTMODE_HIGH_Z); 11188c2ecf20Sopenharmony_ci dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY); 11198c2ecf20Sopenharmony_ci return dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) | 11208c2ecf20Sopenharmony_ci dib7000m_set_adc_state(st, DIBX000_ADC_OFF); 11218c2ecf20Sopenharmony_ci} 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_cistatic int dib7000m_identify(struct dib7000m_state *state) 11248c2ecf20Sopenharmony_ci{ 11258c2ecf20Sopenharmony_ci u16 value; 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci if ((value = dib7000m_read_word(state, 896)) != 0x01b3) { 11288c2ecf20Sopenharmony_ci dprintk("wrong Vendor ID (0x%x)\n", value); 11298c2ecf20Sopenharmony_ci return -EREMOTEIO; 11308c2ecf20Sopenharmony_ci } 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci state->revision = dib7000m_read_word(state, 897); 11338c2ecf20Sopenharmony_ci if (state->revision != 0x4000 && 11348c2ecf20Sopenharmony_ci state->revision != 0x4001 && 11358c2ecf20Sopenharmony_ci state->revision != 0x4002 && 11368c2ecf20Sopenharmony_ci state->revision != 0x4003) { 11378c2ecf20Sopenharmony_ci dprintk("wrong Device ID (0x%x)\n", value); 11388c2ecf20Sopenharmony_ci return -EREMOTEIO; 11398c2ecf20Sopenharmony_ci } 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci /* protect this driver to be used with 7000PC */ 11428c2ecf20Sopenharmony_ci if (state->revision == 0x4000 && dib7000m_read_word(state, 769) == 0x4000) { 11438c2ecf20Sopenharmony_ci dprintk("this driver does not work with DiB7000PC\n"); 11448c2ecf20Sopenharmony_ci return -EREMOTEIO; 11458c2ecf20Sopenharmony_ci } 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci switch (state->revision) { 11488c2ecf20Sopenharmony_ci case 0x4000: dprintk("found DiB7000MA/PA/MB/PB\n"); break; 11498c2ecf20Sopenharmony_ci case 0x4001: state->reg_offs = 1; dprintk("found DiB7000HC\n"); break; 11508c2ecf20Sopenharmony_ci case 0x4002: state->reg_offs = 1; dprintk("found DiB7000MC\n"); break; 11518c2ecf20Sopenharmony_ci case 0x4003: state->reg_offs = 1; dprintk("found DiB9000\n"); break; 11528c2ecf20Sopenharmony_ci } 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci return 0; 11558c2ecf20Sopenharmony_ci} 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_cistatic int dib7000m_get_frontend(struct dvb_frontend* fe, 11598c2ecf20Sopenharmony_ci struct dtv_frontend_properties *fep) 11608c2ecf20Sopenharmony_ci{ 11618c2ecf20Sopenharmony_ci struct dib7000m_state *state = fe->demodulator_priv; 11628c2ecf20Sopenharmony_ci u16 tps = dib7000m_read_word(state,480); 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci fep->inversion = INVERSION_AUTO; 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci fep->bandwidth_hz = BANDWIDTH_TO_HZ(state->current_bandwidth); 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci switch ((tps >> 8) & 0x3) { 11698c2ecf20Sopenharmony_ci case 0: fep->transmission_mode = TRANSMISSION_MODE_2K; break; 11708c2ecf20Sopenharmony_ci case 1: fep->transmission_mode = TRANSMISSION_MODE_8K; break; 11718c2ecf20Sopenharmony_ci /* case 2: fep->transmission_mode = TRANSMISSION_MODE_4K; break; */ 11728c2ecf20Sopenharmony_ci } 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci switch (tps & 0x3) { 11758c2ecf20Sopenharmony_ci case 0: fep->guard_interval = GUARD_INTERVAL_1_32; break; 11768c2ecf20Sopenharmony_ci case 1: fep->guard_interval = GUARD_INTERVAL_1_16; break; 11778c2ecf20Sopenharmony_ci case 2: fep->guard_interval = GUARD_INTERVAL_1_8; break; 11788c2ecf20Sopenharmony_ci case 3: fep->guard_interval = GUARD_INTERVAL_1_4; break; 11798c2ecf20Sopenharmony_ci } 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci switch ((tps >> 14) & 0x3) { 11828c2ecf20Sopenharmony_ci case 0: fep->modulation = QPSK; break; 11838c2ecf20Sopenharmony_ci case 1: fep->modulation = QAM_16; break; 11848c2ecf20Sopenharmony_ci case 2: 11858c2ecf20Sopenharmony_ci default: fep->modulation = QAM_64; break; 11868c2ecf20Sopenharmony_ci } 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */ 11898c2ecf20Sopenharmony_ci /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */ 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci fep->hierarchy = HIERARCHY_NONE; 11928c2ecf20Sopenharmony_ci switch ((tps >> 5) & 0x7) { 11938c2ecf20Sopenharmony_ci case 1: fep->code_rate_HP = FEC_1_2; break; 11948c2ecf20Sopenharmony_ci case 2: fep->code_rate_HP = FEC_2_3; break; 11958c2ecf20Sopenharmony_ci case 3: fep->code_rate_HP = FEC_3_4; break; 11968c2ecf20Sopenharmony_ci case 5: fep->code_rate_HP = FEC_5_6; break; 11978c2ecf20Sopenharmony_ci case 7: 11988c2ecf20Sopenharmony_ci default: fep->code_rate_HP = FEC_7_8; break; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci } 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci switch ((tps >> 2) & 0x7) { 12038c2ecf20Sopenharmony_ci case 1: fep->code_rate_LP = FEC_1_2; break; 12048c2ecf20Sopenharmony_ci case 2: fep->code_rate_LP = FEC_2_3; break; 12058c2ecf20Sopenharmony_ci case 3: fep->code_rate_LP = FEC_3_4; break; 12068c2ecf20Sopenharmony_ci case 5: fep->code_rate_LP = FEC_5_6; break; 12078c2ecf20Sopenharmony_ci case 7: 12088c2ecf20Sopenharmony_ci default: fep->code_rate_LP = FEC_7_8; break; 12098c2ecf20Sopenharmony_ci } 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci /* native interleaver: (dib7000m_read_word(state, 481) >> 5) & 0x1 */ 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci return 0; 12148c2ecf20Sopenharmony_ci} 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_cistatic int dib7000m_set_frontend(struct dvb_frontend *fe) 12178c2ecf20Sopenharmony_ci{ 12188c2ecf20Sopenharmony_ci struct dtv_frontend_properties *fep = &fe->dtv_property_cache; 12198c2ecf20Sopenharmony_ci struct dib7000m_state *state = fe->demodulator_priv; 12208c2ecf20Sopenharmony_ci int time, ret; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci dib7000m_set_output_mode(state, OUTMODE_HIGH_Z); 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->bandwidth_hz)); 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci if (fe->ops.tuner_ops.set_params) 12278c2ecf20Sopenharmony_ci fe->ops.tuner_ops.set_params(fe); 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci /* start up the AGC */ 12308c2ecf20Sopenharmony_ci state->agc_state = 0; 12318c2ecf20Sopenharmony_ci do { 12328c2ecf20Sopenharmony_ci time = dib7000m_agc_startup(fe); 12338c2ecf20Sopenharmony_ci if (time != -1) 12348c2ecf20Sopenharmony_ci msleep(time); 12358c2ecf20Sopenharmony_ci } while (time != -1); 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci if (fep->transmission_mode == TRANSMISSION_MODE_AUTO || 12388c2ecf20Sopenharmony_ci fep->guard_interval == GUARD_INTERVAL_AUTO || 12398c2ecf20Sopenharmony_ci fep->modulation == QAM_AUTO || 12408c2ecf20Sopenharmony_ci fep->code_rate_HP == FEC_AUTO) { 12418c2ecf20Sopenharmony_ci int i = 800, found; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci dib7000m_autosearch_start(fe); 12448c2ecf20Sopenharmony_ci do { 12458c2ecf20Sopenharmony_ci msleep(1); 12468c2ecf20Sopenharmony_ci found = dib7000m_autosearch_is_irq(fe); 12478c2ecf20Sopenharmony_ci } while (found == 0 && i--); 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci dprintk("autosearch returns: %d\n", found); 12508c2ecf20Sopenharmony_ci if (found == 0 || found == 1) 12518c2ecf20Sopenharmony_ci return 0; // no channel found 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci dib7000m_get_frontend(fe, fep); 12548c2ecf20Sopenharmony_ci } 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci ret = dib7000m_tune(fe); 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci /* make this a config parameter */ 12598c2ecf20Sopenharmony_ci dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO); 12608c2ecf20Sopenharmony_ci return ret; 12618c2ecf20Sopenharmony_ci} 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_cistatic int dib7000m_read_status(struct dvb_frontend *fe, enum fe_status *stat) 12648c2ecf20Sopenharmony_ci{ 12658c2ecf20Sopenharmony_ci struct dib7000m_state *state = fe->demodulator_priv; 12668c2ecf20Sopenharmony_ci u16 lock = dib7000m_read_word(state, 535); 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci *stat = 0; 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci if (lock & 0x8000) 12718c2ecf20Sopenharmony_ci *stat |= FE_HAS_SIGNAL; 12728c2ecf20Sopenharmony_ci if (lock & 0x3000) 12738c2ecf20Sopenharmony_ci *stat |= FE_HAS_CARRIER; 12748c2ecf20Sopenharmony_ci if (lock & 0x0100) 12758c2ecf20Sopenharmony_ci *stat |= FE_HAS_VITERBI; 12768c2ecf20Sopenharmony_ci if (lock & 0x0010) 12778c2ecf20Sopenharmony_ci *stat |= FE_HAS_SYNC; 12788c2ecf20Sopenharmony_ci if (lock & 0x0008) 12798c2ecf20Sopenharmony_ci *stat |= FE_HAS_LOCK; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci return 0; 12828c2ecf20Sopenharmony_ci} 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_cistatic int dib7000m_read_ber(struct dvb_frontend *fe, u32 *ber) 12858c2ecf20Sopenharmony_ci{ 12868c2ecf20Sopenharmony_ci struct dib7000m_state *state = fe->demodulator_priv; 12878c2ecf20Sopenharmony_ci *ber = (dib7000m_read_word(state, 526) << 16) | dib7000m_read_word(state, 527); 12888c2ecf20Sopenharmony_ci return 0; 12898c2ecf20Sopenharmony_ci} 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_cistatic int dib7000m_read_unc_blocks(struct dvb_frontend *fe, u32 *unc) 12928c2ecf20Sopenharmony_ci{ 12938c2ecf20Sopenharmony_ci struct dib7000m_state *state = fe->demodulator_priv; 12948c2ecf20Sopenharmony_ci *unc = dib7000m_read_word(state, 534); 12958c2ecf20Sopenharmony_ci return 0; 12968c2ecf20Sopenharmony_ci} 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_cistatic int dib7000m_read_signal_strength(struct dvb_frontend *fe, u16 *strength) 12998c2ecf20Sopenharmony_ci{ 13008c2ecf20Sopenharmony_ci struct dib7000m_state *state = fe->demodulator_priv; 13018c2ecf20Sopenharmony_ci u16 val = dib7000m_read_word(state, 390); 13028c2ecf20Sopenharmony_ci *strength = 65535 - val; 13038c2ecf20Sopenharmony_ci return 0; 13048c2ecf20Sopenharmony_ci} 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_cistatic int dib7000m_read_snr(struct dvb_frontend* fe, u16 *snr) 13078c2ecf20Sopenharmony_ci{ 13088c2ecf20Sopenharmony_ci *snr = 0x0000; 13098c2ecf20Sopenharmony_ci return 0; 13108c2ecf20Sopenharmony_ci} 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_cistatic int dib7000m_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) 13138c2ecf20Sopenharmony_ci{ 13148c2ecf20Sopenharmony_ci tune->min_delay_ms = 1000; 13158c2ecf20Sopenharmony_ci return 0; 13168c2ecf20Sopenharmony_ci} 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_cistatic void dib7000m_release(struct dvb_frontend *demod) 13198c2ecf20Sopenharmony_ci{ 13208c2ecf20Sopenharmony_ci struct dib7000m_state *st = demod->demodulator_priv; 13218c2ecf20Sopenharmony_ci dibx000_exit_i2c_master(&st->i2c_master); 13228c2ecf20Sopenharmony_ci kfree(st); 13238c2ecf20Sopenharmony_ci} 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_cistruct i2c_adapter * dib7000m_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating) 13268c2ecf20Sopenharmony_ci{ 13278c2ecf20Sopenharmony_ci struct dib7000m_state *st = demod->demodulator_priv; 13288c2ecf20Sopenharmony_ci return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating); 13298c2ecf20Sopenharmony_ci} 13308c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dib7000m_get_i2c_master); 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ciint dib7000m_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) 13338c2ecf20Sopenharmony_ci{ 13348c2ecf20Sopenharmony_ci struct dib7000m_state *state = fe->demodulator_priv; 13358c2ecf20Sopenharmony_ci u16 val = dib7000m_read_word(state, 294 + state->reg_offs) & 0xffef; 13368c2ecf20Sopenharmony_ci val |= (onoff & 0x1) << 4; 13378c2ecf20Sopenharmony_ci dprintk("PID filter enabled %d\n", onoff); 13388c2ecf20Sopenharmony_ci return dib7000m_write_word(state, 294 + state->reg_offs, val); 13398c2ecf20Sopenharmony_ci} 13408c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dib7000m_pid_filter_ctrl); 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ciint dib7000m_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) 13438c2ecf20Sopenharmony_ci{ 13448c2ecf20Sopenharmony_ci struct dib7000m_state *state = fe->demodulator_priv; 13458c2ecf20Sopenharmony_ci dprintk("PID filter: index %x, PID %d, OnOff %d\n", id, pid, onoff); 13468c2ecf20Sopenharmony_ci return dib7000m_write_word(state, 300 + state->reg_offs + id, 13478c2ecf20Sopenharmony_ci onoff ? (1 << 13) | pid : 0); 13488c2ecf20Sopenharmony_ci} 13498c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dib7000m_pid_filter); 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci#if 0 13528c2ecf20Sopenharmony_ci/* used with some prototype boards */ 13538c2ecf20Sopenharmony_ciint dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, 13548c2ecf20Sopenharmony_ci u8 default_addr, struct dib7000m_config cfg[]) 13558c2ecf20Sopenharmony_ci{ 13568c2ecf20Sopenharmony_ci struct dib7000m_state st = { .i2c_adap = i2c }; 13578c2ecf20Sopenharmony_ci int k = 0; 13588c2ecf20Sopenharmony_ci u8 new_addr = 0; 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci for (k = no_of_demods-1; k >= 0; k--) { 13618c2ecf20Sopenharmony_ci st.cfg = cfg[k]; 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci /* designated i2c address */ 13648c2ecf20Sopenharmony_ci new_addr = (0x40 + k) << 1; 13658c2ecf20Sopenharmony_ci st.i2c_addr = new_addr; 13668c2ecf20Sopenharmony_ci if (dib7000m_identify(&st) != 0) { 13678c2ecf20Sopenharmony_ci st.i2c_addr = default_addr; 13688c2ecf20Sopenharmony_ci if (dib7000m_identify(&st) != 0) { 13698c2ecf20Sopenharmony_ci dprintk("DiB7000M #%d: not identified\n", k); 13708c2ecf20Sopenharmony_ci return -EIO; 13718c2ecf20Sopenharmony_ci } 13728c2ecf20Sopenharmony_ci } 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci /* start diversity to pull_down div_str - just for i2c-enumeration */ 13758c2ecf20Sopenharmony_ci dib7000m_set_output_mode(&st, OUTMODE_DIVERSITY); 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci dib7000m_write_word(&st, 1796, 0x0); // select DVB-T output 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci /* set new i2c address and force divstart */ 13808c2ecf20Sopenharmony_ci dib7000m_write_word(&st, 1794, (new_addr << 2) | 0x2); 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr); 13838c2ecf20Sopenharmony_ci } 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci for (k = 0; k < no_of_demods; k++) { 13868c2ecf20Sopenharmony_ci st.cfg = cfg[k]; 13878c2ecf20Sopenharmony_ci st.i2c_addr = (0x40 + k) << 1; 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci // unforce divstr 13908c2ecf20Sopenharmony_ci dib7000m_write_word(&st,1794, st.i2c_addr << 2); 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci /* deactivate div - it was just for i2c-enumeration */ 13938c2ecf20Sopenharmony_ci dib7000m_set_output_mode(&st, OUTMODE_HIGH_Z); 13948c2ecf20Sopenharmony_ci } 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci return 0; 13978c2ecf20Sopenharmony_ci} 13988c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dib7000m_i2c_enumeration); 13998c2ecf20Sopenharmony_ci#endif 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops dib7000m_ops; 14028c2ecf20Sopenharmony_cistruct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000m_config *cfg) 14038c2ecf20Sopenharmony_ci{ 14048c2ecf20Sopenharmony_ci struct dvb_frontend *demod; 14058c2ecf20Sopenharmony_ci struct dib7000m_state *st; 14068c2ecf20Sopenharmony_ci st = kzalloc(sizeof(struct dib7000m_state), GFP_KERNEL); 14078c2ecf20Sopenharmony_ci if (st == NULL) 14088c2ecf20Sopenharmony_ci return NULL; 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci memcpy(&st->cfg, cfg, sizeof(struct dib7000m_config)); 14118c2ecf20Sopenharmony_ci st->i2c_adap = i2c_adap; 14128c2ecf20Sopenharmony_ci st->i2c_addr = i2c_addr; 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci demod = &st->demod; 14158c2ecf20Sopenharmony_ci demod->demodulator_priv = st; 14168c2ecf20Sopenharmony_ci memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops)); 14178c2ecf20Sopenharmony_ci mutex_init(&st->i2c_buffer_lock); 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci st->timf_default = cfg->bw->timf; 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci if (dib7000m_identify(st) != 0) 14228c2ecf20Sopenharmony_ci goto error; 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci if (st->revision == 0x4000) 14258c2ecf20Sopenharmony_ci dibx000_init_i2c_master(&st->i2c_master, DIB7000, st->i2c_adap, st->i2c_addr); 14268c2ecf20Sopenharmony_ci else 14278c2ecf20Sopenharmony_ci dibx000_init_i2c_master(&st->i2c_master, DIB7000MC, st->i2c_adap, st->i2c_addr); 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci dib7000m_demod_reset(st); 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci return demod; 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_cierror: 14348c2ecf20Sopenharmony_ci kfree(st); 14358c2ecf20Sopenharmony_ci return NULL; 14368c2ecf20Sopenharmony_ci} 14378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dib7000m_attach); 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops dib7000m_ops = { 14408c2ecf20Sopenharmony_ci .delsys = { SYS_DVBT }, 14418c2ecf20Sopenharmony_ci .info = { 14428c2ecf20Sopenharmony_ci .name = "DiBcom 7000MA/MB/PA/PB/MC", 14438c2ecf20Sopenharmony_ci .frequency_min_hz = 44250 * kHz, 14448c2ecf20Sopenharmony_ci .frequency_max_hz = 867250 * kHz, 14458c2ecf20Sopenharmony_ci .frequency_stepsize_hz = 62500, 14468c2ecf20Sopenharmony_ci .caps = FE_CAN_INVERSION_AUTO | 14478c2ecf20Sopenharmony_ci FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 14488c2ecf20Sopenharmony_ci FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | 14498c2ecf20Sopenharmony_ci FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | 14508c2ecf20Sopenharmony_ci FE_CAN_TRANSMISSION_MODE_AUTO | 14518c2ecf20Sopenharmony_ci FE_CAN_GUARD_INTERVAL_AUTO | 14528c2ecf20Sopenharmony_ci FE_CAN_RECOVER | 14538c2ecf20Sopenharmony_ci FE_CAN_HIERARCHY_AUTO, 14548c2ecf20Sopenharmony_ci }, 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci .release = dib7000m_release, 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci .init = dib7000m_wakeup, 14598c2ecf20Sopenharmony_ci .sleep = dib7000m_sleep, 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci .set_frontend = dib7000m_set_frontend, 14628c2ecf20Sopenharmony_ci .get_tune_settings = dib7000m_fe_get_tune_settings, 14638c2ecf20Sopenharmony_ci .get_frontend = dib7000m_get_frontend, 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci .read_status = dib7000m_read_status, 14668c2ecf20Sopenharmony_ci .read_ber = dib7000m_read_ber, 14678c2ecf20Sopenharmony_ci .read_signal_strength = dib7000m_read_signal_strength, 14688c2ecf20Sopenharmony_ci .read_snr = dib7000m_read_snr, 14698c2ecf20Sopenharmony_ci .read_ucblocks = dib7000m_read_unc_blocks, 14708c2ecf20Sopenharmony_ci}; 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ciMODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>"); 14738c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Driver for the DiBcom 7000MA/MB/PA/PB/MC COFDM demodulator"); 14748c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1475