18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for DiBcom DiB3000MC/P-demodulator. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2004-7 DiBcom (http://www.dibcom.fr/) 68c2ecf20Sopenharmony_ci * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@posteo.de) 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This code is partially based on the previous dib3000mc.c . 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 178c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "dib3000mc.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic int debug; 228c2ecf20Sopenharmony_cimodule_param(debug, int, 0644); 238c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic int buggy_sfn_workaround; 268c2ecf20Sopenharmony_cimodule_param(buggy_sfn_workaround, int, 0644); 278c2ecf20Sopenharmony_ciMODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)"); 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define dprintk(fmt, arg...) do { \ 308c2ecf20Sopenharmony_ci if (debug) \ 318c2ecf20Sopenharmony_ci printk(KERN_DEBUG pr_fmt("%s: " fmt), \ 328c2ecf20Sopenharmony_ci __func__, ##arg); \ 338c2ecf20Sopenharmony_ci} while (0) 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistruct dib3000mc_state { 368c2ecf20Sopenharmony_ci struct dvb_frontend demod; 378c2ecf20Sopenharmony_ci struct dib3000mc_config *cfg; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci u8 i2c_addr; 408c2ecf20Sopenharmony_ci struct i2c_adapter *i2c_adap; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci struct dibx000_i2c_master i2c_master; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci u32 timf; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci u32 current_bandwidth; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci u16 dev_id; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci u8 sfn_workaround_active :1; 518c2ecf20Sopenharmony_ci}; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic u16 dib3000mc_read_word(struct dib3000mc_state *state, u16 reg) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci struct i2c_msg msg[2] = { 568c2ecf20Sopenharmony_ci { .addr = state->i2c_addr >> 1, .flags = 0, .len = 2 }, 578c2ecf20Sopenharmony_ci { .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .len = 2 }, 588c2ecf20Sopenharmony_ci }; 598c2ecf20Sopenharmony_ci u16 word; 608c2ecf20Sopenharmony_ci u8 *b; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci b = kmalloc(4, GFP_KERNEL); 638c2ecf20Sopenharmony_ci if (!b) 648c2ecf20Sopenharmony_ci return 0; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci b[0] = (reg >> 8) | 0x80; 678c2ecf20Sopenharmony_ci b[1] = reg; 688c2ecf20Sopenharmony_ci b[2] = 0; 698c2ecf20Sopenharmony_ci b[3] = 0; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci msg[0].buf = b; 728c2ecf20Sopenharmony_ci msg[1].buf = b + 2; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci if (i2c_transfer(state->i2c_adap, msg, 2) != 2) 758c2ecf20Sopenharmony_ci dprintk("i2c read error on %d\n",reg); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci word = (b[2] << 8) | b[3]; 788c2ecf20Sopenharmony_ci kfree(b); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci return word; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic int dib3000mc_write_word(struct dib3000mc_state *state, u16 reg, u16 val) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci struct i2c_msg msg = { 868c2ecf20Sopenharmony_ci .addr = state->i2c_addr >> 1, .flags = 0, .len = 4 878c2ecf20Sopenharmony_ci }; 888c2ecf20Sopenharmony_ci int rc; 898c2ecf20Sopenharmony_ci u8 *b; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci b = kmalloc(4, GFP_KERNEL); 928c2ecf20Sopenharmony_ci if (!b) 938c2ecf20Sopenharmony_ci return -ENOMEM; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci b[0] = reg >> 8; 968c2ecf20Sopenharmony_ci b[1] = reg; 978c2ecf20Sopenharmony_ci b[2] = val >> 8; 988c2ecf20Sopenharmony_ci b[3] = val; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci msg.buf = b; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci rc = i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; 1038c2ecf20Sopenharmony_ci kfree(b); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci return rc; 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic int dib3000mc_identify(struct dib3000mc_state *state) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci u16 value; 1118c2ecf20Sopenharmony_ci if ((value = dib3000mc_read_word(state, 1025)) != 0x01b3) { 1128c2ecf20Sopenharmony_ci dprintk("-E- DiB3000MC/P: wrong Vendor ID (read=0x%x)\n",value); 1138c2ecf20Sopenharmony_ci return -EREMOTEIO; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci value = dib3000mc_read_word(state, 1026); 1178c2ecf20Sopenharmony_ci if (value != 0x3001 && value != 0x3002) { 1188c2ecf20Sopenharmony_ci dprintk("-E- DiB3000MC/P: wrong Device ID (%x)\n",value); 1198c2ecf20Sopenharmony_ci return -EREMOTEIO; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci state->dev_id = value; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci dprintk("-I- found DiB3000MC/P: %x\n",state->dev_id); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci return 0; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u32 bw, u8 update_offset) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci u32 timf; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if (state->timf == 0) { 1338c2ecf20Sopenharmony_ci timf = 1384402; // default value for 8MHz 1348c2ecf20Sopenharmony_ci if (update_offset) 1358c2ecf20Sopenharmony_ci msleep(200); // first time we do an update 1368c2ecf20Sopenharmony_ci } else 1378c2ecf20Sopenharmony_ci timf = state->timf; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci timf *= (bw / 1000); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (update_offset) { 1428c2ecf20Sopenharmony_ci s16 tim_offs = dib3000mc_read_word(state, 416); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci if (tim_offs & 0x2000) 1458c2ecf20Sopenharmony_ci tim_offs -= 0x4000; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci if (nfft == TRANSMISSION_MODE_2K) 1488c2ecf20Sopenharmony_ci tim_offs *= 4; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci timf += tim_offs; 1518c2ecf20Sopenharmony_ci state->timf = timf / (bw / 1000); 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci dprintk("timf: %d\n", timf); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 23, (u16) (timf >> 16)); 1578c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 24, (u16) (timf ) & 0xffff); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci return 0; 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic int dib3000mc_setup_pwm_state(struct dib3000mc_state *state) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci u16 reg_51, reg_52 = state->cfg->agc->setup & 0xfefb; 1658c2ecf20Sopenharmony_ci if (state->cfg->pwm3_inversion) { 1668c2ecf20Sopenharmony_ci reg_51 = (2 << 14) | (0 << 10) | (7 << 6) | (2 << 2) | (2 << 0); 1678c2ecf20Sopenharmony_ci reg_52 |= (1 << 2); 1688c2ecf20Sopenharmony_ci } else { 1698c2ecf20Sopenharmony_ci reg_51 = (2 << 14) | (4 << 10) | (7 << 6) | (2 << 2) | (2 << 0); 1708c2ecf20Sopenharmony_ci reg_52 |= (1 << 8); 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 51, reg_51); 1738c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 52, reg_52); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (state->cfg->use_pwm3) 1768c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 245, (1 << 3) | (1 << 0)); 1778c2ecf20Sopenharmony_ci else 1788c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 245, 0); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 1040, 0x3); 1818c2ecf20Sopenharmony_ci return 0; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic int dib3000mc_set_output_mode(struct dib3000mc_state *state, int mode) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci int ret = 0; 1878c2ecf20Sopenharmony_ci u16 fifo_threshold = 1792; 1888c2ecf20Sopenharmony_ci u16 outreg = 0; 1898c2ecf20Sopenharmony_ci u16 outmode = 0; 1908c2ecf20Sopenharmony_ci u16 elecout = 1; 1918c2ecf20Sopenharmony_ci u16 smo_reg = dib3000mc_read_word(state, 206) & 0x0010; /* keep the pid_parse bit */ 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci dprintk("-I- Setting output mode for demod %p to %d\n", 1948c2ecf20Sopenharmony_ci &state->demod, mode); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci switch (mode) { 1978c2ecf20Sopenharmony_ci case OUTMODE_HIGH_Z: // disable 1988c2ecf20Sopenharmony_ci elecout = 0; 1998c2ecf20Sopenharmony_ci break; 2008c2ecf20Sopenharmony_ci case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock 2018c2ecf20Sopenharmony_ci outmode = 0; 2028c2ecf20Sopenharmony_ci break; 2038c2ecf20Sopenharmony_ci case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock 2048c2ecf20Sopenharmony_ci outmode = 1; 2058c2ecf20Sopenharmony_ci break; 2068c2ecf20Sopenharmony_ci case OUTMODE_MPEG2_SERIAL: // STBs with serial input 2078c2ecf20Sopenharmony_ci outmode = 2; 2088c2ecf20Sopenharmony_ci break; 2098c2ecf20Sopenharmony_ci case OUTMODE_MPEG2_FIFO: // e.g. USB feeding 2108c2ecf20Sopenharmony_ci elecout = 3; 2118c2ecf20Sopenharmony_ci /*ADDR @ 206 : 2128c2ecf20Sopenharmony_ci P_smo_error_discard [1;6:6] = 0 2138c2ecf20Sopenharmony_ci P_smo_rs_discard [1;5:5] = 0 2148c2ecf20Sopenharmony_ci P_smo_pid_parse [1;4:4] = 0 2158c2ecf20Sopenharmony_ci P_smo_fifo_flush [1;3:3] = 0 2168c2ecf20Sopenharmony_ci P_smo_mode [2;2:1] = 11 2178c2ecf20Sopenharmony_ci P_smo_ovf_prot [1;0:0] = 0 2188c2ecf20Sopenharmony_ci */ 2198c2ecf20Sopenharmony_ci smo_reg |= 3 << 1; 2208c2ecf20Sopenharmony_ci fifo_threshold = 512; 2218c2ecf20Sopenharmony_ci outmode = 5; 2228c2ecf20Sopenharmony_ci break; 2238c2ecf20Sopenharmony_ci case OUTMODE_DIVERSITY: 2248c2ecf20Sopenharmony_ci outmode = 4; 2258c2ecf20Sopenharmony_ci elecout = 1; 2268c2ecf20Sopenharmony_ci break; 2278c2ecf20Sopenharmony_ci default: 2288c2ecf20Sopenharmony_ci dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod); 2298c2ecf20Sopenharmony_ci outmode = 0; 2308c2ecf20Sopenharmony_ci break; 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci if ((state->cfg->output_mpeg2_in_188_bytes)) 2348c2ecf20Sopenharmony_ci smo_reg |= (1 << 5); // P_smo_rs_discard [1;5:5] = 1 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci outreg = dib3000mc_read_word(state, 244) & 0x07FF; 2378c2ecf20Sopenharmony_ci outreg |= (outmode << 11); 2388c2ecf20Sopenharmony_ci ret |= dib3000mc_write_word(state, 244, outreg); 2398c2ecf20Sopenharmony_ci ret |= dib3000mc_write_word(state, 206, smo_reg); /*smo_ mode*/ 2408c2ecf20Sopenharmony_ci ret |= dib3000mc_write_word(state, 207, fifo_threshold); /* synchronous fread */ 2418c2ecf20Sopenharmony_ci ret |= dib3000mc_write_word(state, 1040, elecout); /* P_out_cfg */ 2428c2ecf20Sopenharmony_ci return ret; 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic int dib3000mc_set_bandwidth(struct dib3000mc_state *state, u32 bw) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci u16 bw_cfg[6] = { 0 }; 2488c2ecf20Sopenharmony_ci u16 imp_bw_cfg[3] = { 0 }; 2498c2ecf20Sopenharmony_ci u16 reg; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci/* settings here are for 27.7MHz */ 2528c2ecf20Sopenharmony_ci switch (bw) { 2538c2ecf20Sopenharmony_ci case 8000: 2548c2ecf20Sopenharmony_ci bw_cfg[0] = 0x0019; bw_cfg[1] = 0x5c30; bw_cfg[2] = 0x0054; bw_cfg[3] = 0x88a0; bw_cfg[4] = 0x01a6; bw_cfg[5] = 0xab20; 2558c2ecf20Sopenharmony_ci imp_bw_cfg[0] = 0x04db; imp_bw_cfg[1] = 0x00db; imp_bw_cfg[2] = 0x00b7; 2568c2ecf20Sopenharmony_ci break; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci case 7000: 2598c2ecf20Sopenharmony_ci bw_cfg[0] = 0x001c; bw_cfg[1] = 0xfba5; bw_cfg[2] = 0x0060; bw_cfg[3] = 0x9c25; bw_cfg[4] = 0x01e3; bw_cfg[5] = 0x0cb7; 2608c2ecf20Sopenharmony_ci imp_bw_cfg[0] = 0x04c0; imp_bw_cfg[1] = 0x00c0; imp_bw_cfg[2] = 0x00a0; 2618c2ecf20Sopenharmony_ci break; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci case 6000: 2648c2ecf20Sopenharmony_ci bw_cfg[0] = 0x0021; bw_cfg[1] = 0xd040; bw_cfg[2] = 0x0070; bw_cfg[3] = 0xb62b; bw_cfg[4] = 0x0233; bw_cfg[5] = 0x8ed5; 2658c2ecf20Sopenharmony_ci imp_bw_cfg[0] = 0x04a5; imp_bw_cfg[1] = 0x00a5; imp_bw_cfg[2] = 0x0089; 2668c2ecf20Sopenharmony_ci break; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci case 5000: 2698c2ecf20Sopenharmony_ci bw_cfg[0] = 0x0028; bw_cfg[1] = 0x9380; bw_cfg[2] = 0x0087; bw_cfg[3] = 0x4100; bw_cfg[4] = 0x02a4; bw_cfg[5] = 0x4500; 2708c2ecf20Sopenharmony_ci imp_bw_cfg[0] = 0x0489; imp_bw_cfg[1] = 0x0089; imp_bw_cfg[2] = 0x0072; 2718c2ecf20Sopenharmony_ci break; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci default: return -EINVAL; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci for (reg = 6; reg < 12; reg++) 2778c2ecf20Sopenharmony_ci dib3000mc_write_word(state, reg, bw_cfg[reg - 6]); 2788c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 12, 0x0000); 2798c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 13, 0x03e8); 2808c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 14, 0x0000); 2818c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 15, 0x03f2); 2828c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 16, 0x0001); 2838c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 17, 0xb0d0); 2848c2ecf20Sopenharmony_ci // P_sec_len 2858c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 18, 0x0393); 2868c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 19, 0x8700); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci for (reg = 55; reg < 58; reg++) 2898c2ecf20Sopenharmony_ci dib3000mc_write_word(state, reg, imp_bw_cfg[reg - 55]); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci // Timing configuration 2928c2ecf20Sopenharmony_ci dib3000mc_set_timing(state, TRANSMISSION_MODE_2K, bw, 0); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci return 0; 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic u16 impulse_noise_val[29] = 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci 0x38, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c, 0x3ffe, 0x7f3, 3018c2ecf20Sopenharmony_ci 0x2d94, 0x76, 0x53d, 0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3, 0x3feb, 0x7d2, 3028c2ecf20Sopenharmony_ci 0x365e, 0x76, 0x48c, 0x3ffe, 0x5b3, 0x3feb, 0x76, 0x0000, 0xd 3038c2ecf20Sopenharmony_ci}; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic void dib3000mc_set_impulse_noise(struct dib3000mc_state *state, u8 mode, s16 nfft) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci u16 i; 3088c2ecf20Sopenharmony_ci for (i = 58; i < 87; i++) 3098c2ecf20Sopenharmony_ci dib3000mc_write_word(state, i, impulse_noise_val[i-58]); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (nfft == TRANSMISSION_MODE_8K) { 3128c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 58, 0x3b); 3138c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 84, 0x00); 3148c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 85, 0x8200); 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 34, 0x1294); 3188c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 35, 0x1ff8); 3198c2ecf20Sopenharmony_ci if (mode == 1) 3208c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 55, dib3000mc_read_word(state, 55) | (1 << 10)); 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic int dib3000mc_init(struct dvb_frontend *demod) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci struct dib3000mc_state *state = demod->demodulator_priv; 3268c2ecf20Sopenharmony_ci struct dibx000_agc_config *agc = state->cfg->agc; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci // Restart Configuration 3298c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 1027, 0x8000); 3308c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 1027, 0x0000); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci // power up the demod + mobility configuration 3338c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 140, 0x0000); 3348c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 1031, 0); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci if (state->cfg->mobile_mode) { 3378c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 139, 0x0000); 3388c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 141, 0x0000); 3398c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 175, 0x0002); 3408c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 1032, 0x0000); 3418c2ecf20Sopenharmony_ci } else { 3428c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 139, 0x0001); 3438c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 141, 0x0000); 3448c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 175, 0x0000); 3458c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 1032, 0x012C); 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 1033, 0x0000); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci // P_clk_cfg 3508c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 1037, 0x3130); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci // other configurations 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci // P_ctrl_sfreq 3558c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 33, (5 << 0)); 3568c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 88, (1 << 10) | (0x10 << 0)); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci // Phase noise control 3598c2ecf20Sopenharmony_ci // P_fft_phacor_inh, P_fft_phacor_cpe, P_fft_powrange 3608c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 99, (1 << 9) | (0x20 << 0)); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (state->cfg->phase_noise_mode == 0) 3638c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 111, 0x00); 3648c2ecf20Sopenharmony_ci else 3658c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 111, 0x02); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci // P_agc_global 3688c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 50, 0x8000); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci // agc setup misc 3718c2ecf20Sopenharmony_ci dib3000mc_setup_pwm_state(state); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci // P_agc_counter_lock 3748c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 53, 0x87); 3758c2ecf20Sopenharmony_ci // P_agc_counter_unlock 3768c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 54, 0x87); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci /* agc */ 3798c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 36, state->cfg->max_time); 3808c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 37, (state->cfg->agc_command1 << 13) | (state->cfg->agc_command2 << 12) | (0x1d << 0)); 3818c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 38, state->cfg->pwm3_value); 3828c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 39, state->cfg->ln_adc_level); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci // set_agc_loop_Bw 3858c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 40, 0x0179); 3868c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 41, 0x03f0); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 42, agc->agc1_max); 3898c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 43, agc->agc1_min); 3908c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 44, agc->agc2_max); 3918c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 45, agc->agc2_min); 3928c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 46, (agc->agc1_pt1 << 8) | agc->agc1_pt2); 3938c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 47, (agc->agc1_slope1 << 8) | agc->agc1_slope2); 3948c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 48, (agc->agc2_pt1 << 8) | agc->agc2_pt2); 3958c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 49, (agc->agc2_slope1 << 8) | agc->agc2_slope2); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci// Begin: TimeOut registers 3988c2ecf20Sopenharmony_ci // P_pha3_thres 3998c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 110, 3277); 4008c2ecf20Sopenharmony_ci // P_timf_alpha = 6, P_corm_alpha = 6, P_corm_thres = 0x80 4018c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 26, 0x6680); 4028c2ecf20Sopenharmony_ci // lock_mask0 4038c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 1, 4); 4048c2ecf20Sopenharmony_ci // lock_mask1 4058c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 2, 4); 4068c2ecf20Sopenharmony_ci // lock_mask2 4078c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 3, 0x1000); 4088c2ecf20Sopenharmony_ci // P_search_maxtrial=1 4098c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 5, 1); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci dib3000mc_set_bandwidth(state, 8000); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci // div_lock_mask 4148c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 4, 0x814); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 21, (1 << 9) | 0x164); 4178c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 22, 0x463d); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci // Spurious rm cfg 4208c2ecf20Sopenharmony_ci // P_cspu_regul, P_cspu_win_cut 4218c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 120, 0x200f); 4228c2ecf20Sopenharmony_ci // P_adp_selec_monit 4238c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 134, 0); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci // Fec cfg 4268c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 195, 0x10); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci // diversity register: P_dvsy_sync_wait.. 4298c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 180, 0x2FF0); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci // Impulse noise configuration 4328c2ecf20Sopenharmony_ci dib3000mc_set_impulse_noise(state, 0, TRANSMISSION_MODE_8K); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci // output mode set-up 4358c2ecf20Sopenharmony_ci dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci /* close the i2c-gate */ 4388c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 769, (1 << 7) ); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci return 0; 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic int dib3000mc_sleep(struct dvb_frontend *demod) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci struct dib3000mc_state *state = demod->demodulator_priv; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 1031, 0xFFFF); 4488c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 1032, 0xFFFF); 4498c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 1033, 0xFFF0); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci return 0; 4528c2ecf20Sopenharmony_ci} 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cistatic void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci u16 cfg[4] = { 0 },reg; 4578c2ecf20Sopenharmony_ci switch (qam) { 4588c2ecf20Sopenharmony_ci case QPSK: 4598c2ecf20Sopenharmony_ci cfg[0] = 0x099a; cfg[1] = 0x7fae; cfg[2] = 0x0333; cfg[3] = 0x7ff0; 4608c2ecf20Sopenharmony_ci break; 4618c2ecf20Sopenharmony_ci case QAM_16: 4628c2ecf20Sopenharmony_ci cfg[0] = 0x023d; cfg[1] = 0x7fdf; cfg[2] = 0x00a4; cfg[3] = 0x7ff0; 4638c2ecf20Sopenharmony_ci break; 4648c2ecf20Sopenharmony_ci case QAM_64: 4658c2ecf20Sopenharmony_ci cfg[0] = 0x0148; cfg[1] = 0x7ff0; cfg[2] = 0x00a4; cfg[3] = 0x7ff8; 4668c2ecf20Sopenharmony_ci break; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci for (reg = 129; reg < 133; reg++) 4698c2ecf20Sopenharmony_ci dib3000mc_write_word(state, reg, cfg[reg - 129]); 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, 4738c2ecf20Sopenharmony_ci struct dtv_frontend_properties *ch, u16 seq) 4748c2ecf20Sopenharmony_ci{ 4758c2ecf20Sopenharmony_ci u16 value; 4768c2ecf20Sopenharmony_ci u32 bw = BANDWIDTH_TO_KHZ(ch->bandwidth_hz); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci dib3000mc_set_bandwidth(state, bw); 4798c2ecf20Sopenharmony_ci dib3000mc_set_timing(state, ch->transmission_mode, bw, 0); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci#if 1 4828c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 100, (16 << 6) + 9); 4838c2ecf20Sopenharmony_ci#else 4848c2ecf20Sopenharmony_ci if (boost) 4858c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 100, (11 << 6) + 6); 4868c2ecf20Sopenharmony_ci else 4878c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 100, (16 << 6) + 9); 4888c2ecf20Sopenharmony_ci#endif 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 1027, 0x0800); 4918c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 1027, 0x0000); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci //Default cfg isi offset adp 4948c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 26, 0x6680); 4958c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 29, 0x1273); 4968c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 33, 5); 4978c2ecf20Sopenharmony_ci dib3000mc_set_adp_cfg(state, QAM_16); 4988c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 133, 15564); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 12 , 0x0); 5018c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 13 , 0x3e8); 5028c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 14 , 0x0); 5038c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 15 , 0x3f2); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 93,0); 5068c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 94,0); 5078c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 95,0); 5088c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 96,0); 5098c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 97,0); 5108c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 98,0); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci dib3000mc_set_impulse_noise(state, 0, ch->transmission_mode); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci value = 0; 5158c2ecf20Sopenharmony_ci switch (ch->transmission_mode) { 5168c2ecf20Sopenharmony_ci case TRANSMISSION_MODE_2K: value |= (0 << 7); break; 5178c2ecf20Sopenharmony_ci default: 5188c2ecf20Sopenharmony_ci case TRANSMISSION_MODE_8K: value |= (1 << 7); break; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci switch (ch->guard_interval) { 5218c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_32: value |= (0 << 5); break; 5228c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_16: value |= (1 << 5); break; 5238c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_4: value |= (3 << 5); break; 5248c2ecf20Sopenharmony_ci default: 5258c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_8: value |= (2 << 5); break; 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci switch (ch->modulation) { 5288c2ecf20Sopenharmony_ci case QPSK: value |= (0 << 3); break; 5298c2ecf20Sopenharmony_ci case QAM_16: value |= (1 << 3); break; 5308c2ecf20Sopenharmony_ci default: 5318c2ecf20Sopenharmony_ci case QAM_64: value |= (2 << 3); break; 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci switch (HIERARCHY_1) { 5348c2ecf20Sopenharmony_ci case HIERARCHY_2: value |= 2; break; 5358c2ecf20Sopenharmony_ci case HIERARCHY_4: value |= 4; break; 5368c2ecf20Sopenharmony_ci default: 5378c2ecf20Sopenharmony_ci case HIERARCHY_1: value |= 1; break; 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 0, value); 5408c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 5, (1 << 8) | ((seq & 0xf) << 4)); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci value = 0; 5438c2ecf20Sopenharmony_ci if (ch->hierarchy == 1) 5448c2ecf20Sopenharmony_ci value |= (1 << 4); 5458c2ecf20Sopenharmony_ci if (1 == 1) 5468c2ecf20Sopenharmony_ci value |= 1; 5478c2ecf20Sopenharmony_ci switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) { 5488c2ecf20Sopenharmony_ci case FEC_2_3: value |= (2 << 1); break; 5498c2ecf20Sopenharmony_ci case FEC_3_4: value |= (3 << 1); break; 5508c2ecf20Sopenharmony_ci case FEC_5_6: value |= (5 << 1); break; 5518c2ecf20Sopenharmony_ci case FEC_7_8: value |= (7 << 1); break; 5528c2ecf20Sopenharmony_ci default: 5538c2ecf20Sopenharmony_ci case FEC_1_2: value |= (1 << 1); break; 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 181, value); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci // diversity synchro delay add 50% SFN margin 5588c2ecf20Sopenharmony_ci switch (ch->transmission_mode) { 5598c2ecf20Sopenharmony_ci case TRANSMISSION_MODE_8K: value = 256; break; 5608c2ecf20Sopenharmony_ci case TRANSMISSION_MODE_2K: 5618c2ecf20Sopenharmony_ci default: value = 64; break; 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci switch (ch->guard_interval) { 5648c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_16: value *= 2; break; 5658c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_8: value *= 4; break; 5668c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_4: value *= 8; break; 5678c2ecf20Sopenharmony_ci default: 5688c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_32: value *= 1; break; 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci value <<= 4; 5718c2ecf20Sopenharmony_ci value |= dib3000mc_read_word(state, 180) & 0x000f; 5728c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 180, value); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci // restart demod 5758c2ecf20Sopenharmony_ci value = dib3000mc_read_word(state, 0); 5768c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 0, value | (1 << 9)); 5778c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 0, value); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci msleep(30); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, ch->transmission_mode); 5828c2ecf20Sopenharmony_ci} 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_cistatic int dib3000mc_autosearch_start(struct dvb_frontend *demod) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci struct dtv_frontend_properties *chan = &demod->dtv_property_cache; 5878c2ecf20Sopenharmony_ci struct dib3000mc_state *state = demod->demodulator_priv; 5888c2ecf20Sopenharmony_ci u16 reg; 5898c2ecf20Sopenharmony_ci// u32 val; 5908c2ecf20Sopenharmony_ci struct dtv_frontend_properties schan; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci schan = *chan; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci /* TODO what is that ? */ 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci /* a channel for autosearch */ 5978c2ecf20Sopenharmony_ci schan.transmission_mode = TRANSMISSION_MODE_8K; 5988c2ecf20Sopenharmony_ci schan.guard_interval = GUARD_INTERVAL_1_32; 5998c2ecf20Sopenharmony_ci schan.modulation = QAM_64; 6008c2ecf20Sopenharmony_ci schan.code_rate_HP = FEC_2_3; 6018c2ecf20Sopenharmony_ci schan.code_rate_LP = FEC_2_3; 6028c2ecf20Sopenharmony_ci schan.hierarchy = 0; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci dib3000mc_set_channel_cfg(state, &schan, 11); 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci reg = dib3000mc_read_word(state, 0); 6078c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 0, reg | (1 << 8)); 6088c2ecf20Sopenharmony_ci dib3000mc_read_word(state, 511); 6098c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 0, reg); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci return 0; 6128c2ecf20Sopenharmony_ci} 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_cistatic int dib3000mc_autosearch_is_irq(struct dvb_frontend *demod) 6158c2ecf20Sopenharmony_ci{ 6168c2ecf20Sopenharmony_ci struct dib3000mc_state *state = demod->demodulator_priv; 6178c2ecf20Sopenharmony_ci u16 irq_pending = dib3000mc_read_word(state, 511); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci if (irq_pending & 0x1) // failed 6208c2ecf20Sopenharmony_ci return 1; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci if (irq_pending & 0x2) // succeeded 6238c2ecf20Sopenharmony_ci return 2; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci return 0; // still pending 6268c2ecf20Sopenharmony_ci} 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_cistatic int dib3000mc_tune(struct dvb_frontend *demod) 6298c2ecf20Sopenharmony_ci{ 6308c2ecf20Sopenharmony_ci struct dtv_frontend_properties *ch = &demod->dtv_property_cache; 6318c2ecf20Sopenharmony_ci struct dib3000mc_state *state = demod->demodulator_priv; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci // ** configure demod ** 6348c2ecf20Sopenharmony_ci dib3000mc_set_channel_cfg(state, ch, 0); 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci // activates isi 6378c2ecf20Sopenharmony_ci if (state->sfn_workaround_active) { 6388c2ecf20Sopenharmony_ci dprintk("SFN workaround is active\n"); 6398c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 29, 0x1273); 6408c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 108, 0x4000); // P_pha3_force_pha_shift 6418c2ecf20Sopenharmony_ci } else { 6428c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 29, 0x1073); 6438c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 108, 0x0000); // P_pha3_force_pha_shift 6448c2ecf20Sopenharmony_ci } 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci dib3000mc_set_adp_cfg(state, (u8)ch->modulation); 6478c2ecf20Sopenharmony_ci if (ch->transmission_mode == TRANSMISSION_MODE_8K) { 6488c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 26, 38528); 6498c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 33, 8); 6508c2ecf20Sopenharmony_ci } else { 6518c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 26, 30336); 6528c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 33, 6); 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci if (dib3000mc_read_word(state, 509) & 0x80) 6568c2ecf20Sopenharmony_ci dib3000mc_set_timing(state, ch->transmission_mode, 6578c2ecf20Sopenharmony_ci BANDWIDTH_TO_KHZ(ch->bandwidth_hz), 1); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci return 0; 6608c2ecf20Sopenharmony_ci} 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_cistruct i2c_adapter * dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod, int gating) 6638c2ecf20Sopenharmony_ci{ 6648c2ecf20Sopenharmony_ci struct dib3000mc_state *st = demod->demodulator_priv; 6658c2ecf20Sopenharmony_ci return dibx000_get_i2c_adapter(&st->i2c_master, DIBX000_I2C_INTERFACE_TUNER, gating); 6668c2ecf20Sopenharmony_ci} 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dib3000mc_get_tuner_i2c_master); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_cistatic int dib3000mc_get_frontend(struct dvb_frontend* fe, 6718c2ecf20Sopenharmony_ci struct dtv_frontend_properties *fep) 6728c2ecf20Sopenharmony_ci{ 6738c2ecf20Sopenharmony_ci struct dib3000mc_state *state = fe->demodulator_priv; 6748c2ecf20Sopenharmony_ci u16 tps = dib3000mc_read_word(state,458); 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci fep->inversion = INVERSION_AUTO; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci fep->bandwidth_hz = state->current_bandwidth; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci switch ((tps >> 8) & 0x1) { 6818c2ecf20Sopenharmony_ci case 0: fep->transmission_mode = TRANSMISSION_MODE_2K; break; 6828c2ecf20Sopenharmony_ci case 1: fep->transmission_mode = TRANSMISSION_MODE_8K; break; 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci switch (tps & 0x3) { 6868c2ecf20Sopenharmony_ci case 0: fep->guard_interval = GUARD_INTERVAL_1_32; break; 6878c2ecf20Sopenharmony_ci case 1: fep->guard_interval = GUARD_INTERVAL_1_16; break; 6888c2ecf20Sopenharmony_ci case 2: fep->guard_interval = GUARD_INTERVAL_1_8; break; 6898c2ecf20Sopenharmony_ci case 3: fep->guard_interval = GUARD_INTERVAL_1_4; break; 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci switch ((tps >> 13) & 0x3) { 6938c2ecf20Sopenharmony_ci case 0: fep->modulation = QPSK; break; 6948c2ecf20Sopenharmony_ci case 1: fep->modulation = QAM_16; break; 6958c2ecf20Sopenharmony_ci case 2: 6968c2ecf20Sopenharmony_ci default: fep->modulation = QAM_64; break; 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */ 7008c2ecf20Sopenharmony_ci /* (tps >> 12) & 0x1 == hrch is used, (tps >> 9) & 0x7 == alpha */ 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci fep->hierarchy = HIERARCHY_NONE; 7038c2ecf20Sopenharmony_ci switch ((tps >> 5) & 0x7) { 7048c2ecf20Sopenharmony_ci case 1: fep->code_rate_HP = FEC_1_2; break; 7058c2ecf20Sopenharmony_ci case 2: fep->code_rate_HP = FEC_2_3; break; 7068c2ecf20Sopenharmony_ci case 3: fep->code_rate_HP = FEC_3_4; break; 7078c2ecf20Sopenharmony_ci case 5: fep->code_rate_HP = FEC_5_6; break; 7088c2ecf20Sopenharmony_ci case 7: 7098c2ecf20Sopenharmony_ci default: fep->code_rate_HP = FEC_7_8; break; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci switch ((tps >> 2) & 0x7) { 7148c2ecf20Sopenharmony_ci case 1: fep->code_rate_LP = FEC_1_2; break; 7158c2ecf20Sopenharmony_ci case 2: fep->code_rate_LP = FEC_2_3; break; 7168c2ecf20Sopenharmony_ci case 3: fep->code_rate_LP = FEC_3_4; break; 7178c2ecf20Sopenharmony_ci case 5: fep->code_rate_LP = FEC_5_6; break; 7188c2ecf20Sopenharmony_ci case 7: 7198c2ecf20Sopenharmony_ci default: fep->code_rate_LP = FEC_7_8; break; 7208c2ecf20Sopenharmony_ci } 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci return 0; 7238c2ecf20Sopenharmony_ci} 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_cistatic int dib3000mc_set_frontend(struct dvb_frontend *fe) 7268c2ecf20Sopenharmony_ci{ 7278c2ecf20Sopenharmony_ci struct dtv_frontend_properties *fep = &fe->dtv_property_cache; 7288c2ecf20Sopenharmony_ci struct dib3000mc_state *state = fe->demodulator_priv; 7298c2ecf20Sopenharmony_ci int ret; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci state->current_bandwidth = fep->bandwidth_hz; 7348c2ecf20Sopenharmony_ci dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->bandwidth_hz)); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci /* maybe the parameter has been changed */ 7378c2ecf20Sopenharmony_ci state->sfn_workaround_active = buggy_sfn_workaround; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci if (fe->ops.tuner_ops.set_params) { 7408c2ecf20Sopenharmony_ci fe->ops.tuner_ops.set_params(fe); 7418c2ecf20Sopenharmony_ci msleep(100); 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci if (fep->transmission_mode == TRANSMISSION_MODE_AUTO || 7458c2ecf20Sopenharmony_ci fep->guard_interval == GUARD_INTERVAL_AUTO || 7468c2ecf20Sopenharmony_ci fep->modulation == QAM_AUTO || 7478c2ecf20Sopenharmony_ci fep->code_rate_HP == FEC_AUTO) { 7488c2ecf20Sopenharmony_ci int i = 1000, found; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci dib3000mc_autosearch_start(fe); 7518c2ecf20Sopenharmony_ci do { 7528c2ecf20Sopenharmony_ci msleep(1); 7538c2ecf20Sopenharmony_ci found = dib3000mc_autosearch_is_irq(fe); 7548c2ecf20Sopenharmony_ci } while (found == 0 && i--); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci dprintk("autosearch returns: %d\n",found); 7578c2ecf20Sopenharmony_ci if (found == 0 || found == 1) 7588c2ecf20Sopenharmony_ci return 0; // no channel found 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci dib3000mc_get_frontend(fe, fep); 7618c2ecf20Sopenharmony_ci } 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci ret = dib3000mc_tune(fe); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci /* make this a config parameter */ 7668c2ecf20Sopenharmony_ci dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO); 7678c2ecf20Sopenharmony_ci return ret; 7688c2ecf20Sopenharmony_ci} 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_cistatic int dib3000mc_read_status(struct dvb_frontend *fe, enum fe_status *stat) 7718c2ecf20Sopenharmony_ci{ 7728c2ecf20Sopenharmony_ci struct dib3000mc_state *state = fe->demodulator_priv; 7738c2ecf20Sopenharmony_ci u16 lock = dib3000mc_read_word(state, 509); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci *stat = 0; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci if (lock & 0x8000) 7788c2ecf20Sopenharmony_ci *stat |= FE_HAS_SIGNAL; 7798c2ecf20Sopenharmony_ci if (lock & 0x3000) 7808c2ecf20Sopenharmony_ci *stat |= FE_HAS_CARRIER; 7818c2ecf20Sopenharmony_ci if (lock & 0x0100) 7828c2ecf20Sopenharmony_ci *stat |= FE_HAS_VITERBI; 7838c2ecf20Sopenharmony_ci if (lock & 0x0010) 7848c2ecf20Sopenharmony_ci *stat |= FE_HAS_SYNC; 7858c2ecf20Sopenharmony_ci if (lock & 0x0008) 7868c2ecf20Sopenharmony_ci *stat |= FE_HAS_LOCK; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci return 0; 7898c2ecf20Sopenharmony_ci} 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_cistatic int dib3000mc_read_ber(struct dvb_frontend *fe, u32 *ber) 7928c2ecf20Sopenharmony_ci{ 7938c2ecf20Sopenharmony_ci struct dib3000mc_state *state = fe->demodulator_priv; 7948c2ecf20Sopenharmony_ci *ber = (dib3000mc_read_word(state, 500) << 16) | dib3000mc_read_word(state, 501); 7958c2ecf20Sopenharmony_ci return 0; 7968c2ecf20Sopenharmony_ci} 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_cistatic int dib3000mc_read_unc_blocks(struct dvb_frontend *fe, u32 *unc) 7998c2ecf20Sopenharmony_ci{ 8008c2ecf20Sopenharmony_ci struct dib3000mc_state *state = fe->demodulator_priv; 8018c2ecf20Sopenharmony_ci *unc = dib3000mc_read_word(state, 508); 8028c2ecf20Sopenharmony_ci return 0; 8038c2ecf20Sopenharmony_ci} 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_cistatic int dib3000mc_read_signal_strength(struct dvb_frontend *fe, u16 *strength) 8068c2ecf20Sopenharmony_ci{ 8078c2ecf20Sopenharmony_ci struct dib3000mc_state *state = fe->demodulator_priv; 8088c2ecf20Sopenharmony_ci u16 val = dib3000mc_read_word(state, 392); 8098c2ecf20Sopenharmony_ci *strength = 65535 - val; 8108c2ecf20Sopenharmony_ci return 0; 8118c2ecf20Sopenharmony_ci} 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_cistatic int dib3000mc_read_snr(struct dvb_frontend* fe, u16 *snr) 8148c2ecf20Sopenharmony_ci{ 8158c2ecf20Sopenharmony_ci *snr = 0x0000; 8168c2ecf20Sopenharmony_ci return 0; 8178c2ecf20Sopenharmony_ci} 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_cistatic int dib3000mc_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) 8208c2ecf20Sopenharmony_ci{ 8218c2ecf20Sopenharmony_ci tune->min_delay_ms = 1000; 8228c2ecf20Sopenharmony_ci return 0; 8238c2ecf20Sopenharmony_ci} 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_cistatic void dib3000mc_release(struct dvb_frontend *fe) 8268c2ecf20Sopenharmony_ci{ 8278c2ecf20Sopenharmony_ci struct dib3000mc_state *state = fe->demodulator_priv; 8288c2ecf20Sopenharmony_ci dibx000_exit_i2c_master(&state->i2c_master); 8298c2ecf20Sopenharmony_ci kfree(state); 8308c2ecf20Sopenharmony_ci} 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ciint dib3000mc_pid_control(struct dvb_frontend *fe, int index, int pid,int onoff) 8338c2ecf20Sopenharmony_ci{ 8348c2ecf20Sopenharmony_ci struct dib3000mc_state *state = fe->demodulator_priv; 8358c2ecf20Sopenharmony_ci dib3000mc_write_word(state, 212 + index, onoff ? (1 << 13) | pid : 0); 8368c2ecf20Sopenharmony_ci return 0; 8378c2ecf20Sopenharmony_ci} 8388c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dib3000mc_pid_control); 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ciint dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff) 8418c2ecf20Sopenharmony_ci{ 8428c2ecf20Sopenharmony_ci struct dib3000mc_state *state = fe->demodulator_priv; 8438c2ecf20Sopenharmony_ci u16 tmp = dib3000mc_read_word(state, 206) & ~(1 << 4); 8448c2ecf20Sopenharmony_ci tmp |= (onoff << 4); 8458c2ecf20Sopenharmony_ci return dib3000mc_write_word(state, 206, tmp); 8468c2ecf20Sopenharmony_ci} 8478c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dib3000mc_pid_parse); 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_civoid dib3000mc_set_config(struct dvb_frontend *fe, struct dib3000mc_config *cfg) 8508c2ecf20Sopenharmony_ci{ 8518c2ecf20Sopenharmony_ci struct dib3000mc_state *state = fe->demodulator_priv; 8528c2ecf20Sopenharmony_ci state->cfg = cfg; 8538c2ecf20Sopenharmony_ci} 8548c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dib3000mc_set_config); 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ciint dib3000mc_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib3000mc_config cfg[]) 8578c2ecf20Sopenharmony_ci{ 8588c2ecf20Sopenharmony_ci struct dib3000mc_state *dmcst; 8598c2ecf20Sopenharmony_ci int k; 8608c2ecf20Sopenharmony_ci u8 new_addr; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci static u8 DIB3000MC_I2C_ADDRESS[] = {20,22,24,26}; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci dmcst = kzalloc(sizeof(struct dib3000mc_state), GFP_KERNEL); 8658c2ecf20Sopenharmony_ci if (dmcst == NULL) 8668c2ecf20Sopenharmony_ci return -ENOMEM; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci dmcst->i2c_adap = i2c; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci for (k = no_of_demods-1; k >= 0; k--) { 8718c2ecf20Sopenharmony_ci dmcst->cfg = &cfg[k]; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci /* designated i2c address */ 8748c2ecf20Sopenharmony_ci new_addr = DIB3000MC_I2C_ADDRESS[k]; 8758c2ecf20Sopenharmony_ci dmcst->i2c_addr = new_addr; 8768c2ecf20Sopenharmony_ci if (dib3000mc_identify(dmcst) != 0) { 8778c2ecf20Sopenharmony_ci dmcst->i2c_addr = default_addr; 8788c2ecf20Sopenharmony_ci if (dib3000mc_identify(dmcst) != 0) { 8798c2ecf20Sopenharmony_ci dprintk("-E- DiB3000P/MC #%d: not identified\n", k); 8808c2ecf20Sopenharmony_ci kfree(dmcst); 8818c2ecf20Sopenharmony_ci return -ENODEV; 8828c2ecf20Sopenharmony_ci } 8838c2ecf20Sopenharmony_ci } 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci dib3000mc_set_output_mode(dmcst, OUTMODE_MPEG2_PAR_CONT_CLK); 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci // set new i2c address and force divstr (Bit 1) to value 0 (Bit 0) 8888c2ecf20Sopenharmony_ci dib3000mc_write_word(dmcst, 1024, (new_addr << 3) | 0x1); 8898c2ecf20Sopenharmony_ci dmcst->i2c_addr = new_addr; 8908c2ecf20Sopenharmony_ci } 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci for (k = 0; k < no_of_demods; k++) { 8938c2ecf20Sopenharmony_ci dmcst->cfg = &cfg[k]; 8948c2ecf20Sopenharmony_ci dmcst->i2c_addr = DIB3000MC_I2C_ADDRESS[k]; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci dib3000mc_write_word(dmcst, 1024, dmcst->i2c_addr << 3); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci /* turn off data output */ 8998c2ecf20Sopenharmony_ci dib3000mc_set_output_mode(dmcst, OUTMODE_HIGH_Z); 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci kfree(dmcst); 9038c2ecf20Sopenharmony_ci return 0; 9048c2ecf20Sopenharmony_ci} 9058c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dib3000mc_i2c_enumeration); 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops dib3000mc_ops; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_cistruct dvb_frontend * dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib3000mc_config *cfg) 9108c2ecf20Sopenharmony_ci{ 9118c2ecf20Sopenharmony_ci struct dvb_frontend *demod; 9128c2ecf20Sopenharmony_ci struct dib3000mc_state *st; 9138c2ecf20Sopenharmony_ci st = kzalloc(sizeof(struct dib3000mc_state), GFP_KERNEL); 9148c2ecf20Sopenharmony_ci if (st == NULL) 9158c2ecf20Sopenharmony_ci return NULL; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci st->cfg = cfg; 9188c2ecf20Sopenharmony_ci st->i2c_adap = i2c_adap; 9198c2ecf20Sopenharmony_ci st->i2c_addr = i2c_addr; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci demod = &st->demod; 9228c2ecf20Sopenharmony_ci demod->demodulator_priv = st; 9238c2ecf20Sopenharmony_ci memcpy(&st->demod.ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops)); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci if (dib3000mc_identify(st) != 0) 9268c2ecf20Sopenharmony_ci goto error; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci dibx000_init_i2c_master(&st->i2c_master, DIB3000MC, st->i2c_adap, st->i2c_addr); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci dib3000mc_write_word(st, 1037, 0x3130); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci return demod; 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_cierror: 9358c2ecf20Sopenharmony_ci kfree(st); 9368c2ecf20Sopenharmony_ci return NULL; 9378c2ecf20Sopenharmony_ci} 9388c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dib3000mc_attach); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops dib3000mc_ops = { 9418c2ecf20Sopenharmony_ci .delsys = { SYS_DVBT }, 9428c2ecf20Sopenharmony_ci .info = { 9438c2ecf20Sopenharmony_ci .name = "DiBcom 3000MC/P", 9448c2ecf20Sopenharmony_ci .frequency_min_hz = 44250 * kHz, 9458c2ecf20Sopenharmony_ci .frequency_max_hz = 867250 * kHz, 9468c2ecf20Sopenharmony_ci .frequency_stepsize_hz = 62500, 9478c2ecf20Sopenharmony_ci .caps = FE_CAN_INVERSION_AUTO | 9488c2ecf20Sopenharmony_ci FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 9498c2ecf20Sopenharmony_ci FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | 9508c2ecf20Sopenharmony_ci FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | 9518c2ecf20Sopenharmony_ci FE_CAN_TRANSMISSION_MODE_AUTO | 9528c2ecf20Sopenharmony_ci FE_CAN_GUARD_INTERVAL_AUTO | 9538c2ecf20Sopenharmony_ci FE_CAN_RECOVER | 9548c2ecf20Sopenharmony_ci FE_CAN_HIERARCHY_AUTO, 9558c2ecf20Sopenharmony_ci }, 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci .release = dib3000mc_release, 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci .init = dib3000mc_init, 9608c2ecf20Sopenharmony_ci .sleep = dib3000mc_sleep, 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci .set_frontend = dib3000mc_set_frontend, 9638c2ecf20Sopenharmony_ci .get_tune_settings = dib3000mc_fe_get_tune_settings, 9648c2ecf20Sopenharmony_ci .get_frontend = dib3000mc_get_frontend, 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci .read_status = dib3000mc_read_status, 9678c2ecf20Sopenharmony_ci .read_ber = dib3000mc_read_ber, 9688c2ecf20Sopenharmony_ci .read_signal_strength = dib3000mc_read_signal_strength, 9698c2ecf20Sopenharmony_ci .read_snr = dib3000mc_read_snr, 9708c2ecf20Sopenharmony_ci .read_ucblocks = dib3000mc_read_unc_blocks, 9718c2ecf20Sopenharmony_ci}; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ciMODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>"); 9748c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Driver for the DiBcom 3000MC/P COFDM demodulator"); 9758c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 976