18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci Copyright (C) 2008 Sirius International (Hong Kong) Limited 68c2ecf20Sopenharmony_ci Timothy Lee <timothy.lee@siriushk.com> 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci*/ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/string.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h> 178c2ecf20Sopenharmony_ci#include "lgs8gl5.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define REG_RESET 0x02 218c2ecf20Sopenharmony_ci#define REG_RESET_OFF 0x01 228c2ecf20Sopenharmony_ci#define REG_03 0x03 238c2ecf20Sopenharmony_ci#define REG_04 0x04 248c2ecf20Sopenharmony_ci#define REG_07 0x07 258c2ecf20Sopenharmony_ci#define REG_09 0x09 268c2ecf20Sopenharmony_ci#define REG_0A 0x0a 278c2ecf20Sopenharmony_ci#define REG_0B 0x0b 288c2ecf20Sopenharmony_ci#define REG_0C 0x0c 298c2ecf20Sopenharmony_ci#define REG_37 0x37 308c2ecf20Sopenharmony_ci#define REG_STRENGTH 0x4b 318c2ecf20Sopenharmony_ci#define REG_STRENGTH_MASK 0x7f 328c2ecf20Sopenharmony_ci#define REG_STRENGTH_CARRIER 0x80 338c2ecf20Sopenharmony_ci#define REG_INVERSION 0x7c 348c2ecf20Sopenharmony_ci#define REG_INVERSION_ON 0x80 358c2ecf20Sopenharmony_ci#define REG_7D 0x7d 368c2ecf20Sopenharmony_ci#define REG_7E 0x7e 378c2ecf20Sopenharmony_ci#define REG_A2 0xa2 388c2ecf20Sopenharmony_ci#define REG_STATUS 0xa4 398c2ecf20Sopenharmony_ci#define REG_STATUS_SYNC 0x04 408c2ecf20Sopenharmony_ci#define REG_STATUS_LOCK 0x01 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistruct lgs8gl5_state { 448c2ecf20Sopenharmony_ci struct i2c_adapter *i2c; 458c2ecf20Sopenharmony_ci const struct lgs8gl5_config *config; 468c2ecf20Sopenharmony_ci struct dvb_frontend frontend; 478c2ecf20Sopenharmony_ci}; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic int debug; 518c2ecf20Sopenharmony_ci#define dprintk(args...) \ 528c2ecf20Sopenharmony_ci do { \ 538c2ecf20Sopenharmony_ci if (debug) \ 548c2ecf20Sopenharmony_ci printk(KERN_DEBUG "lgs8gl5: " args); \ 558c2ecf20Sopenharmony_ci } while (0) 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* Writes into demod's register */ 598c2ecf20Sopenharmony_cistatic int 608c2ecf20Sopenharmony_cilgs8gl5_write_reg(struct lgs8gl5_state *state, u8 reg, u8 data) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci int ret; 638c2ecf20Sopenharmony_ci u8 buf[] = {reg, data}; 648c2ecf20Sopenharmony_ci struct i2c_msg msg = { 658c2ecf20Sopenharmony_ci .addr = state->config->demod_address, 668c2ecf20Sopenharmony_ci .flags = 0, 678c2ecf20Sopenharmony_ci .buf = buf, 688c2ecf20Sopenharmony_ci .len = 2 698c2ecf20Sopenharmony_ci }; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci ret = i2c_transfer(state->i2c, &msg, 1); 728c2ecf20Sopenharmony_ci if (ret != 1) 738c2ecf20Sopenharmony_ci dprintk("%s: error (reg=0x%02x, val=0x%02x, ret=%i)\n", 748c2ecf20Sopenharmony_ci __func__, reg, data, ret); 758c2ecf20Sopenharmony_ci return (ret != 1) ? -1 : 0; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/* Reads from demod's register */ 808c2ecf20Sopenharmony_cistatic int 818c2ecf20Sopenharmony_cilgs8gl5_read_reg(struct lgs8gl5_state *state, u8 reg) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci int ret; 848c2ecf20Sopenharmony_ci u8 b0[] = {reg}; 858c2ecf20Sopenharmony_ci u8 b1[] = {0}; 868c2ecf20Sopenharmony_ci struct i2c_msg msg[2] = { 878c2ecf20Sopenharmony_ci { 888c2ecf20Sopenharmony_ci .addr = state->config->demod_address, 898c2ecf20Sopenharmony_ci .flags = 0, 908c2ecf20Sopenharmony_ci .buf = b0, 918c2ecf20Sopenharmony_ci .len = 1 928c2ecf20Sopenharmony_ci }, 938c2ecf20Sopenharmony_ci { 948c2ecf20Sopenharmony_ci .addr = state->config->demod_address, 958c2ecf20Sopenharmony_ci .flags = I2C_M_RD, 968c2ecf20Sopenharmony_ci .buf = b1, 978c2ecf20Sopenharmony_ci .len = 1 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci }; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci ret = i2c_transfer(state->i2c, msg, 2); 1028c2ecf20Sopenharmony_ci if (ret != 2) 1038c2ecf20Sopenharmony_ci return -EIO; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci return b1[0]; 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic int 1108c2ecf20Sopenharmony_cilgs8gl5_update_reg(struct lgs8gl5_state *state, u8 reg, u8 data) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci lgs8gl5_read_reg(state, reg); 1138c2ecf20Sopenharmony_ci lgs8gl5_write_reg(state, reg, data); 1148c2ecf20Sopenharmony_ci return 0; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/* Writes into alternate device's register */ 1198c2ecf20Sopenharmony_ci/* TODO: Find out what that device is for! */ 1208c2ecf20Sopenharmony_cistatic int 1218c2ecf20Sopenharmony_cilgs8gl5_update_alt_reg(struct lgs8gl5_state *state, u8 reg, u8 data) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci int ret; 1248c2ecf20Sopenharmony_ci u8 b0[] = {reg}; 1258c2ecf20Sopenharmony_ci u8 b1[] = {0}; 1268c2ecf20Sopenharmony_ci u8 b2[] = {reg, data}; 1278c2ecf20Sopenharmony_ci struct i2c_msg msg[3] = { 1288c2ecf20Sopenharmony_ci { 1298c2ecf20Sopenharmony_ci .addr = state->config->demod_address + 2, 1308c2ecf20Sopenharmony_ci .flags = 0, 1318c2ecf20Sopenharmony_ci .buf = b0, 1328c2ecf20Sopenharmony_ci .len = 1 1338c2ecf20Sopenharmony_ci }, 1348c2ecf20Sopenharmony_ci { 1358c2ecf20Sopenharmony_ci .addr = state->config->demod_address + 2, 1368c2ecf20Sopenharmony_ci .flags = I2C_M_RD, 1378c2ecf20Sopenharmony_ci .buf = b1, 1388c2ecf20Sopenharmony_ci .len = 1 1398c2ecf20Sopenharmony_ci }, 1408c2ecf20Sopenharmony_ci { 1418c2ecf20Sopenharmony_ci .addr = state->config->demod_address + 2, 1428c2ecf20Sopenharmony_ci .flags = 0, 1438c2ecf20Sopenharmony_ci .buf = b2, 1448c2ecf20Sopenharmony_ci .len = 2 1458c2ecf20Sopenharmony_ci }, 1468c2ecf20Sopenharmony_ci }; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci ret = i2c_transfer(state->i2c, msg, 3); 1498c2ecf20Sopenharmony_ci return (ret != 3) ? -1 : 0; 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic void 1548c2ecf20Sopenharmony_cilgs8gl5_soft_reset(struct lgs8gl5_state *state) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci u8 val; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci val = lgs8gl5_read_reg(state, REG_RESET); 1618c2ecf20Sopenharmony_ci lgs8gl5_write_reg(state, REG_RESET, val & ~REG_RESET_OFF); 1628c2ecf20Sopenharmony_ci lgs8gl5_write_reg(state, REG_RESET, val | REG_RESET_OFF); 1638c2ecf20Sopenharmony_ci msleep(5); 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci/* Starts demodulation */ 1688c2ecf20Sopenharmony_cistatic void 1698c2ecf20Sopenharmony_cilgs8gl5_start_demod(struct lgs8gl5_state *state) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci u8 val; 1728c2ecf20Sopenharmony_ci int n; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci lgs8gl5_update_alt_reg(state, 0xc2, 0x28); 1778c2ecf20Sopenharmony_ci lgs8gl5_soft_reset(state); 1788c2ecf20Sopenharmony_ci lgs8gl5_update_reg(state, REG_07, 0x10); 1798c2ecf20Sopenharmony_ci lgs8gl5_update_reg(state, REG_07, 0x10); 1808c2ecf20Sopenharmony_ci lgs8gl5_write_reg(state, REG_09, 0x0e); 1818c2ecf20Sopenharmony_ci lgs8gl5_write_reg(state, REG_0A, 0xe5); 1828c2ecf20Sopenharmony_ci lgs8gl5_write_reg(state, REG_0B, 0x35); 1838c2ecf20Sopenharmony_ci lgs8gl5_write_reg(state, REG_0C, 0x30); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci lgs8gl5_update_reg(state, REG_03, 0x00); 1868c2ecf20Sopenharmony_ci lgs8gl5_update_reg(state, REG_7E, 0x01); 1878c2ecf20Sopenharmony_ci lgs8gl5_update_alt_reg(state, 0xc5, 0x00); 1888c2ecf20Sopenharmony_ci lgs8gl5_update_reg(state, REG_04, 0x02); 1898c2ecf20Sopenharmony_ci lgs8gl5_update_reg(state, REG_37, 0x01); 1908c2ecf20Sopenharmony_ci lgs8gl5_soft_reset(state); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci /* Wait for carrier */ 1938c2ecf20Sopenharmony_ci for (n = 0; n < 10; n++) { 1948c2ecf20Sopenharmony_ci val = lgs8gl5_read_reg(state, REG_STRENGTH); 1958c2ecf20Sopenharmony_ci dprintk("Wait for carrier[%d] 0x%02X\n", n, val); 1968c2ecf20Sopenharmony_ci if (val & REG_STRENGTH_CARRIER) 1978c2ecf20Sopenharmony_ci break; 1988c2ecf20Sopenharmony_ci msleep(4); 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci if (!(val & REG_STRENGTH_CARRIER)) 2018c2ecf20Sopenharmony_ci return; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci /* Wait for lock */ 2048c2ecf20Sopenharmony_ci for (n = 0; n < 20; n++) { 2058c2ecf20Sopenharmony_ci val = lgs8gl5_read_reg(state, REG_STATUS); 2068c2ecf20Sopenharmony_ci dprintk("Wait for lock[%d] 0x%02X\n", n, val); 2078c2ecf20Sopenharmony_ci if (val & REG_STATUS_LOCK) 2088c2ecf20Sopenharmony_ci break; 2098c2ecf20Sopenharmony_ci msleep(12); 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci if (!(val & REG_STATUS_LOCK)) 2128c2ecf20Sopenharmony_ci return; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci lgs8gl5_write_reg(state, REG_7D, lgs8gl5_read_reg(state, REG_A2)); 2158c2ecf20Sopenharmony_ci lgs8gl5_soft_reset(state); 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic int 2208c2ecf20Sopenharmony_cilgs8gl5_init(struct dvb_frontend *fe) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci struct lgs8gl5_state *state = fe->demodulator_priv; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci lgs8gl5_update_alt_reg(state, 0xc2, 0x28); 2278c2ecf20Sopenharmony_ci lgs8gl5_soft_reset(state); 2288c2ecf20Sopenharmony_ci lgs8gl5_update_reg(state, REG_07, 0x10); 2298c2ecf20Sopenharmony_ci lgs8gl5_update_reg(state, REG_07, 0x10); 2308c2ecf20Sopenharmony_ci lgs8gl5_write_reg(state, REG_09, 0x0e); 2318c2ecf20Sopenharmony_ci lgs8gl5_write_reg(state, REG_0A, 0xe5); 2328c2ecf20Sopenharmony_ci lgs8gl5_write_reg(state, REG_0B, 0x35); 2338c2ecf20Sopenharmony_ci lgs8gl5_write_reg(state, REG_0C, 0x30); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci return 0; 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic int 2408c2ecf20Sopenharmony_cilgs8gl5_read_status(struct dvb_frontend *fe, enum fe_status *status) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci struct lgs8gl5_state *state = fe->demodulator_priv; 2438c2ecf20Sopenharmony_ci u8 level = lgs8gl5_read_reg(state, REG_STRENGTH); 2448c2ecf20Sopenharmony_ci u8 flags = lgs8gl5_read_reg(state, REG_STATUS); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci *status = 0; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if ((level & REG_STRENGTH_MASK) > 0) 2498c2ecf20Sopenharmony_ci *status |= FE_HAS_SIGNAL; 2508c2ecf20Sopenharmony_ci if (level & REG_STRENGTH_CARRIER) 2518c2ecf20Sopenharmony_ci *status |= FE_HAS_CARRIER; 2528c2ecf20Sopenharmony_ci if (flags & REG_STATUS_SYNC) 2538c2ecf20Sopenharmony_ci *status |= FE_HAS_SYNC; 2548c2ecf20Sopenharmony_ci if (flags & REG_STATUS_LOCK) 2558c2ecf20Sopenharmony_ci *status |= FE_HAS_LOCK; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci return 0; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic int 2628c2ecf20Sopenharmony_cilgs8gl5_read_ber(struct dvb_frontend *fe, u32 *ber) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci *ber = 0; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci return 0; 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic int 2718c2ecf20Sopenharmony_cilgs8gl5_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci struct lgs8gl5_state *state = fe->demodulator_priv; 2748c2ecf20Sopenharmony_ci u8 level = lgs8gl5_read_reg(state, REG_STRENGTH); 2758c2ecf20Sopenharmony_ci *signal_strength = (level & REG_STRENGTH_MASK) << 8; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci return 0; 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic int 2828c2ecf20Sopenharmony_cilgs8gl5_read_snr(struct dvb_frontend *fe, u16 *snr) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci struct lgs8gl5_state *state = fe->demodulator_priv; 2858c2ecf20Sopenharmony_ci u8 level = lgs8gl5_read_reg(state, REG_STRENGTH); 2868c2ecf20Sopenharmony_ci *snr = (level & REG_STRENGTH_MASK) << 8; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci return 0; 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic int 2938c2ecf20Sopenharmony_cilgs8gl5_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci *ucblocks = 0; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci return 0; 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic int 3028c2ecf20Sopenharmony_cilgs8gl5_set_frontend(struct dvb_frontend *fe) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci struct dtv_frontend_properties *p = &fe->dtv_property_cache; 3058c2ecf20Sopenharmony_ci struct lgs8gl5_state *state = fe->demodulator_priv; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci if (p->bandwidth_hz != 8000000) 3108c2ecf20Sopenharmony_ci return -EINVAL; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci if (fe->ops.tuner_ops.set_params) { 3138c2ecf20Sopenharmony_ci fe->ops.tuner_ops.set_params(fe); 3148c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 3158c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci /* lgs8gl5_set_inversion(state, p->inversion); */ 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci lgs8gl5_start_demod(state); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci return 0; 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic int 3278c2ecf20Sopenharmony_cilgs8gl5_get_frontend(struct dvb_frontend *fe, 3288c2ecf20Sopenharmony_ci struct dtv_frontend_properties *p) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci struct lgs8gl5_state *state = fe->demodulator_priv; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci u8 inv = lgs8gl5_read_reg(state, REG_INVERSION); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci p->inversion = (inv & REG_INVERSION_ON) ? INVERSION_ON : INVERSION_OFF; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci p->code_rate_HP = FEC_1_2; 3378c2ecf20Sopenharmony_ci p->code_rate_LP = FEC_7_8; 3388c2ecf20Sopenharmony_ci p->guard_interval = GUARD_INTERVAL_1_32; 3398c2ecf20Sopenharmony_ci p->transmission_mode = TRANSMISSION_MODE_2K; 3408c2ecf20Sopenharmony_ci p->modulation = QAM_64; 3418c2ecf20Sopenharmony_ci p->hierarchy = HIERARCHY_NONE; 3428c2ecf20Sopenharmony_ci p->bandwidth_hz = 8000000; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci return 0; 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic int 3498c2ecf20Sopenharmony_cilgs8gl5_get_tune_settings(struct dvb_frontend *fe, 3508c2ecf20Sopenharmony_ci struct dvb_frontend_tune_settings *fesettings) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci fesettings->min_delay_ms = 240; 3538c2ecf20Sopenharmony_ci fesettings->step_size = 0; 3548c2ecf20Sopenharmony_ci fesettings->max_drift = 0; 3558c2ecf20Sopenharmony_ci return 0; 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic void 3608c2ecf20Sopenharmony_cilgs8gl5_release(struct dvb_frontend *fe) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci struct lgs8gl5_state *state = fe->demodulator_priv; 3638c2ecf20Sopenharmony_ci kfree(state); 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops lgs8gl5_ops; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistruct dvb_frontend* 3718c2ecf20Sopenharmony_cilgs8gl5_attach(const struct lgs8gl5_config *config, struct i2c_adapter *i2c) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci struct lgs8gl5_state *state = NULL; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci /* Allocate memory for the internal state */ 3788c2ecf20Sopenharmony_ci state = kzalloc(sizeof(struct lgs8gl5_state), GFP_KERNEL); 3798c2ecf20Sopenharmony_ci if (state == NULL) 3808c2ecf20Sopenharmony_ci goto error; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci /* Setup the state */ 3838c2ecf20Sopenharmony_ci state->config = config; 3848c2ecf20Sopenharmony_ci state->i2c = i2c; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci /* Check if the demod is there */ 3878c2ecf20Sopenharmony_ci if (lgs8gl5_read_reg(state, REG_RESET) < 0) 3888c2ecf20Sopenharmony_ci goto error; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci /* Create dvb_frontend */ 3918c2ecf20Sopenharmony_ci memcpy(&state->frontend.ops, &lgs8gl5_ops, 3928c2ecf20Sopenharmony_ci sizeof(struct dvb_frontend_ops)); 3938c2ecf20Sopenharmony_ci state->frontend.demodulator_priv = state; 3948c2ecf20Sopenharmony_ci return &state->frontend; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_cierror: 3978c2ecf20Sopenharmony_ci kfree(state); 3988c2ecf20Sopenharmony_ci return NULL; 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ciEXPORT_SYMBOL(lgs8gl5_attach); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops lgs8gl5_ops = { 4048c2ecf20Sopenharmony_ci .delsys = { SYS_DTMB }, 4058c2ecf20Sopenharmony_ci .info = { 4068c2ecf20Sopenharmony_ci .name = "Legend Silicon LGS-8GL5 DMB-TH", 4078c2ecf20Sopenharmony_ci .frequency_min_hz = 474 * MHz, 4088c2ecf20Sopenharmony_ci .frequency_max_hz = 858 * MHz, 4098c2ecf20Sopenharmony_ci .frequency_stepsize_hz = 10 * kHz, 4108c2ecf20Sopenharmony_ci .caps = FE_CAN_FEC_AUTO | 4118c2ecf20Sopenharmony_ci FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 | 4128c2ecf20Sopenharmony_ci FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | 4138c2ecf20Sopenharmony_ci FE_CAN_TRANSMISSION_MODE_AUTO | 4148c2ecf20Sopenharmony_ci FE_CAN_BANDWIDTH_AUTO | 4158c2ecf20Sopenharmony_ci FE_CAN_GUARD_INTERVAL_AUTO | 4168c2ecf20Sopenharmony_ci FE_CAN_HIERARCHY_AUTO | 4178c2ecf20Sopenharmony_ci FE_CAN_RECOVER 4188c2ecf20Sopenharmony_ci }, 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci .release = lgs8gl5_release, 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci .init = lgs8gl5_init, 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci .set_frontend = lgs8gl5_set_frontend, 4258c2ecf20Sopenharmony_ci .get_frontend = lgs8gl5_get_frontend, 4268c2ecf20Sopenharmony_ci .get_tune_settings = lgs8gl5_get_tune_settings, 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci .read_status = lgs8gl5_read_status, 4298c2ecf20Sopenharmony_ci .read_ber = lgs8gl5_read_ber, 4308c2ecf20Sopenharmony_ci .read_signal_strength = lgs8gl5_read_signal_strength, 4318c2ecf20Sopenharmony_ci .read_snr = lgs8gl5_read_snr, 4328c2ecf20Sopenharmony_ci .read_ucblocks = lgs8gl5_read_ucblocks, 4338c2ecf20Sopenharmony_ci}; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cimodule_param(debug, int, 0644); 4378c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Legend Silicon LGS-8GL5 DMB-TH Demodulator driver"); 4408c2ecf20Sopenharmony_ciMODULE_AUTHOR("Timothy Lee"); 4418c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 442