18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci Montage Technology DS3000 - DVBS/S2 Demodulator driver 48c2ecf20Sopenharmony_ci Copyright (C) 2009-2012 Konstantin Dimitrov <kosio.dimitrov@gmail.com> 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci Copyright (C) 2009-2012 TurboSight.com 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 148c2ecf20Sopenharmony_ci#include <linux/init.h> 158c2ecf20Sopenharmony_ci#include <linux/firmware.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h> 188c2ecf20Sopenharmony_ci#include "ts2020.h" 198c2ecf20Sopenharmony_ci#include "ds3000.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic int debug; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define dprintk(args...) \ 248c2ecf20Sopenharmony_ci do { \ 258c2ecf20Sopenharmony_ci if (debug) \ 268c2ecf20Sopenharmony_ci printk(args); \ 278c2ecf20Sopenharmony_ci } while (0) 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/* as of March 2009 current DS3000 firmware version is 1.78 */ 308c2ecf20Sopenharmony_ci/* DS3000 FW v1.78 MD5: a32d17910c4f370073f9346e71d34b80 */ 318c2ecf20Sopenharmony_ci#define DS3000_DEFAULT_FIRMWARE "dvb-fe-ds3000.fw" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define DS3000_SAMPLE_RATE 96000 /* in kHz */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* Register values to initialise the demod in DVB-S mode */ 368c2ecf20Sopenharmony_cistatic u8 ds3000_dvbs_init_tab[] = { 378c2ecf20Sopenharmony_ci 0x23, 0x05, 388c2ecf20Sopenharmony_ci 0x08, 0x03, 398c2ecf20Sopenharmony_ci 0x0c, 0x00, 408c2ecf20Sopenharmony_ci 0x21, 0x54, 418c2ecf20Sopenharmony_ci 0x25, 0x82, 428c2ecf20Sopenharmony_ci 0x27, 0x31, 438c2ecf20Sopenharmony_ci 0x30, 0x08, 448c2ecf20Sopenharmony_ci 0x31, 0x40, 458c2ecf20Sopenharmony_ci 0x32, 0x32, 468c2ecf20Sopenharmony_ci 0x33, 0x35, 478c2ecf20Sopenharmony_ci 0x35, 0xff, 488c2ecf20Sopenharmony_ci 0x3a, 0x00, 498c2ecf20Sopenharmony_ci 0x37, 0x10, 508c2ecf20Sopenharmony_ci 0x38, 0x10, 518c2ecf20Sopenharmony_ci 0x39, 0x02, 528c2ecf20Sopenharmony_ci 0x42, 0x60, 538c2ecf20Sopenharmony_ci 0x4a, 0x40, 548c2ecf20Sopenharmony_ci 0x4b, 0x04, 558c2ecf20Sopenharmony_ci 0x4d, 0x91, 568c2ecf20Sopenharmony_ci 0x5d, 0xc8, 578c2ecf20Sopenharmony_ci 0x50, 0x77, 588c2ecf20Sopenharmony_ci 0x51, 0x77, 598c2ecf20Sopenharmony_ci 0x52, 0x36, 608c2ecf20Sopenharmony_ci 0x53, 0x36, 618c2ecf20Sopenharmony_ci 0x56, 0x01, 628c2ecf20Sopenharmony_ci 0x63, 0x43, 638c2ecf20Sopenharmony_ci 0x64, 0x30, 648c2ecf20Sopenharmony_ci 0x65, 0x40, 658c2ecf20Sopenharmony_ci 0x68, 0x26, 668c2ecf20Sopenharmony_ci 0x69, 0x4c, 678c2ecf20Sopenharmony_ci 0x70, 0x20, 688c2ecf20Sopenharmony_ci 0x71, 0x70, 698c2ecf20Sopenharmony_ci 0x72, 0x04, 708c2ecf20Sopenharmony_ci 0x73, 0x00, 718c2ecf20Sopenharmony_ci 0x70, 0x40, 728c2ecf20Sopenharmony_ci 0x71, 0x70, 738c2ecf20Sopenharmony_ci 0x72, 0x04, 748c2ecf20Sopenharmony_ci 0x73, 0x00, 758c2ecf20Sopenharmony_ci 0x70, 0x60, 768c2ecf20Sopenharmony_ci 0x71, 0x70, 778c2ecf20Sopenharmony_ci 0x72, 0x04, 788c2ecf20Sopenharmony_ci 0x73, 0x00, 798c2ecf20Sopenharmony_ci 0x70, 0x80, 808c2ecf20Sopenharmony_ci 0x71, 0x70, 818c2ecf20Sopenharmony_ci 0x72, 0x04, 828c2ecf20Sopenharmony_ci 0x73, 0x00, 838c2ecf20Sopenharmony_ci 0x70, 0xa0, 848c2ecf20Sopenharmony_ci 0x71, 0x70, 858c2ecf20Sopenharmony_ci 0x72, 0x04, 868c2ecf20Sopenharmony_ci 0x73, 0x00, 878c2ecf20Sopenharmony_ci 0x70, 0x1f, 888c2ecf20Sopenharmony_ci 0x76, 0x00, 898c2ecf20Sopenharmony_ci 0x77, 0xd1, 908c2ecf20Sopenharmony_ci 0x78, 0x0c, 918c2ecf20Sopenharmony_ci 0x79, 0x80, 928c2ecf20Sopenharmony_ci 0x7f, 0x04, 938c2ecf20Sopenharmony_ci 0x7c, 0x00, 948c2ecf20Sopenharmony_ci 0x80, 0x86, 958c2ecf20Sopenharmony_ci 0x81, 0xa6, 968c2ecf20Sopenharmony_ci 0x85, 0x04, 978c2ecf20Sopenharmony_ci 0xcd, 0xf4, 988c2ecf20Sopenharmony_ci 0x90, 0x33, 998c2ecf20Sopenharmony_ci 0xa0, 0x44, 1008c2ecf20Sopenharmony_ci 0xc0, 0x18, 1018c2ecf20Sopenharmony_ci 0xc3, 0x10, 1028c2ecf20Sopenharmony_ci 0xc4, 0x08, 1038c2ecf20Sopenharmony_ci 0xc5, 0x80, 1048c2ecf20Sopenharmony_ci 0xc6, 0x80, 1058c2ecf20Sopenharmony_ci 0xc7, 0x0a, 1068c2ecf20Sopenharmony_ci 0xc8, 0x1a, 1078c2ecf20Sopenharmony_ci 0xc9, 0x80, 1088c2ecf20Sopenharmony_ci 0xfe, 0x92, 1098c2ecf20Sopenharmony_ci 0xe0, 0xf8, 1108c2ecf20Sopenharmony_ci 0xe6, 0x8b, 1118c2ecf20Sopenharmony_ci 0xd0, 0x40, 1128c2ecf20Sopenharmony_ci 0xf8, 0x20, 1138c2ecf20Sopenharmony_ci 0xfa, 0x0f, 1148c2ecf20Sopenharmony_ci 0xfd, 0x20, 1158c2ecf20Sopenharmony_ci 0xad, 0x20, 1168c2ecf20Sopenharmony_ci 0xae, 0x07, 1178c2ecf20Sopenharmony_ci 0xb8, 0x00, 1188c2ecf20Sopenharmony_ci}; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci/* Register values to initialise the demod in DVB-S2 mode */ 1218c2ecf20Sopenharmony_cistatic u8 ds3000_dvbs2_init_tab[] = { 1228c2ecf20Sopenharmony_ci 0x23, 0x0f, 1238c2ecf20Sopenharmony_ci 0x08, 0x07, 1248c2ecf20Sopenharmony_ci 0x0c, 0x00, 1258c2ecf20Sopenharmony_ci 0x21, 0x54, 1268c2ecf20Sopenharmony_ci 0x25, 0x82, 1278c2ecf20Sopenharmony_ci 0x27, 0x31, 1288c2ecf20Sopenharmony_ci 0x30, 0x08, 1298c2ecf20Sopenharmony_ci 0x31, 0x32, 1308c2ecf20Sopenharmony_ci 0x32, 0x32, 1318c2ecf20Sopenharmony_ci 0x33, 0x35, 1328c2ecf20Sopenharmony_ci 0x35, 0xff, 1338c2ecf20Sopenharmony_ci 0x3a, 0x00, 1348c2ecf20Sopenharmony_ci 0x37, 0x10, 1358c2ecf20Sopenharmony_ci 0x38, 0x10, 1368c2ecf20Sopenharmony_ci 0x39, 0x02, 1378c2ecf20Sopenharmony_ci 0x42, 0x60, 1388c2ecf20Sopenharmony_ci 0x4a, 0x80, 1398c2ecf20Sopenharmony_ci 0x4b, 0x04, 1408c2ecf20Sopenharmony_ci 0x4d, 0x81, 1418c2ecf20Sopenharmony_ci 0x5d, 0x88, 1428c2ecf20Sopenharmony_ci 0x50, 0x36, 1438c2ecf20Sopenharmony_ci 0x51, 0x36, 1448c2ecf20Sopenharmony_ci 0x52, 0x36, 1458c2ecf20Sopenharmony_ci 0x53, 0x36, 1468c2ecf20Sopenharmony_ci 0x63, 0x60, 1478c2ecf20Sopenharmony_ci 0x64, 0x10, 1488c2ecf20Sopenharmony_ci 0x65, 0x10, 1498c2ecf20Sopenharmony_ci 0x68, 0x04, 1508c2ecf20Sopenharmony_ci 0x69, 0x29, 1518c2ecf20Sopenharmony_ci 0x70, 0x20, 1528c2ecf20Sopenharmony_ci 0x71, 0x70, 1538c2ecf20Sopenharmony_ci 0x72, 0x04, 1548c2ecf20Sopenharmony_ci 0x73, 0x00, 1558c2ecf20Sopenharmony_ci 0x70, 0x40, 1568c2ecf20Sopenharmony_ci 0x71, 0x70, 1578c2ecf20Sopenharmony_ci 0x72, 0x04, 1588c2ecf20Sopenharmony_ci 0x73, 0x00, 1598c2ecf20Sopenharmony_ci 0x70, 0x60, 1608c2ecf20Sopenharmony_ci 0x71, 0x70, 1618c2ecf20Sopenharmony_ci 0x72, 0x04, 1628c2ecf20Sopenharmony_ci 0x73, 0x00, 1638c2ecf20Sopenharmony_ci 0x70, 0x80, 1648c2ecf20Sopenharmony_ci 0x71, 0x70, 1658c2ecf20Sopenharmony_ci 0x72, 0x04, 1668c2ecf20Sopenharmony_ci 0x73, 0x00, 1678c2ecf20Sopenharmony_ci 0x70, 0xa0, 1688c2ecf20Sopenharmony_ci 0x71, 0x70, 1698c2ecf20Sopenharmony_ci 0x72, 0x04, 1708c2ecf20Sopenharmony_ci 0x73, 0x00, 1718c2ecf20Sopenharmony_ci 0x70, 0x1f, 1728c2ecf20Sopenharmony_ci 0xa0, 0x44, 1738c2ecf20Sopenharmony_ci 0xc0, 0x08, 1748c2ecf20Sopenharmony_ci 0xc1, 0x10, 1758c2ecf20Sopenharmony_ci 0xc2, 0x08, 1768c2ecf20Sopenharmony_ci 0xc3, 0x10, 1778c2ecf20Sopenharmony_ci 0xc4, 0x08, 1788c2ecf20Sopenharmony_ci 0xc5, 0xf0, 1798c2ecf20Sopenharmony_ci 0xc6, 0xf0, 1808c2ecf20Sopenharmony_ci 0xc7, 0x0a, 1818c2ecf20Sopenharmony_ci 0xc8, 0x1a, 1828c2ecf20Sopenharmony_ci 0xc9, 0x80, 1838c2ecf20Sopenharmony_ci 0xca, 0x23, 1848c2ecf20Sopenharmony_ci 0xcb, 0x24, 1858c2ecf20Sopenharmony_ci 0xce, 0x74, 1868c2ecf20Sopenharmony_ci 0x90, 0x03, 1878c2ecf20Sopenharmony_ci 0x76, 0x80, 1888c2ecf20Sopenharmony_ci 0x77, 0x42, 1898c2ecf20Sopenharmony_ci 0x78, 0x0a, 1908c2ecf20Sopenharmony_ci 0x79, 0x80, 1918c2ecf20Sopenharmony_ci 0xad, 0x40, 1928c2ecf20Sopenharmony_ci 0xae, 0x07, 1938c2ecf20Sopenharmony_ci 0x7f, 0xd4, 1948c2ecf20Sopenharmony_ci 0x7c, 0x00, 1958c2ecf20Sopenharmony_ci 0x80, 0xa8, 1968c2ecf20Sopenharmony_ci 0x81, 0xda, 1978c2ecf20Sopenharmony_ci 0x7c, 0x01, 1988c2ecf20Sopenharmony_ci 0x80, 0xda, 1998c2ecf20Sopenharmony_ci 0x81, 0xec, 2008c2ecf20Sopenharmony_ci 0x7c, 0x02, 2018c2ecf20Sopenharmony_ci 0x80, 0xca, 2028c2ecf20Sopenharmony_ci 0x81, 0xeb, 2038c2ecf20Sopenharmony_ci 0x7c, 0x03, 2048c2ecf20Sopenharmony_ci 0x80, 0xba, 2058c2ecf20Sopenharmony_ci 0x81, 0xdb, 2068c2ecf20Sopenharmony_ci 0x85, 0x08, 2078c2ecf20Sopenharmony_ci 0x86, 0x00, 2088c2ecf20Sopenharmony_ci 0x87, 0x02, 2098c2ecf20Sopenharmony_ci 0x89, 0x80, 2108c2ecf20Sopenharmony_ci 0x8b, 0x44, 2118c2ecf20Sopenharmony_ci 0x8c, 0xaa, 2128c2ecf20Sopenharmony_ci 0x8a, 0x10, 2138c2ecf20Sopenharmony_ci 0xba, 0x00, 2148c2ecf20Sopenharmony_ci 0xf5, 0x04, 2158c2ecf20Sopenharmony_ci 0xfe, 0x44, 2168c2ecf20Sopenharmony_ci 0xd2, 0x32, 2178c2ecf20Sopenharmony_ci 0xb8, 0x00, 2188c2ecf20Sopenharmony_ci}; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistruct ds3000_state { 2218c2ecf20Sopenharmony_ci struct i2c_adapter *i2c; 2228c2ecf20Sopenharmony_ci const struct ds3000_config *config; 2238c2ecf20Sopenharmony_ci struct dvb_frontend frontend; 2248c2ecf20Sopenharmony_ci /* previous uncorrected block counter for DVB-S2 */ 2258c2ecf20Sopenharmony_ci u16 prevUCBS2; 2268c2ecf20Sopenharmony_ci}; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic int ds3000_writereg(struct ds3000_state *state, int reg, int data) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci u8 buf[] = { reg, data }; 2318c2ecf20Sopenharmony_ci struct i2c_msg msg = { .addr = state->config->demod_address, 2328c2ecf20Sopenharmony_ci .flags = 0, .buf = buf, .len = 2 }; 2338c2ecf20Sopenharmony_ci int err; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci dprintk("%s: write reg 0x%02x, value 0x%02x\n", __func__, reg, data); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci err = i2c_transfer(state->i2c, &msg, 1); 2388c2ecf20Sopenharmony_ci if (err != 1) { 2398c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x, value == 0x%02x)\n", 2408c2ecf20Sopenharmony_ci __func__, err, reg, data); 2418c2ecf20Sopenharmony_ci return -EREMOTEIO; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci return 0; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic int ds3000_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci struct ds3000_state *state = fe->demodulator_priv; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (enable) 2528c2ecf20Sopenharmony_ci ds3000_writereg(state, 0x03, 0x12); 2538c2ecf20Sopenharmony_ci else 2548c2ecf20Sopenharmony_ci ds3000_writereg(state, 0x03, 0x02); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci return 0; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci/* I2C write for 8k firmware load */ 2608c2ecf20Sopenharmony_cistatic int ds3000_writeFW(struct ds3000_state *state, int reg, 2618c2ecf20Sopenharmony_ci const u8 *data, u16 len) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci int i, ret = 0; 2648c2ecf20Sopenharmony_ci struct i2c_msg msg; 2658c2ecf20Sopenharmony_ci u8 *buf; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci buf = kmalloc(33, GFP_KERNEL); 2688c2ecf20Sopenharmony_ci if (!buf) 2698c2ecf20Sopenharmony_ci return -ENOMEM; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci *(buf) = reg; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci msg.addr = state->config->demod_address; 2748c2ecf20Sopenharmony_ci msg.flags = 0; 2758c2ecf20Sopenharmony_ci msg.buf = buf; 2768c2ecf20Sopenharmony_ci msg.len = 33; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci for (i = 0; i < len; i += 32) { 2798c2ecf20Sopenharmony_ci memcpy(buf + 1, data + i, 32); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci dprintk("%s: write reg 0x%02x, len = %d\n", __func__, reg, len); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci ret = i2c_transfer(state->i2c, &msg, 1); 2848c2ecf20Sopenharmony_ci if (ret != 1) { 2858c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: write error(err == %i, reg == 0x%02x\n", 2868c2ecf20Sopenharmony_ci __func__, ret, reg); 2878c2ecf20Sopenharmony_ci ret = -EREMOTEIO; 2888c2ecf20Sopenharmony_ci goto error; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci ret = 0; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cierror: 2948c2ecf20Sopenharmony_ci kfree(buf); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci return ret; 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic int ds3000_readreg(struct ds3000_state *state, u8 reg) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci int ret; 3028c2ecf20Sopenharmony_ci u8 b0[] = { reg }; 3038c2ecf20Sopenharmony_ci u8 b1[] = { 0 }; 3048c2ecf20Sopenharmony_ci struct i2c_msg msg[] = { 3058c2ecf20Sopenharmony_ci { 3068c2ecf20Sopenharmony_ci .addr = state->config->demod_address, 3078c2ecf20Sopenharmony_ci .flags = 0, 3088c2ecf20Sopenharmony_ci .buf = b0, 3098c2ecf20Sopenharmony_ci .len = 1 3108c2ecf20Sopenharmony_ci }, { 3118c2ecf20Sopenharmony_ci .addr = state->config->demod_address, 3128c2ecf20Sopenharmony_ci .flags = I2C_M_RD, 3138c2ecf20Sopenharmony_ci .buf = b1, 3148c2ecf20Sopenharmony_ci .len = 1 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci }; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci ret = i2c_transfer(state->i2c, msg, 2); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (ret != 2) { 3218c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret); 3228c2ecf20Sopenharmony_ci return ret; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci dprintk("%s: read reg 0x%02x, value 0x%02x\n", __func__, reg, b1[0]); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci return b1[0]; 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic int ds3000_load_firmware(struct dvb_frontend *fe, 3318c2ecf20Sopenharmony_ci const struct firmware *fw); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic int ds3000_firmware_ondemand(struct dvb_frontend *fe) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci struct ds3000_state *state = fe->demodulator_priv; 3368c2ecf20Sopenharmony_ci const struct firmware *fw; 3378c2ecf20Sopenharmony_ci int ret = 0; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci dprintk("%s()\n", __func__); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci ret = ds3000_readreg(state, 0xb2); 3428c2ecf20Sopenharmony_ci if (ret < 0) 3438c2ecf20Sopenharmony_ci return ret; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci /* Load firmware */ 3468c2ecf20Sopenharmony_ci /* request the firmware, this will block until someone uploads it */ 3478c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__, 3488c2ecf20Sopenharmony_ci DS3000_DEFAULT_FIRMWARE); 3498c2ecf20Sopenharmony_ci ret = request_firmware(&fw, DS3000_DEFAULT_FIRMWARE, 3508c2ecf20Sopenharmony_ci state->i2c->dev.parent); 3518c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n", __func__); 3528c2ecf20Sopenharmony_ci if (ret) { 3538c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: No firmware uploaded (timeout or file not found?)\n", 3548c2ecf20Sopenharmony_ci __func__); 3558c2ecf20Sopenharmony_ci return ret; 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci ret = ds3000_load_firmware(fe, fw); 3598c2ecf20Sopenharmony_ci if (ret) 3608c2ecf20Sopenharmony_ci printk("%s: Writing firmware to device failed\n", __func__); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci release_firmware(fw); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci dprintk("%s: Firmware upload %s\n", __func__, 3658c2ecf20Sopenharmony_ci ret == 0 ? "complete" : "failed"); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci return ret; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic int ds3000_load_firmware(struct dvb_frontend *fe, 3718c2ecf20Sopenharmony_ci const struct firmware *fw) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci struct ds3000_state *state = fe->demodulator_priv; 3748c2ecf20Sopenharmony_ci int ret = 0; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 3778c2ecf20Sopenharmony_ci dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n", 3788c2ecf20Sopenharmony_ci fw->size, 3798c2ecf20Sopenharmony_ci fw->data[0], 3808c2ecf20Sopenharmony_ci fw->data[1], 3818c2ecf20Sopenharmony_ci fw->data[fw->size - 2], 3828c2ecf20Sopenharmony_ci fw->data[fw->size - 1]); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci /* Begin the firmware load process */ 3858c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xb2, 0x01); 3868c2ecf20Sopenharmony_ci /* write the entire firmware */ 3878c2ecf20Sopenharmony_ci ret = ds3000_writeFW(state, 0xb0, fw->data, fw->size); 3888c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xb2, 0x00); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci return ret; 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_cistatic int ds3000_set_voltage(struct dvb_frontend *fe, 3948c2ecf20Sopenharmony_ci enum fe_sec_voltage voltage) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci struct ds3000_state *state = fe->demodulator_priv; 3978c2ecf20Sopenharmony_ci u8 data; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci dprintk("%s(%d)\n", __func__, voltage); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci data = ds3000_readreg(state, 0xa2); 4028c2ecf20Sopenharmony_ci data |= 0x03; /* bit0 V/H, bit1 off/on */ 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci switch (voltage) { 4058c2ecf20Sopenharmony_ci case SEC_VOLTAGE_18: 4068c2ecf20Sopenharmony_ci data &= ~0x03; 4078c2ecf20Sopenharmony_ci break; 4088c2ecf20Sopenharmony_ci case SEC_VOLTAGE_13: 4098c2ecf20Sopenharmony_ci data &= ~0x03; 4108c2ecf20Sopenharmony_ci data |= 0x01; 4118c2ecf20Sopenharmony_ci break; 4128c2ecf20Sopenharmony_ci case SEC_VOLTAGE_OFF: 4138c2ecf20Sopenharmony_ci break; 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xa2, data); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci return 0; 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic int ds3000_read_status(struct dvb_frontend *fe, enum fe_status *status) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci struct ds3000_state *state = fe->demodulator_priv; 4248c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 4258c2ecf20Sopenharmony_ci int lock; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci *status = 0; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci switch (c->delivery_system) { 4308c2ecf20Sopenharmony_ci case SYS_DVBS: 4318c2ecf20Sopenharmony_ci lock = ds3000_readreg(state, 0xd1); 4328c2ecf20Sopenharmony_ci if ((lock & 0x07) == 0x07) 4338c2ecf20Sopenharmony_ci *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | 4348c2ecf20Sopenharmony_ci FE_HAS_VITERBI | FE_HAS_SYNC | 4358c2ecf20Sopenharmony_ci FE_HAS_LOCK; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci break; 4388c2ecf20Sopenharmony_ci case SYS_DVBS2: 4398c2ecf20Sopenharmony_ci lock = ds3000_readreg(state, 0x0d); 4408c2ecf20Sopenharmony_ci if ((lock & 0x8f) == 0x8f) 4418c2ecf20Sopenharmony_ci *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | 4428c2ecf20Sopenharmony_ci FE_HAS_VITERBI | FE_HAS_SYNC | 4438c2ecf20Sopenharmony_ci FE_HAS_LOCK; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci break; 4468c2ecf20Sopenharmony_ci default: 4478c2ecf20Sopenharmony_ci return -EINVAL; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci if (state->config->set_lock_led) 4518c2ecf20Sopenharmony_ci state->config->set_lock_led(fe, *status == 0 ? 0 : 1); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci dprintk("%s: status = 0x%02x\n", __func__, lock); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci return 0; 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci/* read DS3000 BER value */ 4598c2ecf20Sopenharmony_cistatic int ds3000_read_ber(struct dvb_frontend *fe, u32* ber) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci struct ds3000_state *state = fe->demodulator_priv; 4628c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 4638c2ecf20Sopenharmony_ci u8 data; 4648c2ecf20Sopenharmony_ci u32 ber_reading, lpdc_frames; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci dprintk("%s()\n", __func__); 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci switch (c->delivery_system) { 4698c2ecf20Sopenharmony_ci case SYS_DVBS: 4708c2ecf20Sopenharmony_ci /* set the number of bytes checked during 4718c2ecf20Sopenharmony_ci BER estimation */ 4728c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xf9, 0x04); 4738c2ecf20Sopenharmony_ci /* read BER estimation status */ 4748c2ecf20Sopenharmony_ci data = ds3000_readreg(state, 0xf8); 4758c2ecf20Sopenharmony_ci /* check if BER estimation is ready */ 4768c2ecf20Sopenharmony_ci if ((data & 0x10) == 0) { 4778c2ecf20Sopenharmony_ci /* this is the number of error bits, 4788c2ecf20Sopenharmony_ci to calculate the bit error rate 4798c2ecf20Sopenharmony_ci divide to 8388608 */ 4808c2ecf20Sopenharmony_ci *ber = (ds3000_readreg(state, 0xf7) << 8) | 4818c2ecf20Sopenharmony_ci ds3000_readreg(state, 0xf6); 4828c2ecf20Sopenharmony_ci /* start counting error bits */ 4838c2ecf20Sopenharmony_ci /* need to be set twice 4848c2ecf20Sopenharmony_ci otherwise it fails sometimes */ 4858c2ecf20Sopenharmony_ci data |= 0x10; 4868c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xf8, data); 4878c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xf8, data); 4888c2ecf20Sopenharmony_ci } else 4898c2ecf20Sopenharmony_ci /* used to indicate that BER estimation 4908c2ecf20Sopenharmony_ci is not ready, i.e. BER is unknown */ 4918c2ecf20Sopenharmony_ci *ber = 0xffffffff; 4928c2ecf20Sopenharmony_ci break; 4938c2ecf20Sopenharmony_ci case SYS_DVBS2: 4948c2ecf20Sopenharmony_ci /* read the number of LPDC decoded frames */ 4958c2ecf20Sopenharmony_ci lpdc_frames = (ds3000_readreg(state, 0xd7) << 16) | 4968c2ecf20Sopenharmony_ci (ds3000_readreg(state, 0xd6) << 8) | 4978c2ecf20Sopenharmony_ci ds3000_readreg(state, 0xd5); 4988c2ecf20Sopenharmony_ci /* read the number of packets with bad CRC */ 4998c2ecf20Sopenharmony_ci ber_reading = (ds3000_readreg(state, 0xf8) << 8) | 5008c2ecf20Sopenharmony_ci ds3000_readreg(state, 0xf7); 5018c2ecf20Sopenharmony_ci if (lpdc_frames > 750) { 5028c2ecf20Sopenharmony_ci /* clear LPDC frame counters */ 5038c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xd1, 0x01); 5048c2ecf20Sopenharmony_ci /* clear bad packets counter */ 5058c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xf9, 0x01); 5068c2ecf20Sopenharmony_ci /* enable bad packets counter */ 5078c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xf9, 0x00); 5088c2ecf20Sopenharmony_ci /* enable LPDC frame counters */ 5098c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xd1, 0x00); 5108c2ecf20Sopenharmony_ci *ber = ber_reading; 5118c2ecf20Sopenharmony_ci } else 5128c2ecf20Sopenharmony_ci /* used to indicate that BER estimation is not ready, 5138c2ecf20Sopenharmony_ci i.e. BER is unknown */ 5148c2ecf20Sopenharmony_ci *ber = 0xffffffff; 5158c2ecf20Sopenharmony_ci break; 5168c2ecf20Sopenharmony_ci default: 5178c2ecf20Sopenharmony_ci return -EINVAL; 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci return 0; 5218c2ecf20Sopenharmony_ci} 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_cistatic int ds3000_read_signal_strength(struct dvb_frontend *fe, 5248c2ecf20Sopenharmony_ci u16 *signal_strength) 5258c2ecf20Sopenharmony_ci{ 5268c2ecf20Sopenharmony_ci if (fe->ops.tuner_ops.get_rf_strength) 5278c2ecf20Sopenharmony_ci fe->ops.tuner_ops.get_rf_strength(fe, signal_strength); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci return 0; 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci/* calculate DS3000 snr value in dB */ 5338c2ecf20Sopenharmony_cistatic int ds3000_read_snr(struct dvb_frontend *fe, u16 *snr) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci struct ds3000_state *state = fe->demodulator_priv; 5368c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 5378c2ecf20Sopenharmony_ci u8 snr_reading, snr_value; 5388c2ecf20Sopenharmony_ci u32 dvbs2_signal_reading, dvbs2_noise_reading, tmp; 5398c2ecf20Sopenharmony_ci static const u16 dvbs_snr_tab[] = { /* 20 x Table (rounded up) */ 5408c2ecf20Sopenharmony_ci 0x0000, 0x1b13, 0x2aea, 0x3627, 0x3ede, 0x45fe, 0x4c03, 5418c2ecf20Sopenharmony_ci 0x513a, 0x55d4, 0x59f2, 0x5dab, 0x6111, 0x6431, 0x6717, 5428c2ecf20Sopenharmony_ci 0x69c9, 0x6c4e, 0x6eac, 0x70e8, 0x7304, 0x7505 5438c2ecf20Sopenharmony_ci }; 5448c2ecf20Sopenharmony_ci static const u16 dvbs2_snr_tab[] = { /* 80 x Table (rounded up) */ 5458c2ecf20Sopenharmony_ci 0x0000, 0x0bc2, 0x12a3, 0x1785, 0x1b4e, 0x1e65, 0x2103, 5468c2ecf20Sopenharmony_ci 0x2347, 0x2546, 0x2710, 0x28ae, 0x2a28, 0x2b83, 0x2cc5, 5478c2ecf20Sopenharmony_ci 0x2df1, 0x2f09, 0x3010, 0x3109, 0x31f4, 0x32d2, 0x33a6, 5488c2ecf20Sopenharmony_ci 0x3470, 0x3531, 0x35ea, 0x369b, 0x3746, 0x37ea, 0x3888, 5498c2ecf20Sopenharmony_ci 0x3920, 0x39b3, 0x3a42, 0x3acc, 0x3b51, 0x3bd3, 0x3c51, 5508c2ecf20Sopenharmony_ci 0x3ccb, 0x3d42, 0x3db6, 0x3e27, 0x3e95, 0x3f00, 0x3f68, 5518c2ecf20Sopenharmony_ci 0x3fcf, 0x4033, 0x4094, 0x40f4, 0x4151, 0x41ac, 0x4206, 5528c2ecf20Sopenharmony_ci 0x425e, 0x42b4, 0x4308, 0x435b, 0x43ac, 0x43fc, 0x444a, 5538c2ecf20Sopenharmony_ci 0x4497, 0x44e2, 0x452d, 0x4576, 0x45bd, 0x4604, 0x4649, 5548c2ecf20Sopenharmony_ci 0x468e, 0x46d1, 0x4713, 0x4755, 0x4795, 0x47d4, 0x4813, 5558c2ecf20Sopenharmony_ci 0x4851, 0x488d, 0x48c9, 0x4904, 0x493f, 0x4978, 0x49b1, 5568c2ecf20Sopenharmony_ci 0x49e9, 0x4a20, 0x4a57 5578c2ecf20Sopenharmony_ci }; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci dprintk("%s()\n", __func__); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci switch (c->delivery_system) { 5628c2ecf20Sopenharmony_ci case SYS_DVBS: 5638c2ecf20Sopenharmony_ci snr_reading = ds3000_readreg(state, 0xff); 5648c2ecf20Sopenharmony_ci snr_reading /= 8; 5658c2ecf20Sopenharmony_ci if (snr_reading == 0) 5668c2ecf20Sopenharmony_ci *snr = 0x0000; 5678c2ecf20Sopenharmony_ci else { 5688c2ecf20Sopenharmony_ci if (snr_reading > 20) 5698c2ecf20Sopenharmony_ci snr_reading = 20; 5708c2ecf20Sopenharmony_ci snr_value = dvbs_snr_tab[snr_reading - 1] * 10 / 23026; 5718c2ecf20Sopenharmony_ci /* cook the value to be suitable for szap-s2 5728c2ecf20Sopenharmony_ci human readable output */ 5738c2ecf20Sopenharmony_ci *snr = snr_value * 8 * 655; 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__, 5768c2ecf20Sopenharmony_ci snr_reading, *snr); 5778c2ecf20Sopenharmony_ci break; 5788c2ecf20Sopenharmony_ci case SYS_DVBS2: 5798c2ecf20Sopenharmony_ci dvbs2_noise_reading = (ds3000_readreg(state, 0x8c) & 0x3f) + 5808c2ecf20Sopenharmony_ci (ds3000_readreg(state, 0x8d) << 4); 5818c2ecf20Sopenharmony_ci dvbs2_signal_reading = ds3000_readreg(state, 0x8e); 5828c2ecf20Sopenharmony_ci tmp = dvbs2_signal_reading * dvbs2_signal_reading >> 1; 5838c2ecf20Sopenharmony_ci if (tmp == 0) { 5848c2ecf20Sopenharmony_ci *snr = 0x0000; 5858c2ecf20Sopenharmony_ci return 0; 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci if (dvbs2_noise_reading == 0) { 5888c2ecf20Sopenharmony_ci snr_value = 0x0013; 5898c2ecf20Sopenharmony_ci /* cook the value to be suitable for szap-s2 5908c2ecf20Sopenharmony_ci human readable output */ 5918c2ecf20Sopenharmony_ci *snr = 0xffff; 5928c2ecf20Sopenharmony_ci return 0; 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci if (tmp > dvbs2_noise_reading) { 5958c2ecf20Sopenharmony_ci snr_reading = tmp / dvbs2_noise_reading; 5968c2ecf20Sopenharmony_ci if (snr_reading > 80) 5978c2ecf20Sopenharmony_ci snr_reading = 80; 5988c2ecf20Sopenharmony_ci snr_value = dvbs2_snr_tab[snr_reading - 1] / 1000; 5998c2ecf20Sopenharmony_ci /* cook the value to be suitable for szap-s2 6008c2ecf20Sopenharmony_ci human readable output */ 6018c2ecf20Sopenharmony_ci *snr = snr_value * 5 * 655; 6028c2ecf20Sopenharmony_ci } else { 6038c2ecf20Sopenharmony_ci snr_reading = dvbs2_noise_reading / tmp; 6048c2ecf20Sopenharmony_ci if (snr_reading > 80) 6058c2ecf20Sopenharmony_ci snr_reading = 80; 6068c2ecf20Sopenharmony_ci *snr = -(dvbs2_snr_tab[snr_reading - 1] / 1000); 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__, 6098c2ecf20Sopenharmony_ci snr_reading, *snr); 6108c2ecf20Sopenharmony_ci break; 6118c2ecf20Sopenharmony_ci default: 6128c2ecf20Sopenharmony_ci return -EINVAL; 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci return 0; 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci/* read DS3000 uncorrected blocks */ 6198c2ecf20Sopenharmony_cistatic int ds3000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci struct ds3000_state *state = fe->demodulator_priv; 6228c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 6238c2ecf20Sopenharmony_ci u8 data; 6248c2ecf20Sopenharmony_ci u16 _ucblocks; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci dprintk("%s()\n", __func__); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci switch (c->delivery_system) { 6298c2ecf20Sopenharmony_ci case SYS_DVBS: 6308c2ecf20Sopenharmony_ci *ucblocks = (ds3000_readreg(state, 0xf5) << 8) | 6318c2ecf20Sopenharmony_ci ds3000_readreg(state, 0xf4); 6328c2ecf20Sopenharmony_ci data = ds3000_readreg(state, 0xf8); 6338c2ecf20Sopenharmony_ci /* clear packet counters */ 6348c2ecf20Sopenharmony_ci data &= ~0x20; 6358c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xf8, data); 6368c2ecf20Sopenharmony_ci /* enable packet counters */ 6378c2ecf20Sopenharmony_ci data |= 0x20; 6388c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xf8, data); 6398c2ecf20Sopenharmony_ci break; 6408c2ecf20Sopenharmony_ci case SYS_DVBS2: 6418c2ecf20Sopenharmony_ci _ucblocks = (ds3000_readreg(state, 0xe2) << 8) | 6428c2ecf20Sopenharmony_ci ds3000_readreg(state, 0xe1); 6438c2ecf20Sopenharmony_ci if (_ucblocks > state->prevUCBS2) 6448c2ecf20Sopenharmony_ci *ucblocks = _ucblocks - state->prevUCBS2; 6458c2ecf20Sopenharmony_ci else 6468c2ecf20Sopenharmony_ci *ucblocks = state->prevUCBS2 - _ucblocks; 6478c2ecf20Sopenharmony_ci state->prevUCBS2 = _ucblocks; 6488c2ecf20Sopenharmony_ci break; 6498c2ecf20Sopenharmony_ci default: 6508c2ecf20Sopenharmony_ci return -EINVAL; 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci return 0; 6548c2ecf20Sopenharmony_ci} 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_cistatic int ds3000_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone) 6578c2ecf20Sopenharmony_ci{ 6588c2ecf20Sopenharmony_ci struct ds3000_state *state = fe->demodulator_priv; 6598c2ecf20Sopenharmony_ci u8 data; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci dprintk("%s(%d)\n", __func__, tone); 6628c2ecf20Sopenharmony_ci if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) { 6638c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone); 6648c2ecf20Sopenharmony_ci return -EINVAL; 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci data = ds3000_readreg(state, 0xa2); 6688c2ecf20Sopenharmony_ci data &= ~0xc0; 6698c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xa2, data); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci switch (tone) { 6728c2ecf20Sopenharmony_ci case SEC_TONE_ON: 6738c2ecf20Sopenharmony_ci dprintk("%s: setting tone on\n", __func__); 6748c2ecf20Sopenharmony_ci data = ds3000_readreg(state, 0xa1); 6758c2ecf20Sopenharmony_ci data &= ~0x43; 6768c2ecf20Sopenharmony_ci data |= 0x04; 6778c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xa1, data); 6788c2ecf20Sopenharmony_ci break; 6798c2ecf20Sopenharmony_ci case SEC_TONE_OFF: 6808c2ecf20Sopenharmony_ci dprintk("%s: setting tone off\n", __func__); 6818c2ecf20Sopenharmony_ci data = ds3000_readreg(state, 0xa2); 6828c2ecf20Sopenharmony_ci data |= 0x80; 6838c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xa2, data); 6848c2ecf20Sopenharmony_ci break; 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci return 0; 6888c2ecf20Sopenharmony_ci} 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_cistatic int ds3000_send_diseqc_msg(struct dvb_frontend *fe, 6918c2ecf20Sopenharmony_ci struct dvb_diseqc_master_cmd *d) 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci struct ds3000_state *state = fe->demodulator_priv; 6948c2ecf20Sopenharmony_ci int i; 6958c2ecf20Sopenharmony_ci u8 data; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci /* Dump DiSEqC message */ 6988c2ecf20Sopenharmony_ci dprintk("%s(", __func__); 6998c2ecf20Sopenharmony_ci for (i = 0 ; i < d->msg_len;) { 7008c2ecf20Sopenharmony_ci dprintk("0x%02x", d->msg[i]); 7018c2ecf20Sopenharmony_ci if (++i < d->msg_len) 7028c2ecf20Sopenharmony_ci dprintk(", "); 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci /* enable DiSEqC message send pin */ 7068c2ecf20Sopenharmony_ci data = ds3000_readreg(state, 0xa2); 7078c2ecf20Sopenharmony_ci data &= ~0xc0; 7088c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xa2, data); 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci /* DiSEqC message */ 7118c2ecf20Sopenharmony_ci for (i = 0; i < d->msg_len; i++) 7128c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xa3 + i, d->msg[i]); 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci data = ds3000_readreg(state, 0xa1); 7158c2ecf20Sopenharmony_ci /* clear DiSEqC message length and status, 7168c2ecf20Sopenharmony_ci enable DiSEqC message send */ 7178c2ecf20Sopenharmony_ci data &= ~0xf8; 7188c2ecf20Sopenharmony_ci /* set DiSEqC mode, modulation active during 33 pulses, 7198c2ecf20Sopenharmony_ci set DiSEqC message length */ 7208c2ecf20Sopenharmony_ci data |= ((d->msg_len - 1) << 3) | 0x07; 7218c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xa1, data); 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci /* wait up to 150ms for DiSEqC transmission to complete */ 7248c2ecf20Sopenharmony_ci for (i = 0; i < 15; i++) { 7258c2ecf20Sopenharmony_ci data = ds3000_readreg(state, 0xa1); 7268c2ecf20Sopenharmony_ci if ((data & 0x40) == 0) 7278c2ecf20Sopenharmony_ci break; 7288c2ecf20Sopenharmony_ci msleep(10); 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci /* DiSEqC timeout after 150ms */ 7328c2ecf20Sopenharmony_ci if (i == 15) { 7338c2ecf20Sopenharmony_ci data = ds3000_readreg(state, 0xa1); 7348c2ecf20Sopenharmony_ci data &= ~0x80; 7358c2ecf20Sopenharmony_ci data |= 0x40; 7368c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xa1, data); 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci data = ds3000_readreg(state, 0xa2); 7398c2ecf20Sopenharmony_ci data &= ~0xc0; 7408c2ecf20Sopenharmony_ci data |= 0x80; 7418c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xa2, data); 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci return -ETIMEDOUT; 7448c2ecf20Sopenharmony_ci } 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci data = ds3000_readreg(state, 0xa2); 7478c2ecf20Sopenharmony_ci data &= ~0xc0; 7488c2ecf20Sopenharmony_ci data |= 0x80; 7498c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xa2, data); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci return 0; 7528c2ecf20Sopenharmony_ci} 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci/* Send DiSEqC burst */ 7558c2ecf20Sopenharmony_cistatic int ds3000_diseqc_send_burst(struct dvb_frontend *fe, 7568c2ecf20Sopenharmony_ci enum fe_sec_mini_cmd burst) 7578c2ecf20Sopenharmony_ci{ 7588c2ecf20Sopenharmony_ci struct ds3000_state *state = fe->demodulator_priv; 7598c2ecf20Sopenharmony_ci int i; 7608c2ecf20Sopenharmony_ci u8 data; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci dprintk("%s()\n", __func__); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci data = ds3000_readreg(state, 0xa2); 7658c2ecf20Sopenharmony_ci data &= ~0xc0; 7668c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xa2, data); 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci /* DiSEqC burst */ 7698c2ecf20Sopenharmony_ci if (burst == SEC_MINI_A) 7708c2ecf20Sopenharmony_ci /* Unmodulated tone burst */ 7718c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xa1, 0x02); 7728c2ecf20Sopenharmony_ci else if (burst == SEC_MINI_B) 7738c2ecf20Sopenharmony_ci /* Modulated tone burst */ 7748c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xa1, 0x01); 7758c2ecf20Sopenharmony_ci else 7768c2ecf20Sopenharmony_ci return -EINVAL; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci msleep(13); 7798c2ecf20Sopenharmony_ci for (i = 0; i < 5; i++) { 7808c2ecf20Sopenharmony_ci data = ds3000_readreg(state, 0xa1); 7818c2ecf20Sopenharmony_ci if ((data & 0x40) == 0) 7828c2ecf20Sopenharmony_ci break; 7838c2ecf20Sopenharmony_ci msleep(1); 7848c2ecf20Sopenharmony_ci } 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci if (i == 5) { 7878c2ecf20Sopenharmony_ci data = ds3000_readreg(state, 0xa1); 7888c2ecf20Sopenharmony_ci data &= ~0x80; 7898c2ecf20Sopenharmony_ci data |= 0x40; 7908c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xa1, data); 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci data = ds3000_readreg(state, 0xa2); 7938c2ecf20Sopenharmony_ci data &= ~0xc0; 7948c2ecf20Sopenharmony_ci data |= 0x80; 7958c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xa2, data); 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci return -ETIMEDOUT; 7988c2ecf20Sopenharmony_ci } 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci data = ds3000_readreg(state, 0xa2); 8018c2ecf20Sopenharmony_ci data &= ~0xc0; 8028c2ecf20Sopenharmony_ci data |= 0x80; 8038c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xa2, data); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci return 0; 8068c2ecf20Sopenharmony_ci} 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_cistatic void ds3000_release(struct dvb_frontend *fe) 8098c2ecf20Sopenharmony_ci{ 8108c2ecf20Sopenharmony_ci struct ds3000_state *state = fe->demodulator_priv; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci if (state->config->set_lock_led) 8138c2ecf20Sopenharmony_ci state->config->set_lock_led(fe, 0); 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 8168c2ecf20Sopenharmony_ci kfree(state); 8178c2ecf20Sopenharmony_ci} 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops ds3000_ops; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_cistruct dvb_frontend *ds3000_attach(const struct ds3000_config *config, 8228c2ecf20Sopenharmony_ci struct i2c_adapter *i2c) 8238c2ecf20Sopenharmony_ci{ 8248c2ecf20Sopenharmony_ci struct ds3000_state *state; 8258c2ecf20Sopenharmony_ci int ret; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci /* allocate memory for the internal state */ 8308c2ecf20Sopenharmony_ci state = kzalloc(sizeof(*state), GFP_KERNEL); 8318c2ecf20Sopenharmony_ci if (!state) 8328c2ecf20Sopenharmony_ci return NULL; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci state->config = config; 8358c2ecf20Sopenharmony_ci state->i2c = i2c; 8368c2ecf20Sopenharmony_ci state->prevUCBS2 = 0; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci /* check if the demod is present */ 8398c2ecf20Sopenharmony_ci ret = ds3000_readreg(state, 0x00) & 0xfe; 8408c2ecf20Sopenharmony_ci if (ret != 0xe0) { 8418c2ecf20Sopenharmony_ci kfree(state); 8428c2ecf20Sopenharmony_ci printk(KERN_ERR "Invalid probe, probably not a DS3000\n"); 8438c2ecf20Sopenharmony_ci return NULL; 8448c2ecf20Sopenharmony_ci } 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci printk(KERN_INFO "DS3000 chip version: %d.%d attached.\n", 8478c2ecf20Sopenharmony_ci ds3000_readreg(state, 0x02), 8488c2ecf20Sopenharmony_ci ds3000_readreg(state, 0x01)); 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci memcpy(&state->frontend.ops, &ds3000_ops, 8518c2ecf20Sopenharmony_ci sizeof(struct dvb_frontend_ops)); 8528c2ecf20Sopenharmony_ci state->frontend.demodulator_priv = state; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci /* 8558c2ecf20Sopenharmony_ci * Some devices like T480 starts with voltage on. Be sure 8568c2ecf20Sopenharmony_ci * to turn voltage off during init, as this can otherwise 8578c2ecf20Sopenharmony_ci * interfere with Unicable SCR systems. 8588c2ecf20Sopenharmony_ci */ 8598c2ecf20Sopenharmony_ci ds3000_set_voltage(&state->frontend, SEC_VOLTAGE_OFF); 8608c2ecf20Sopenharmony_ci return &state->frontend; 8618c2ecf20Sopenharmony_ci} 8628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ds3000_attach); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_cistatic int ds3000_set_carrier_offset(struct dvb_frontend *fe, 8658c2ecf20Sopenharmony_ci s32 carrier_offset_khz) 8668c2ecf20Sopenharmony_ci{ 8678c2ecf20Sopenharmony_ci struct ds3000_state *state = fe->demodulator_priv; 8688c2ecf20Sopenharmony_ci s32 tmp; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci tmp = carrier_offset_khz; 8718c2ecf20Sopenharmony_ci tmp *= 65536; 8728c2ecf20Sopenharmony_ci tmp = (2 * tmp + DS3000_SAMPLE_RATE) / (2 * DS3000_SAMPLE_RATE); 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci if (tmp < 0) 8758c2ecf20Sopenharmony_ci tmp += 65536; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci ds3000_writereg(state, 0x5f, tmp >> 8); 8788c2ecf20Sopenharmony_ci ds3000_writereg(state, 0x5e, tmp & 0xff); 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci return 0; 8818c2ecf20Sopenharmony_ci} 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_cistatic int ds3000_set_frontend(struct dvb_frontend *fe) 8848c2ecf20Sopenharmony_ci{ 8858c2ecf20Sopenharmony_ci struct ds3000_state *state = fe->demodulator_priv; 8868c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci int i; 8898c2ecf20Sopenharmony_ci enum fe_status status; 8908c2ecf20Sopenharmony_ci s32 offset_khz; 8918c2ecf20Sopenharmony_ci u32 frequency; 8928c2ecf20Sopenharmony_ci u16 value; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci dprintk("%s() ", __func__); 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci if (state->config->set_ts_params) 8978c2ecf20Sopenharmony_ci state->config->set_ts_params(fe, 0); 8988c2ecf20Sopenharmony_ci /* Tune */ 8998c2ecf20Sopenharmony_ci if (fe->ops.tuner_ops.set_params) 9008c2ecf20Sopenharmony_ci fe->ops.tuner_ops.set_params(fe); 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci /* ds3000 global reset */ 9038c2ecf20Sopenharmony_ci ds3000_writereg(state, 0x07, 0x80); 9048c2ecf20Sopenharmony_ci ds3000_writereg(state, 0x07, 0x00); 9058c2ecf20Sopenharmony_ci /* ds3000 built-in uC reset */ 9068c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xb2, 0x01); 9078c2ecf20Sopenharmony_ci /* ds3000 software reset */ 9088c2ecf20Sopenharmony_ci ds3000_writereg(state, 0x00, 0x01); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci switch (c->delivery_system) { 9118c2ecf20Sopenharmony_ci case SYS_DVBS: 9128c2ecf20Sopenharmony_ci /* initialise the demod in DVB-S mode */ 9138c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(ds3000_dvbs_init_tab); i += 2) 9148c2ecf20Sopenharmony_ci ds3000_writereg(state, 9158c2ecf20Sopenharmony_ci ds3000_dvbs_init_tab[i], 9168c2ecf20Sopenharmony_ci ds3000_dvbs_init_tab[i + 1]); 9178c2ecf20Sopenharmony_ci value = ds3000_readreg(state, 0xfe); 9188c2ecf20Sopenharmony_ci value &= 0xc0; 9198c2ecf20Sopenharmony_ci value |= 0x1b; 9208c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xfe, value); 9218c2ecf20Sopenharmony_ci break; 9228c2ecf20Sopenharmony_ci case SYS_DVBS2: 9238c2ecf20Sopenharmony_ci /* initialise the demod in DVB-S2 mode */ 9248c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(ds3000_dvbs2_init_tab); i += 2) 9258c2ecf20Sopenharmony_ci ds3000_writereg(state, 9268c2ecf20Sopenharmony_ci ds3000_dvbs2_init_tab[i], 9278c2ecf20Sopenharmony_ci ds3000_dvbs2_init_tab[i + 1]); 9288c2ecf20Sopenharmony_ci if (c->symbol_rate >= 30000000) 9298c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xfe, 0x54); 9308c2ecf20Sopenharmony_ci else 9318c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xfe, 0x98); 9328c2ecf20Sopenharmony_ci break; 9338c2ecf20Sopenharmony_ci default: 9348c2ecf20Sopenharmony_ci return -EINVAL; 9358c2ecf20Sopenharmony_ci } 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci /* enable 27MHz clock output */ 9388c2ecf20Sopenharmony_ci ds3000_writereg(state, 0x29, 0x80); 9398c2ecf20Sopenharmony_ci /* enable ac coupling */ 9408c2ecf20Sopenharmony_ci ds3000_writereg(state, 0x25, 0x8a); 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci if ((c->symbol_rate < ds3000_ops.info.symbol_rate_min) || 9438c2ecf20Sopenharmony_ci (c->symbol_rate > ds3000_ops.info.symbol_rate_max)) { 9448c2ecf20Sopenharmony_ci dprintk("%s() symbol_rate %u out of range (%u ... %u)\n", 9458c2ecf20Sopenharmony_ci __func__, c->symbol_rate, 9468c2ecf20Sopenharmony_ci ds3000_ops.info.symbol_rate_min, 9478c2ecf20Sopenharmony_ci ds3000_ops.info.symbol_rate_max); 9488c2ecf20Sopenharmony_ci return -EINVAL; 9498c2ecf20Sopenharmony_ci } 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci /* enhance symbol rate performance */ 9528c2ecf20Sopenharmony_ci if ((c->symbol_rate / 1000) <= 5000) { 9538c2ecf20Sopenharmony_ci value = 29777 / (c->symbol_rate / 1000) + 1; 9548c2ecf20Sopenharmony_ci if (value % 2 != 0) 9558c2ecf20Sopenharmony_ci value++; 9568c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xc3, 0x0d); 9578c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xc8, value); 9588c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xc4, 0x10); 9598c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xc7, 0x0e); 9608c2ecf20Sopenharmony_ci } else if ((c->symbol_rate / 1000) <= 10000) { 9618c2ecf20Sopenharmony_ci value = 92166 / (c->symbol_rate / 1000) + 1; 9628c2ecf20Sopenharmony_ci if (value % 2 != 0) 9638c2ecf20Sopenharmony_ci value++; 9648c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xc3, 0x07); 9658c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xc8, value); 9668c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xc4, 0x09); 9678c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xc7, 0x12); 9688c2ecf20Sopenharmony_ci } else if ((c->symbol_rate / 1000) <= 20000) { 9698c2ecf20Sopenharmony_ci value = 64516 / (c->symbol_rate / 1000) + 1; 9708c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xc3, value); 9718c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xc8, 0x0e); 9728c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xc4, 0x07); 9738c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xc7, 0x18); 9748c2ecf20Sopenharmony_ci } else { 9758c2ecf20Sopenharmony_ci value = 129032 / (c->symbol_rate / 1000) + 1; 9768c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xc3, value); 9778c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xc8, 0x0a); 9788c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xc4, 0x05); 9798c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xc7, 0x24); 9808c2ecf20Sopenharmony_ci } 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci /* normalized symbol rate rounded to the closest integer */ 9838c2ecf20Sopenharmony_ci value = (((c->symbol_rate / 1000) << 16) + 9848c2ecf20Sopenharmony_ci (DS3000_SAMPLE_RATE / 2)) / DS3000_SAMPLE_RATE; 9858c2ecf20Sopenharmony_ci ds3000_writereg(state, 0x61, value & 0x00ff); 9868c2ecf20Sopenharmony_ci ds3000_writereg(state, 0x62, (value & 0xff00) >> 8); 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci /* co-channel interference cancellation disabled */ 9898c2ecf20Sopenharmony_ci ds3000_writereg(state, 0x56, 0x00); 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci /* equalizer disabled */ 9928c2ecf20Sopenharmony_ci ds3000_writereg(state, 0x76, 0x00); 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci /*ds3000_writereg(state, 0x08, 0x03); 9958c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xfd, 0x22); 9968c2ecf20Sopenharmony_ci ds3000_writereg(state, 0x08, 0x07); 9978c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xfd, 0x42); 9988c2ecf20Sopenharmony_ci ds3000_writereg(state, 0x08, 0x07);*/ 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci if (state->config->ci_mode) { 10018c2ecf20Sopenharmony_ci switch (c->delivery_system) { 10028c2ecf20Sopenharmony_ci case SYS_DVBS: 10038c2ecf20Sopenharmony_ci default: 10048c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xfd, 0x80); 10058c2ecf20Sopenharmony_ci break; 10068c2ecf20Sopenharmony_ci case SYS_DVBS2: 10078c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xfd, 0x01); 10088c2ecf20Sopenharmony_ci break; 10098c2ecf20Sopenharmony_ci } 10108c2ecf20Sopenharmony_ci } 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci /* ds3000 out of software reset */ 10138c2ecf20Sopenharmony_ci ds3000_writereg(state, 0x00, 0x00); 10148c2ecf20Sopenharmony_ci /* start ds3000 built-in uC */ 10158c2ecf20Sopenharmony_ci ds3000_writereg(state, 0xb2, 0x00); 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci if (fe->ops.tuner_ops.get_frequency) { 10188c2ecf20Sopenharmony_ci fe->ops.tuner_ops.get_frequency(fe, &frequency); 10198c2ecf20Sopenharmony_ci offset_khz = frequency - c->frequency; 10208c2ecf20Sopenharmony_ci ds3000_set_carrier_offset(fe, offset_khz); 10218c2ecf20Sopenharmony_ci } 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci for (i = 0; i < 30 ; i++) { 10248c2ecf20Sopenharmony_ci ds3000_read_status(fe, &status); 10258c2ecf20Sopenharmony_ci if (status & FE_HAS_LOCK) 10268c2ecf20Sopenharmony_ci break; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci msleep(10); 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci return 0; 10328c2ecf20Sopenharmony_ci} 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_cistatic int ds3000_tune(struct dvb_frontend *fe, 10358c2ecf20Sopenharmony_ci bool re_tune, 10368c2ecf20Sopenharmony_ci unsigned int mode_flags, 10378c2ecf20Sopenharmony_ci unsigned int *delay, 10388c2ecf20Sopenharmony_ci enum fe_status *status) 10398c2ecf20Sopenharmony_ci{ 10408c2ecf20Sopenharmony_ci if (re_tune) { 10418c2ecf20Sopenharmony_ci int ret = ds3000_set_frontend(fe); 10428c2ecf20Sopenharmony_ci if (ret) 10438c2ecf20Sopenharmony_ci return ret; 10448c2ecf20Sopenharmony_ci } 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci *delay = HZ / 5; 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci return ds3000_read_status(fe, status); 10498c2ecf20Sopenharmony_ci} 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_cistatic enum dvbfe_algo ds3000_get_algo(struct dvb_frontend *fe) 10528c2ecf20Sopenharmony_ci{ 10538c2ecf20Sopenharmony_ci struct ds3000_state *state = fe->demodulator_priv; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci if (state->config->set_lock_led) 10568c2ecf20Sopenharmony_ci state->config->set_lock_led(fe, 0); 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci dprintk("%s()\n", __func__); 10598c2ecf20Sopenharmony_ci return DVBFE_ALGO_HW; 10608c2ecf20Sopenharmony_ci} 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci/* 10638c2ecf20Sopenharmony_ci * Initialise or wake up device 10648c2ecf20Sopenharmony_ci * 10658c2ecf20Sopenharmony_ci * Power config will reset and load initial firmware if required 10668c2ecf20Sopenharmony_ci */ 10678c2ecf20Sopenharmony_cistatic int ds3000_initfe(struct dvb_frontend *fe) 10688c2ecf20Sopenharmony_ci{ 10698c2ecf20Sopenharmony_ci struct ds3000_state *state = fe->demodulator_priv; 10708c2ecf20Sopenharmony_ci int ret; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci dprintk("%s()\n", __func__); 10738c2ecf20Sopenharmony_ci /* hard reset */ 10748c2ecf20Sopenharmony_ci ds3000_writereg(state, 0x08, 0x01 | ds3000_readreg(state, 0x08)); 10758c2ecf20Sopenharmony_ci msleep(1); 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci /* Load the firmware if required */ 10788c2ecf20Sopenharmony_ci ret = ds3000_firmware_ondemand(fe); 10798c2ecf20Sopenharmony_ci if (ret != 0) { 10808c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Unable initialize firmware\n", __func__); 10818c2ecf20Sopenharmony_ci return ret; 10828c2ecf20Sopenharmony_ci } 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci return 0; 10858c2ecf20Sopenharmony_ci} 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops ds3000_ops = { 10888c2ecf20Sopenharmony_ci .delsys = { SYS_DVBS, SYS_DVBS2 }, 10898c2ecf20Sopenharmony_ci .info = { 10908c2ecf20Sopenharmony_ci .name = "Montage Technology DS3000", 10918c2ecf20Sopenharmony_ci .frequency_min_hz = 950 * MHz, 10928c2ecf20Sopenharmony_ci .frequency_max_hz = 2150 * MHz, 10938c2ecf20Sopenharmony_ci .frequency_stepsize_hz = 1011 * kHz, 10948c2ecf20Sopenharmony_ci .frequency_tolerance_hz = 5 * MHz, 10958c2ecf20Sopenharmony_ci .symbol_rate_min = 1000000, 10968c2ecf20Sopenharmony_ci .symbol_rate_max = 45000000, 10978c2ecf20Sopenharmony_ci .caps = FE_CAN_INVERSION_AUTO | 10988c2ecf20Sopenharmony_ci FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 10998c2ecf20Sopenharmony_ci FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | 11008c2ecf20Sopenharmony_ci FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | 11018c2ecf20Sopenharmony_ci FE_CAN_2G_MODULATION | 11028c2ecf20Sopenharmony_ci FE_CAN_QPSK | FE_CAN_RECOVER 11038c2ecf20Sopenharmony_ci }, 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci .release = ds3000_release, 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci .init = ds3000_initfe, 11088c2ecf20Sopenharmony_ci .i2c_gate_ctrl = ds3000_i2c_gate_ctrl, 11098c2ecf20Sopenharmony_ci .read_status = ds3000_read_status, 11108c2ecf20Sopenharmony_ci .read_ber = ds3000_read_ber, 11118c2ecf20Sopenharmony_ci .read_signal_strength = ds3000_read_signal_strength, 11128c2ecf20Sopenharmony_ci .read_snr = ds3000_read_snr, 11138c2ecf20Sopenharmony_ci .read_ucblocks = ds3000_read_ucblocks, 11148c2ecf20Sopenharmony_ci .set_voltage = ds3000_set_voltage, 11158c2ecf20Sopenharmony_ci .set_tone = ds3000_set_tone, 11168c2ecf20Sopenharmony_ci .diseqc_send_master_cmd = ds3000_send_diseqc_msg, 11178c2ecf20Sopenharmony_ci .diseqc_send_burst = ds3000_diseqc_send_burst, 11188c2ecf20Sopenharmony_ci .get_frontend_algo = ds3000_get_algo, 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci .set_frontend = ds3000_set_frontend, 11218c2ecf20Sopenharmony_ci .tune = ds3000_tune, 11228c2ecf20Sopenharmony_ci}; 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_cimodule_param(debug, int, 0644); 11258c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("DVB Frontend module for Montage Technology DS3000 hardware"); 11288c2ecf20Sopenharmony_ciMODULE_AUTHOR("Konstantin Dimitrov <kosio.dimitrov@gmail.com>"); 11298c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 11308c2ecf20Sopenharmony_ciMODULE_FIRMWARE(DS3000_DEFAULT_FIRMWARE); 1131