18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2005-9 DiBcom (http://www.dibcom.fr/) 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This code is more or less generated from another driver, please 88c2ecf20Sopenharmony_ci * excuse some codingstyle oddities. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/i2c.h> 168c2ecf20Sopenharmony_ci#include <linux/mutex.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "dib0070.h" 218c2ecf20Sopenharmony_ci#include "dibx000_common.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic int debug; 248c2ecf20Sopenharmony_cimodule_param(debug, int, 0644); 258c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define dprintk(fmt, arg...) do { \ 288c2ecf20Sopenharmony_ci if (debug) \ 298c2ecf20Sopenharmony_ci printk(KERN_DEBUG pr_fmt("%s: " fmt), \ 308c2ecf20Sopenharmony_ci __func__, ##arg); \ 318c2ecf20Sopenharmony_ci} while (0) 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define DIB0070_P1D 0x00 348c2ecf20Sopenharmony_ci#define DIB0070_P1F 0x01 358c2ecf20Sopenharmony_ci#define DIB0070_P1G 0x03 368c2ecf20Sopenharmony_ci#define DIB0070S_P1A 0x02 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistruct dib0070_state { 398c2ecf20Sopenharmony_ci struct i2c_adapter *i2c; 408c2ecf20Sopenharmony_ci struct dvb_frontend *fe; 418c2ecf20Sopenharmony_ci const struct dib0070_config *cfg; 428c2ecf20Sopenharmony_ci u16 wbd_ff_offset; 438c2ecf20Sopenharmony_ci u8 revision; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci enum frontend_tune_state tune_state; 468c2ecf20Sopenharmony_ci u32 current_rf; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci /* for the captrim binary search */ 498c2ecf20Sopenharmony_ci s8 step; 508c2ecf20Sopenharmony_ci u16 adc_diff; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci s8 captrim; 538c2ecf20Sopenharmony_ci s8 fcaptrim; 548c2ecf20Sopenharmony_ci u16 lo4; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci const struct dib0070_tuning *current_tune_table_index; 578c2ecf20Sopenharmony_ci const struct dib0070_lna_match *lna_match; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci u8 wbd_gain_current; 608c2ecf20Sopenharmony_ci u16 wbd_offset_3_3[2]; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci /* for the I2C transfer */ 638c2ecf20Sopenharmony_ci struct i2c_msg msg[2]; 648c2ecf20Sopenharmony_ci u8 i2c_write_buffer[3]; 658c2ecf20Sopenharmony_ci u8 i2c_read_buffer[2]; 668c2ecf20Sopenharmony_ci struct mutex i2c_buffer_lock; 678c2ecf20Sopenharmony_ci}; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic u16 dib0070_read_reg(struct dib0070_state *state, u8 reg) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci u16 ret; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { 748c2ecf20Sopenharmony_ci dprintk("could not acquire lock\n"); 758c2ecf20Sopenharmony_ci return 0; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci state->i2c_write_buffer[0] = reg; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci memset(state->msg, 0, 2 * sizeof(struct i2c_msg)); 818c2ecf20Sopenharmony_ci state->msg[0].addr = state->cfg->i2c_address; 828c2ecf20Sopenharmony_ci state->msg[0].flags = 0; 838c2ecf20Sopenharmony_ci state->msg[0].buf = state->i2c_write_buffer; 848c2ecf20Sopenharmony_ci state->msg[0].len = 1; 858c2ecf20Sopenharmony_ci state->msg[1].addr = state->cfg->i2c_address; 868c2ecf20Sopenharmony_ci state->msg[1].flags = I2C_M_RD; 878c2ecf20Sopenharmony_ci state->msg[1].buf = state->i2c_read_buffer; 888c2ecf20Sopenharmony_ci state->msg[1].len = 2; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci if (i2c_transfer(state->i2c, state->msg, 2) != 2) { 918c2ecf20Sopenharmony_ci pr_warn("DiB0070 I2C read failed\n"); 928c2ecf20Sopenharmony_ci ret = 0; 938c2ecf20Sopenharmony_ci } else 948c2ecf20Sopenharmony_ci ret = (state->i2c_read_buffer[0] << 8) 958c2ecf20Sopenharmony_ci | state->i2c_read_buffer[1]; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci mutex_unlock(&state->i2c_buffer_lock); 988c2ecf20Sopenharmony_ci return ret; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci int ret; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { 1068c2ecf20Sopenharmony_ci dprintk("could not acquire lock\n"); 1078c2ecf20Sopenharmony_ci return -EINVAL; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci state->i2c_write_buffer[0] = reg; 1108c2ecf20Sopenharmony_ci state->i2c_write_buffer[1] = val >> 8; 1118c2ecf20Sopenharmony_ci state->i2c_write_buffer[2] = val & 0xff; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci memset(state->msg, 0, sizeof(struct i2c_msg)); 1148c2ecf20Sopenharmony_ci state->msg[0].addr = state->cfg->i2c_address; 1158c2ecf20Sopenharmony_ci state->msg[0].flags = 0; 1168c2ecf20Sopenharmony_ci state->msg[0].buf = state->i2c_write_buffer; 1178c2ecf20Sopenharmony_ci state->msg[0].len = 3; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if (i2c_transfer(state->i2c, state->msg, 1) != 1) { 1208c2ecf20Sopenharmony_ci pr_warn("DiB0070 I2C write failed\n"); 1218c2ecf20Sopenharmony_ci ret = -EREMOTEIO; 1228c2ecf20Sopenharmony_ci } else 1238c2ecf20Sopenharmony_ci ret = 0; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci mutex_unlock(&state->i2c_buffer_lock); 1268c2ecf20Sopenharmony_ci return ret; 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci#define HARD_RESET(state) do { \ 1308c2ecf20Sopenharmony_ci state->cfg->sleep(state->fe, 0); \ 1318c2ecf20Sopenharmony_ci if (state->cfg->reset) { \ 1328c2ecf20Sopenharmony_ci state->cfg->reset(state->fe,1); msleep(10); \ 1338c2ecf20Sopenharmony_ci state->cfg->reset(state->fe,0); msleep(10); \ 1348c2ecf20Sopenharmony_ci } \ 1358c2ecf20Sopenharmony_ci} while (0) 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic int dib0070_set_bandwidth(struct dvb_frontend *fe) 1388c2ecf20Sopenharmony_ci { 1398c2ecf20Sopenharmony_ci struct dib0070_state *state = fe->tuner_priv; 1408c2ecf20Sopenharmony_ci u16 tmp = dib0070_read_reg(state, 0x02) & 0x3fff; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 7000) 1438c2ecf20Sopenharmony_ci tmp |= (0 << 14); 1448c2ecf20Sopenharmony_ci else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 6000) 1458c2ecf20Sopenharmony_ci tmp |= (1 << 14); 1468c2ecf20Sopenharmony_ci else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 5000) 1478c2ecf20Sopenharmony_ci tmp |= (2 << 14); 1488c2ecf20Sopenharmony_ci else 1498c2ecf20Sopenharmony_ci tmp |= (3 << 14); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x02, tmp); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci /* sharpen the BB filter in ISDB-T to have higher immunity to adjacent channels */ 1548c2ecf20Sopenharmony_ci if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) { 1558c2ecf20Sopenharmony_ci u16 value = dib0070_read_reg(state, 0x17); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x17, value & 0xfffc); 1588c2ecf20Sopenharmony_ci tmp = dib0070_read_reg(state, 0x01) & 0x01ff; 1598c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x01, tmp | (60 << 9)); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x17, value); 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci return 0; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state *tune_state) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci int8_t step_sign; 1698c2ecf20Sopenharmony_ci u16 adc; 1708c2ecf20Sopenharmony_ci int ret = 0; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (*tune_state == CT_TUNER_STEP_0) { 1738c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x0f, 0xed10); 1748c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x17, 0x0034); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x18, 0x0032); 1778c2ecf20Sopenharmony_ci state->step = state->captrim = state->fcaptrim = 64; 1788c2ecf20Sopenharmony_ci state->adc_diff = 3000; 1798c2ecf20Sopenharmony_ci ret = 20; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci *tune_state = CT_TUNER_STEP_1; 1828c2ecf20Sopenharmony_ci } else if (*tune_state == CT_TUNER_STEP_1) { 1838c2ecf20Sopenharmony_ci state->step /= 2; 1848c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x14, state->lo4 | state->captrim); 1858c2ecf20Sopenharmony_ci ret = 15; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci *tune_state = CT_TUNER_STEP_2; 1888c2ecf20Sopenharmony_ci } else if (*tune_state == CT_TUNER_STEP_2) { 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci adc = dib0070_read_reg(state, 0x19); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci dprintk("CAPTRIM=%d; ADC = %hd (ADC) & %dmV\n", state->captrim, 1938c2ecf20Sopenharmony_ci adc, (u32)adc * (u32)1800 / (u32)1024); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (adc >= 400) { 1968c2ecf20Sopenharmony_ci adc -= 400; 1978c2ecf20Sopenharmony_ci step_sign = -1; 1988c2ecf20Sopenharmony_ci } else { 1998c2ecf20Sopenharmony_ci adc = 400 - adc; 2008c2ecf20Sopenharmony_ci step_sign = 1; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (adc < state->adc_diff) { 2048c2ecf20Sopenharmony_ci dprintk("CAPTRIM=%d is closer to target (%hd/%hd)\n", 2058c2ecf20Sopenharmony_ci state->captrim, adc, state->adc_diff); 2068c2ecf20Sopenharmony_ci state->adc_diff = adc; 2078c2ecf20Sopenharmony_ci state->fcaptrim = state->captrim; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci state->captrim += (step_sign * state->step); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci if (state->step >= 1) 2128c2ecf20Sopenharmony_ci *tune_state = CT_TUNER_STEP_1; 2138c2ecf20Sopenharmony_ci else 2148c2ecf20Sopenharmony_ci *tune_state = CT_TUNER_STEP_3; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci } else if (*tune_state == CT_TUNER_STEP_3) { 2178c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x14, state->lo4 | state->fcaptrim); 2188c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x18, 0x07ff); 2198c2ecf20Sopenharmony_ci *tune_state = CT_TUNER_STEP_4; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci return ret; 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci struct dib0070_state *state = fe->tuner_priv; 2288c2ecf20Sopenharmony_ci u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci dprintk("CTRL_LO5: 0x%x\n", lo5); 2318c2ecf20Sopenharmony_ci return dib0070_write_reg(state, 0x15, lo5); 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_civoid dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci struct dib0070_state *state = fe->tuner_priv; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (open) { 2398c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x1b, 0xff00); 2408c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x1a, 0x0000); 2418c2ecf20Sopenharmony_ci } else { 2428c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x1b, 0x4112); 2438c2ecf20Sopenharmony_ci if (state->cfg->vga_filter != 0) { 2448c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x1a, state->cfg->vga_filter); 2458c2ecf20Sopenharmony_ci dprintk("vga filter register is set to %x\n", state->cfg->vga_filter); 2468c2ecf20Sopenharmony_ci } else 2478c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x1a, 0x0009); 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dib0070_ctrl_agc_filter); 2528c2ecf20Sopenharmony_cistruct dib0070_tuning { 2538c2ecf20Sopenharmony_ci u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ 2548c2ecf20Sopenharmony_ci u8 switch_trim; 2558c2ecf20Sopenharmony_ci u8 vco_band; 2568c2ecf20Sopenharmony_ci u8 hfdiv; 2578c2ecf20Sopenharmony_ci u8 vco_multi; 2588c2ecf20Sopenharmony_ci u8 presc; 2598c2ecf20Sopenharmony_ci u8 wbdmux; 2608c2ecf20Sopenharmony_ci u16 tuner_enable; 2618c2ecf20Sopenharmony_ci}; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistruct dib0070_lna_match { 2648c2ecf20Sopenharmony_ci u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ 2658c2ecf20Sopenharmony_ci u8 lna_band; 2668c2ecf20Sopenharmony_ci}; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic const struct dib0070_tuning dib0070s_tuning_table[] = { 2698c2ecf20Sopenharmony_ci { 570000, 2, 1, 3, 6, 6, 2, 0x4000 | 0x0800 }, /* UHF */ 2708c2ecf20Sopenharmony_ci { 700000, 2, 0, 2, 4, 2, 2, 0x4000 | 0x0800 }, 2718c2ecf20Sopenharmony_ci { 863999, 2, 1, 2, 4, 2, 2, 0x4000 | 0x0800 }, 2728c2ecf20Sopenharmony_ci { 1500000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND */ 2738c2ecf20Sopenharmony_ci { 1600000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, 2748c2ecf20Sopenharmony_ci { 2000000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, 2758c2ecf20Sopenharmony_ci { 0xffffffff, 0, 0, 8, 1, 2, 1, 0x8000 | 0x1000 }, /* SBAND */ 2768c2ecf20Sopenharmony_ci}; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic const struct dib0070_tuning dib0070_tuning_table[] = { 2798c2ecf20Sopenharmony_ci { 115000, 1, 0, 7, 24, 2, 1, 0x8000 | 0x1000 }, /* FM below 92MHz cannot be tuned */ 2808c2ecf20Sopenharmony_ci { 179500, 1, 0, 3, 16, 2, 1, 0x8000 | 0x1000 }, /* VHF */ 2818c2ecf20Sopenharmony_ci { 189999, 1, 1, 3, 16, 2, 1, 0x8000 | 0x1000 }, 2828c2ecf20Sopenharmony_ci { 250000, 1, 0, 6, 12, 2, 1, 0x8000 | 0x1000 }, 2838c2ecf20Sopenharmony_ci { 569999, 2, 1, 5, 6, 2, 2, 0x4000 | 0x0800 }, /* UHF */ 2848c2ecf20Sopenharmony_ci { 699999, 2, 0, 1, 4, 2, 2, 0x4000 | 0x0800 }, 2858c2ecf20Sopenharmony_ci { 863999, 2, 1, 1, 4, 2, 2, 0x4000 | 0x0800 }, 2868c2ecf20Sopenharmony_ci { 0xffffffff, 0, 1, 0, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND or everything higher than UHF */ 2878c2ecf20Sopenharmony_ci}; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic const struct dib0070_lna_match dib0070_lna_flip_chip[] = { 2908c2ecf20Sopenharmony_ci { 180000, 0 }, /* VHF */ 2918c2ecf20Sopenharmony_ci { 188000, 1 }, 2928c2ecf20Sopenharmony_ci { 196400, 2 }, 2938c2ecf20Sopenharmony_ci { 250000, 3 }, 2948c2ecf20Sopenharmony_ci { 550000, 0 }, /* UHF */ 2958c2ecf20Sopenharmony_ci { 590000, 1 }, 2968c2ecf20Sopenharmony_ci { 666000, 3 }, 2978c2ecf20Sopenharmony_ci { 864000, 5 }, 2988c2ecf20Sopenharmony_ci { 1500000, 0 }, /* LBAND or everything higher than UHF */ 2998c2ecf20Sopenharmony_ci { 1600000, 1 }, 3008c2ecf20Sopenharmony_ci { 2000000, 3 }, 3018c2ecf20Sopenharmony_ci { 0xffffffff, 7 }, 3028c2ecf20Sopenharmony_ci}; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic const struct dib0070_lna_match dib0070_lna[] = { 3058c2ecf20Sopenharmony_ci { 180000, 0 }, /* VHF */ 3068c2ecf20Sopenharmony_ci { 188000, 1 }, 3078c2ecf20Sopenharmony_ci { 196400, 2 }, 3088c2ecf20Sopenharmony_ci { 250000, 3 }, 3098c2ecf20Sopenharmony_ci { 550000, 2 }, /* UHF */ 3108c2ecf20Sopenharmony_ci { 650000, 3 }, 3118c2ecf20Sopenharmony_ci { 750000, 5 }, 3128c2ecf20Sopenharmony_ci { 850000, 6 }, 3138c2ecf20Sopenharmony_ci { 864000, 7 }, 3148c2ecf20Sopenharmony_ci { 1500000, 0 }, /* LBAND or everything higher than UHF */ 3158c2ecf20Sopenharmony_ci { 1600000, 1 }, 3168c2ecf20Sopenharmony_ci { 2000000, 3 }, 3178c2ecf20Sopenharmony_ci { 0xffffffff, 7 }, 3188c2ecf20Sopenharmony_ci}; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci#define LPF 100 3218c2ecf20Sopenharmony_cistatic int dib0070_tune_digital(struct dvb_frontend *fe) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci struct dib0070_state *state = fe->tuner_priv; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci const struct dib0070_tuning *tune; 3268c2ecf20Sopenharmony_ci const struct dib0070_lna_match *lna_match; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci enum frontend_tune_state *tune_state = &state->tune_state; 3298c2ecf20Sopenharmony_ci int ret = 10; /* 1ms is the default delay most of the time */ 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci u8 band = (u8)BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency/1000); 3328c2ecf20Sopenharmony_ci u32 freq = fe->dtv_property_cache.frequency/1000 + (band == BAND_VHF ? state->cfg->freq_offset_khz_vhf : state->cfg->freq_offset_khz_uhf); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci#ifdef CONFIG_SYS_ISDBT 3358c2ecf20Sopenharmony_ci if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1) 3368c2ecf20Sopenharmony_ci if (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) 3378c2ecf20Sopenharmony_ci && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))) 3388c2ecf20Sopenharmony_ci || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) 3398c2ecf20Sopenharmony_ci && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == (state->fe->dtv_property_cache.isdbt_sb_segment_count / 2))) 3408c2ecf20Sopenharmony_ci || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) 3418c2ecf20Sopenharmony_ci && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))) 3428c2ecf20Sopenharmony_ci freq += 850; 3438c2ecf20Sopenharmony_ci#endif 3448c2ecf20Sopenharmony_ci if (state->current_rf != freq) { 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci switch (state->revision) { 3478c2ecf20Sopenharmony_ci case DIB0070S_P1A: 3488c2ecf20Sopenharmony_ci tune = dib0070s_tuning_table; 3498c2ecf20Sopenharmony_ci lna_match = dib0070_lna; 3508c2ecf20Sopenharmony_ci break; 3518c2ecf20Sopenharmony_ci default: 3528c2ecf20Sopenharmony_ci tune = dib0070_tuning_table; 3538c2ecf20Sopenharmony_ci if (state->cfg->flip_chip) 3548c2ecf20Sopenharmony_ci lna_match = dib0070_lna_flip_chip; 3558c2ecf20Sopenharmony_ci else 3568c2ecf20Sopenharmony_ci lna_match = dib0070_lna; 3578c2ecf20Sopenharmony_ci break; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci while (freq > tune->max_freq) /* find the right one */ 3608c2ecf20Sopenharmony_ci tune++; 3618c2ecf20Sopenharmony_ci while (freq > lna_match->max_freq) /* find the right one */ 3628c2ecf20Sopenharmony_ci lna_match++; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci state->current_tune_table_index = tune; 3658c2ecf20Sopenharmony_ci state->lna_match = lna_match; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci if (*tune_state == CT_TUNER_START) { 3698c2ecf20Sopenharmony_ci dprintk("Tuning for Band: %d (%d kHz)\n", band, freq); 3708c2ecf20Sopenharmony_ci if (state->current_rf != freq) { 3718c2ecf20Sopenharmony_ci u8 REFDIV; 3728c2ecf20Sopenharmony_ci u32 FBDiv, Rest, FREF, VCOF_kHz; 3738c2ecf20Sopenharmony_ci u8 Den; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci state->current_rf = freq; 3768c2ecf20Sopenharmony_ci state->lo4 = (state->current_tune_table_index->vco_band << 11) | (state->current_tune_table_index->hfdiv << 7); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x17, 0x30); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci VCOF_kHz = state->current_tune_table_index->vco_multi * freq * 2; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci switch (band) { 3858c2ecf20Sopenharmony_ci case BAND_VHF: 3868c2ecf20Sopenharmony_ci REFDIV = (u8) ((state->cfg->clock_khz + 9999) / 10000); 3878c2ecf20Sopenharmony_ci break; 3888c2ecf20Sopenharmony_ci case BAND_FM: 3898c2ecf20Sopenharmony_ci REFDIV = (u8) ((state->cfg->clock_khz) / 1000); 3908c2ecf20Sopenharmony_ci break; 3918c2ecf20Sopenharmony_ci default: 3928c2ecf20Sopenharmony_ci REFDIV = (u8) (state->cfg->clock_khz / 10000); 3938c2ecf20Sopenharmony_ci break; 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci FREF = state->cfg->clock_khz / REFDIV; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci switch (state->revision) { 4008c2ecf20Sopenharmony_ci case DIB0070S_P1A: 4018c2ecf20Sopenharmony_ci FBDiv = (VCOF_kHz / state->current_tune_table_index->presc / FREF); 4028c2ecf20Sopenharmony_ci Rest = (VCOF_kHz / state->current_tune_table_index->presc) - FBDiv * FREF; 4038c2ecf20Sopenharmony_ci break; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci case DIB0070_P1G: 4068c2ecf20Sopenharmony_ci case DIB0070_P1F: 4078c2ecf20Sopenharmony_ci default: 4088c2ecf20Sopenharmony_ci FBDiv = (freq / (FREF / 2)); 4098c2ecf20Sopenharmony_ci Rest = 2 * freq - FBDiv * FREF; 4108c2ecf20Sopenharmony_ci break; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (Rest < LPF) 4148c2ecf20Sopenharmony_ci Rest = 0; 4158c2ecf20Sopenharmony_ci else if (Rest < 2 * LPF) 4168c2ecf20Sopenharmony_ci Rest = 2 * LPF; 4178c2ecf20Sopenharmony_ci else if (Rest > (FREF - LPF)) { 4188c2ecf20Sopenharmony_ci Rest = 0; 4198c2ecf20Sopenharmony_ci FBDiv += 1; 4208c2ecf20Sopenharmony_ci } else if (Rest > (FREF - 2 * LPF)) 4218c2ecf20Sopenharmony_ci Rest = FREF - 2 * LPF; 4228c2ecf20Sopenharmony_ci Rest = (Rest * 6528) / (FREF / 10); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci Den = 1; 4258c2ecf20Sopenharmony_ci if (Rest > 0) { 4268c2ecf20Sopenharmony_ci state->lo4 |= (1 << 14) | (1 << 12); 4278c2ecf20Sopenharmony_ci Den = 255; 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x11, (u16)FBDiv); 4328c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x12, (Den << 8) | REFDIV); 4338c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x13, (u16) Rest); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci if (state->revision == DIB0070S_P1A) { 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (band == BAND_SBAND) { 4388c2ecf20Sopenharmony_ci dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0); 4398c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x1d, 0xFFFF); 4408c2ecf20Sopenharmony_ci } else 4418c2ecf20Sopenharmony_ci dib0070_set_ctrl_lo5(fe, 5, 4, 3, 1); 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x20, 4458c2ecf20Sopenharmony_ci 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001 | state->current_tune_table_index->tuner_enable); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci dprintk("REFDIV: %u, FREF: %d\n", REFDIV, FREF); 4488c2ecf20Sopenharmony_ci dprintk("FBDIV: %d, Rest: %d\n", FBDiv, Rest); 4498c2ecf20Sopenharmony_ci dprintk("Num: %u, Den: %u, SD: %d\n", (u16)Rest, Den, 4508c2ecf20Sopenharmony_ci (state->lo4 >> 12) & 0x1); 4518c2ecf20Sopenharmony_ci dprintk("HFDIV code: %u\n", 4528c2ecf20Sopenharmony_ci state->current_tune_table_index->hfdiv); 4538c2ecf20Sopenharmony_ci dprintk("VCO = %u\n", 4548c2ecf20Sopenharmony_ci state->current_tune_table_index->vco_band); 4558c2ecf20Sopenharmony_ci dprintk("VCOF: ((%u*%d) << 1))\n", 4568c2ecf20Sopenharmony_ci state->current_tune_table_index->vco_multi, 4578c2ecf20Sopenharmony_ci freq); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci *tune_state = CT_TUNER_STEP_0; 4608c2ecf20Sopenharmony_ci } else { /* we are already tuned to this frequency - the configuration is correct */ 4618c2ecf20Sopenharmony_ci ret = 50; /* wakeup time */ 4628c2ecf20Sopenharmony_ci *tune_state = CT_TUNER_STEP_5; 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci } else if ((*tune_state > CT_TUNER_START) && (*tune_state < CT_TUNER_STEP_4)) { 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci ret = dib0070_captrim(state, tune_state); 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci } else if (*tune_state == CT_TUNER_STEP_4) { 4698c2ecf20Sopenharmony_ci const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain; 4708c2ecf20Sopenharmony_ci if (tmp != NULL) { 4718c2ecf20Sopenharmony_ci while (freq/1000 > tmp->freq) /* find the right one */ 4728c2ecf20Sopenharmony_ci tmp++; 4738c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x0f, 4748c2ecf20Sopenharmony_ci (0 << 15) | (1 << 14) | (3 << 12) 4758c2ecf20Sopenharmony_ci | (tmp->wbd_gain_val << 9) | (0 << 8) | (1 << 7) 4768c2ecf20Sopenharmony_ci | (state->current_tune_table_index->wbdmux << 0)); 4778c2ecf20Sopenharmony_ci state->wbd_gain_current = tmp->wbd_gain_val; 4788c2ecf20Sopenharmony_ci } else { 4798c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x0f, 4808c2ecf20Sopenharmony_ci (0 << 15) | (1 << 14) | (3 << 12) 4818c2ecf20Sopenharmony_ci | (6 << 9) | (0 << 8) | (1 << 7) 4828c2ecf20Sopenharmony_ci | (state->current_tune_table_index->wbdmux << 0)); 4838c2ecf20Sopenharmony_ci state->wbd_gain_current = 6; 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x06, 0x3fff); 4878c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x07, 4888c2ecf20Sopenharmony_ci (state->current_tune_table_index->switch_trim << 11) | (7 << 8) | (state->lna_match->lna_band << 3) | (3 << 0)); 4898c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x08, (state->lna_match->lna_band << 10) | (3 << 7) | (127)); 4908c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x0d, 0x0d80); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x18, 0x07ff); 4948c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x17, 0x0033); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci *tune_state = CT_TUNER_STEP_5; 4988c2ecf20Sopenharmony_ci } else if (*tune_state == CT_TUNER_STEP_5) { 4998c2ecf20Sopenharmony_ci dib0070_set_bandwidth(fe); 5008c2ecf20Sopenharmony_ci *tune_state = CT_TUNER_STOP; 5018c2ecf20Sopenharmony_ci } else { 5028c2ecf20Sopenharmony_ci ret = FE_CALLBACK_TIME_NEVER; /* tuner finished, time to call again infinite */ 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci return ret; 5058c2ecf20Sopenharmony_ci} 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_cistatic int dib0070_tune(struct dvb_frontend *fe) 5098c2ecf20Sopenharmony_ci{ 5108c2ecf20Sopenharmony_ci struct dib0070_state *state = fe->tuner_priv; 5118c2ecf20Sopenharmony_ci uint32_t ret; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci state->tune_state = CT_TUNER_START; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci do { 5168c2ecf20Sopenharmony_ci ret = dib0070_tune_digital(fe); 5178c2ecf20Sopenharmony_ci if (ret != FE_CALLBACK_TIME_NEVER) 5188c2ecf20Sopenharmony_ci msleep(ret/10); 5198c2ecf20Sopenharmony_ci else 5208c2ecf20Sopenharmony_ci break; 5218c2ecf20Sopenharmony_ci } while (state->tune_state != CT_TUNER_STOP); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci return 0; 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic int dib0070_wakeup(struct dvb_frontend *fe) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci struct dib0070_state *state = fe->tuner_priv; 5298c2ecf20Sopenharmony_ci if (state->cfg->sleep) 5308c2ecf20Sopenharmony_ci state->cfg->sleep(fe, 0); 5318c2ecf20Sopenharmony_ci return 0; 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_cistatic int dib0070_sleep(struct dvb_frontend *fe) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci struct dib0070_state *state = fe->tuner_priv; 5378c2ecf20Sopenharmony_ci if (state->cfg->sleep) 5388c2ecf20Sopenharmony_ci state->cfg->sleep(fe, 1); 5398c2ecf20Sopenharmony_ci return 0; 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ciu8 dib0070_get_rf_output(struct dvb_frontend *fe) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci struct dib0070_state *state = fe->tuner_priv; 5458c2ecf20Sopenharmony_ci return (dib0070_read_reg(state, 0x07) >> 11) & 0x3; 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dib0070_get_rf_output); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ciint dib0070_set_rf_output(struct dvb_frontend *fe, u8 no) 5508c2ecf20Sopenharmony_ci{ 5518c2ecf20Sopenharmony_ci struct dib0070_state *state = fe->tuner_priv; 5528c2ecf20Sopenharmony_ci u16 rxrf2 = dib0070_read_reg(state, 0x07) & 0xfe7ff; 5538c2ecf20Sopenharmony_ci if (no > 3) 5548c2ecf20Sopenharmony_ci no = 3; 5558c2ecf20Sopenharmony_ci if (no < 1) 5568c2ecf20Sopenharmony_ci no = 1; 5578c2ecf20Sopenharmony_ci return dib0070_write_reg(state, 0x07, rxrf2 | (no << 11)); 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dib0070_set_rf_output); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_cistatic const u16 dib0070_p1f_defaults[] = 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci{ 5648c2ecf20Sopenharmony_ci 7, 0x02, 5658c2ecf20Sopenharmony_ci 0x0008, 5668c2ecf20Sopenharmony_ci 0x0000, 5678c2ecf20Sopenharmony_ci 0x0000, 5688c2ecf20Sopenharmony_ci 0x0000, 5698c2ecf20Sopenharmony_ci 0x0000, 5708c2ecf20Sopenharmony_ci 0x0002, 5718c2ecf20Sopenharmony_ci 0x0100, 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci 3, 0x0d, 5748c2ecf20Sopenharmony_ci 0x0d80, 5758c2ecf20Sopenharmony_ci 0x0001, 5768c2ecf20Sopenharmony_ci 0x0000, 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci 4, 0x11, 5798c2ecf20Sopenharmony_ci 0x0000, 5808c2ecf20Sopenharmony_ci 0x0103, 5818c2ecf20Sopenharmony_ci 0x0000, 5828c2ecf20Sopenharmony_ci 0x0000, 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci 3, 0x16, 5858c2ecf20Sopenharmony_ci 0x0004 | 0x0040, 5868c2ecf20Sopenharmony_ci 0x0030, 5878c2ecf20Sopenharmony_ci 0x07ff, 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci 6, 0x1b, 5908c2ecf20Sopenharmony_ci 0x4112, 5918c2ecf20Sopenharmony_ci 0xff00, 5928c2ecf20Sopenharmony_ci 0xc07f, 5938c2ecf20Sopenharmony_ci 0x0000, 5948c2ecf20Sopenharmony_ci 0x0180, 5958c2ecf20Sopenharmony_ci 0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001, 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci 0, 5988c2ecf20Sopenharmony_ci}; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_cistatic u16 dib0070_read_wbd_offset(struct dib0070_state *state, u8 gain) 6018c2ecf20Sopenharmony_ci{ 6028c2ecf20Sopenharmony_ci u16 tuner_en = dib0070_read_reg(state, 0x20); 6038c2ecf20Sopenharmony_ci u16 offset; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x18, 0x07ff); 6068c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x20, 0x0800 | 0x4000 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001); 6078c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x0f, (1 << 14) | (2 << 12) | (gain << 9) | (1 << 8) | (1 << 7) | (0 << 0)); 6088c2ecf20Sopenharmony_ci msleep(9); 6098c2ecf20Sopenharmony_ci offset = dib0070_read_reg(state, 0x19); 6108c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x20, tuner_en); 6118c2ecf20Sopenharmony_ci return offset; 6128c2ecf20Sopenharmony_ci} 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_cistatic void dib0070_wbd_offset_calibration(struct dib0070_state *state) 6158c2ecf20Sopenharmony_ci{ 6168c2ecf20Sopenharmony_ci u8 gain; 6178c2ecf20Sopenharmony_ci for (gain = 6; gain < 8; gain++) { 6188c2ecf20Sopenharmony_ci state->wbd_offset_3_3[gain - 6] = ((dib0070_read_wbd_offset(state, gain) * 8 * 18 / 33 + 1) / 2); 6198c2ecf20Sopenharmony_ci dprintk("Gain: %d, WBDOffset (3.3V) = %hd\n", gain, state->wbd_offset_3_3[gain-6]); 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci} 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ciu16 dib0070_wbd_offset(struct dvb_frontend *fe) 6248c2ecf20Sopenharmony_ci{ 6258c2ecf20Sopenharmony_ci struct dib0070_state *state = fe->tuner_priv; 6268c2ecf20Sopenharmony_ci const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain; 6278c2ecf20Sopenharmony_ci u32 freq = fe->dtv_property_cache.frequency/1000; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci if (tmp != NULL) { 6308c2ecf20Sopenharmony_ci while (freq/1000 > tmp->freq) /* find the right one */ 6318c2ecf20Sopenharmony_ci tmp++; 6328c2ecf20Sopenharmony_ci state->wbd_gain_current = tmp->wbd_gain_val; 6338c2ecf20Sopenharmony_ci } else 6348c2ecf20Sopenharmony_ci state->wbd_gain_current = 6; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci return state->wbd_offset_3_3[state->wbd_gain_current - 6]; 6378c2ecf20Sopenharmony_ci} 6388c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dib0070_wbd_offset); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci#define pgm_read_word(w) (*w) 6418c2ecf20Sopenharmony_cistatic int dib0070_reset(struct dvb_frontend *fe) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci struct dib0070_state *state = fe->tuner_priv; 6448c2ecf20Sopenharmony_ci u16 l, r, *n; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci HARD_RESET(state); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci#ifndef FORCE_SBAND_TUNER 6508c2ecf20Sopenharmony_ci if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1) 6518c2ecf20Sopenharmony_ci state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff; 6528c2ecf20Sopenharmony_ci else 6538c2ecf20Sopenharmony_ci#else 6548c2ecf20Sopenharmony_ci#warning forcing SBAND 6558c2ecf20Sopenharmony_ci#endif 6568c2ecf20Sopenharmony_ci state->revision = DIB0070S_P1A; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci /* P1F or not */ 6598c2ecf20Sopenharmony_ci dprintk("Revision: %x\n", state->revision); 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci if (state->revision == DIB0070_P1D) { 6628c2ecf20Sopenharmony_ci dprintk("Error: this driver is not to be used meant for P1D or earlier\n"); 6638c2ecf20Sopenharmony_ci return -EINVAL; 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci n = (u16 *) dib0070_p1f_defaults; 6678c2ecf20Sopenharmony_ci l = pgm_read_word(n++); 6688c2ecf20Sopenharmony_ci while (l) { 6698c2ecf20Sopenharmony_ci r = pgm_read_word(n++); 6708c2ecf20Sopenharmony_ci do { 6718c2ecf20Sopenharmony_ci dib0070_write_reg(state, (u8)r, pgm_read_word(n++)); 6728c2ecf20Sopenharmony_ci r++; 6738c2ecf20Sopenharmony_ci } while (--l); 6748c2ecf20Sopenharmony_ci l = pgm_read_word(n++); 6758c2ecf20Sopenharmony_ci } 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci if (state->cfg->force_crystal_mode != 0) 6788c2ecf20Sopenharmony_ci r = state->cfg->force_crystal_mode; 6798c2ecf20Sopenharmony_ci else if (state->cfg->clock_khz >= 24000) 6808c2ecf20Sopenharmony_ci r = 1; 6818c2ecf20Sopenharmony_ci else 6828c2ecf20Sopenharmony_ci r = 2; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci r |= state->cfg->osc_buffer_state << 3; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x10, r); 6888c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x1f, (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 5)); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci if (state->cfg->invert_iq) { 6918c2ecf20Sopenharmony_ci r = dib0070_read_reg(state, 0x02) & 0xffdf; 6928c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x02, r | (1 << 5)); 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci if (state->revision == DIB0070S_P1A) 6968c2ecf20Sopenharmony_ci dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0); 6978c2ecf20Sopenharmony_ci else 6988c2ecf20Sopenharmony_ci dib0070_set_ctrl_lo5(fe, 5, 4, state->cfg->charge_pump, 6998c2ecf20Sopenharmony_ci state->cfg->enable_third_order_filter); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci dib0070_wbd_offset_calibration(state); 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci return 0; 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_cistatic int dib0070_get_frequency(struct dvb_frontend *fe, u32 *frequency) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci struct dib0070_state *state = fe->tuner_priv; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci *frequency = 1000 * state->current_rf; 7138c2ecf20Sopenharmony_ci return 0; 7148c2ecf20Sopenharmony_ci} 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_cistatic void dib0070_release(struct dvb_frontend *fe) 7178c2ecf20Sopenharmony_ci{ 7188c2ecf20Sopenharmony_ci kfree(fe->tuner_priv); 7198c2ecf20Sopenharmony_ci fe->tuner_priv = NULL; 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_cistatic const struct dvb_tuner_ops dib0070_ops = { 7238c2ecf20Sopenharmony_ci .info = { 7248c2ecf20Sopenharmony_ci .name = "DiBcom DiB0070", 7258c2ecf20Sopenharmony_ci .frequency_min_hz = 45 * MHz, 7268c2ecf20Sopenharmony_ci .frequency_max_hz = 860 * MHz, 7278c2ecf20Sopenharmony_ci .frequency_step_hz = 1 * kHz, 7288c2ecf20Sopenharmony_ci }, 7298c2ecf20Sopenharmony_ci .release = dib0070_release, 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci .init = dib0070_wakeup, 7328c2ecf20Sopenharmony_ci .sleep = dib0070_sleep, 7338c2ecf20Sopenharmony_ci .set_params = dib0070_tune, 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci .get_frequency = dib0070_get_frequency, 7368c2ecf20Sopenharmony_ci// .get_bandwidth = dib0070_get_bandwidth 7378c2ecf20Sopenharmony_ci}; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_cistruct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg) 7408c2ecf20Sopenharmony_ci{ 7418c2ecf20Sopenharmony_ci struct dib0070_state *state = kzalloc(sizeof(struct dib0070_state), GFP_KERNEL); 7428c2ecf20Sopenharmony_ci if (state == NULL) 7438c2ecf20Sopenharmony_ci return NULL; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci state->cfg = cfg; 7468c2ecf20Sopenharmony_ci state->i2c = i2c; 7478c2ecf20Sopenharmony_ci state->fe = fe; 7488c2ecf20Sopenharmony_ci mutex_init(&state->i2c_buffer_lock); 7498c2ecf20Sopenharmony_ci fe->tuner_priv = state; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci if (dib0070_reset(fe) != 0) 7528c2ecf20Sopenharmony_ci goto free_mem; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci pr_info("DiB0070: successfully identified\n"); 7558c2ecf20Sopenharmony_ci memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops)); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci fe->tuner_priv = state; 7588c2ecf20Sopenharmony_ci return fe; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_cifree_mem: 7618c2ecf20Sopenharmony_ci kfree(state); 7628c2ecf20Sopenharmony_ci fe->tuner_priv = NULL; 7638c2ecf20Sopenharmony_ci return NULL; 7648c2ecf20Sopenharmony_ci} 7658c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dib0070_attach); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ciMODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>"); 7688c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner"); 7698c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 770