18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci Samsung S5H1411 VSB/QAM demodulator driver 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci Copyright (C) 2008 Steven Toth <stoth@linuxtv.org> 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci*/ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/string.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/delay.h> 168c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h> 178c2ecf20Sopenharmony_ci#include "s5h1411.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistruct s5h1411_state { 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci struct i2c_adapter *i2c; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci /* configuration settings */ 248c2ecf20Sopenharmony_ci const struct s5h1411_config *config; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci struct dvb_frontend frontend; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci enum fe_modulation current_modulation; 298c2ecf20Sopenharmony_ci unsigned int first_tune:1; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci u32 current_frequency; 328c2ecf20Sopenharmony_ci int if_freq; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci u8 inversion; 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic int debug; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define dprintk(arg...) do { \ 408c2ecf20Sopenharmony_ci if (debug) \ 418c2ecf20Sopenharmony_ci printk(arg); \ 428c2ecf20Sopenharmony_ci} while (0) 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci/* Register values to initialise the demod, defaults to VSB */ 458c2ecf20Sopenharmony_cistatic struct init_tab { 468c2ecf20Sopenharmony_ci u8 addr; 478c2ecf20Sopenharmony_ci u8 reg; 488c2ecf20Sopenharmony_ci u16 data; 498c2ecf20Sopenharmony_ci} init_tab[] = { 508c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x00, 0x0071, }, 518c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x08, 0x0047, }, 528c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x1c, 0x0400, }, 538c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x1e, 0x0370, }, 548c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x1f, 0x342c, }, 558c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x24, 0x0231, }, 568c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x25, 0x1011, }, 578c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x26, 0x0f07, }, 588c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x27, 0x0f04, }, 598c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x28, 0x070f, }, 608c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x29, 0x2820, }, 618c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x2a, 0x102e, }, 628c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x2b, 0x0220, }, 638c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x2e, 0x0d0e, }, 648c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x2f, 0x1013, }, 658c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x31, 0x171b, }, 668c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x32, 0x0e0f, }, 678c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x33, 0x0f10, }, 688c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x34, 0x170e, }, 698c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x35, 0x4b10, }, 708c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x36, 0x0f17, }, 718c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x3c, 0x1577, }, 728c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x3d, 0x081a, }, 738c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x3e, 0x77ee, }, 748c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x40, 0x1e09, }, 758c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x41, 0x0f0c, }, 768c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x42, 0x1f10, }, 778c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x4d, 0x0509, }, 788c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x4e, 0x0a00, }, 798c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x50, 0x0000, }, 808c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x5b, 0x0000, }, 818c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x5c, 0x0008, }, 828c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x57, 0x1101, }, 838c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x65, 0x007c, }, 848c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x68, 0x0512, }, 858c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x69, 0x0258, }, 868c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x70, 0x0004, }, 878c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x71, 0x0007, }, 888c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x76, 0x00a9, }, 898c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x78, 0x3141, }, 908c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0x7a, 0x3141, }, 918c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0xb3, 0x8003, }, 928c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0xb5, 0xa6bb, }, 938c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0xb6, 0x0609, }, 948c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0xb7, 0x2f06, }, 958c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0xb8, 0x003f, }, 968c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0xb9, 0x2700, }, 978c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0xba, 0xfac8, }, 988c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0xbe, 0x1003, }, 998c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0xbf, 0x103f, }, 1008c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0xce, 0x2000, }, 1018c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0xcf, 0x0800, }, 1028c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0xd0, 0x0800, }, 1038c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0xd1, 0x0400, }, 1048c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0xd2, 0x0800, }, 1058c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0xd3, 0x2000, }, 1068c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0xd4, 0x3000, }, 1078c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0xdb, 0x4a9b, }, 1088c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0xdc, 0x1000, }, 1098c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0xde, 0x0001, }, 1108c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0xdf, 0x0000, }, 1118c2ecf20Sopenharmony_ci { S5H1411_I2C_TOP_ADDR, 0xe3, 0x0301, }, 1128c2ecf20Sopenharmony_ci { S5H1411_I2C_QAM_ADDR, 0xf3, 0x0000, }, 1138c2ecf20Sopenharmony_ci { S5H1411_I2C_QAM_ADDR, 0xf3, 0x0001, }, 1148c2ecf20Sopenharmony_ci { S5H1411_I2C_QAM_ADDR, 0x08, 0x0600, }, 1158c2ecf20Sopenharmony_ci { S5H1411_I2C_QAM_ADDR, 0x18, 0x4201, }, 1168c2ecf20Sopenharmony_ci { S5H1411_I2C_QAM_ADDR, 0x1e, 0x6476, }, 1178c2ecf20Sopenharmony_ci { S5H1411_I2C_QAM_ADDR, 0x21, 0x0830, }, 1188c2ecf20Sopenharmony_ci { S5H1411_I2C_QAM_ADDR, 0x0c, 0x5679, }, 1198c2ecf20Sopenharmony_ci { S5H1411_I2C_QAM_ADDR, 0x0d, 0x579b, }, 1208c2ecf20Sopenharmony_ci { S5H1411_I2C_QAM_ADDR, 0x24, 0x0102, }, 1218c2ecf20Sopenharmony_ci { S5H1411_I2C_QAM_ADDR, 0x31, 0x7488, }, 1228c2ecf20Sopenharmony_ci { S5H1411_I2C_QAM_ADDR, 0x32, 0x0a08, }, 1238c2ecf20Sopenharmony_ci { S5H1411_I2C_QAM_ADDR, 0x3d, 0x8689, }, 1248c2ecf20Sopenharmony_ci { S5H1411_I2C_QAM_ADDR, 0x49, 0x0048, }, 1258c2ecf20Sopenharmony_ci { S5H1411_I2C_QAM_ADDR, 0x57, 0x2012, }, 1268c2ecf20Sopenharmony_ci { S5H1411_I2C_QAM_ADDR, 0x5d, 0x7676, }, 1278c2ecf20Sopenharmony_ci { S5H1411_I2C_QAM_ADDR, 0x04, 0x0400, }, 1288c2ecf20Sopenharmony_ci { S5H1411_I2C_QAM_ADDR, 0x58, 0x00c0, }, 1298c2ecf20Sopenharmony_ci { S5H1411_I2C_QAM_ADDR, 0x5b, 0x0100, }, 1308c2ecf20Sopenharmony_ci}; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci/* VSB SNR lookup table */ 1338c2ecf20Sopenharmony_cistatic struct vsb_snr_tab { 1348c2ecf20Sopenharmony_ci u16 val; 1358c2ecf20Sopenharmony_ci u16 data; 1368c2ecf20Sopenharmony_ci} vsb_snr_tab[] = { 1378c2ecf20Sopenharmony_ci { 0x39f, 300, }, 1388c2ecf20Sopenharmony_ci { 0x39b, 295, }, 1398c2ecf20Sopenharmony_ci { 0x397, 290, }, 1408c2ecf20Sopenharmony_ci { 0x394, 285, }, 1418c2ecf20Sopenharmony_ci { 0x38f, 280, }, 1428c2ecf20Sopenharmony_ci { 0x38b, 275, }, 1438c2ecf20Sopenharmony_ci { 0x387, 270, }, 1448c2ecf20Sopenharmony_ci { 0x382, 265, }, 1458c2ecf20Sopenharmony_ci { 0x37d, 260, }, 1468c2ecf20Sopenharmony_ci { 0x377, 255, }, 1478c2ecf20Sopenharmony_ci { 0x370, 250, }, 1488c2ecf20Sopenharmony_ci { 0x36a, 245, }, 1498c2ecf20Sopenharmony_ci { 0x364, 240, }, 1508c2ecf20Sopenharmony_ci { 0x35b, 235, }, 1518c2ecf20Sopenharmony_ci { 0x353, 230, }, 1528c2ecf20Sopenharmony_ci { 0x349, 225, }, 1538c2ecf20Sopenharmony_ci { 0x340, 320, }, 1548c2ecf20Sopenharmony_ci { 0x337, 215, }, 1558c2ecf20Sopenharmony_ci { 0x327, 210, }, 1568c2ecf20Sopenharmony_ci { 0x31b, 205, }, 1578c2ecf20Sopenharmony_ci { 0x310, 200, }, 1588c2ecf20Sopenharmony_ci { 0x302, 195, }, 1598c2ecf20Sopenharmony_ci { 0x2f3, 190, }, 1608c2ecf20Sopenharmony_ci { 0x2e4, 185, }, 1618c2ecf20Sopenharmony_ci { 0x2d7, 180, }, 1628c2ecf20Sopenharmony_ci { 0x2cd, 175, }, 1638c2ecf20Sopenharmony_ci { 0x2bb, 170, }, 1648c2ecf20Sopenharmony_ci { 0x2a9, 165, }, 1658c2ecf20Sopenharmony_ci { 0x29e, 160, }, 1668c2ecf20Sopenharmony_ci { 0x284, 155, }, 1678c2ecf20Sopenharmony_ci { 0x27a, 150, }, 1688c2ecf20Sopenharmony_ci { 0x260, 145, }, 1698c2ecf20Sopenharmony_ci { 0x23a, 140, }, 1708c2ecf20Sopenharmony_ci { 0x224, 135, }, 1718c2ecf20Sopenharmony_ci { 0x213, 130, }, 1728c2ecf20Sopenharmony_ci { 0x204, 125, }, 1738c2ecf20Sopenharmony_ci { 0x1fe, 120, }, 1748c2ecf20Sopenharmony_ci { 0, 0, }, 1758c2ecf20Sopenharmony_ci}; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci/* QAM64 SNR lookup table */ 1788c2ecf20Sopenharmony_cistatic struct qam64_snr_tab { 1798c2ecf20Sopenharmony_ci u16 val; 1808c2ecf20Sopenharmony_ci u16 data; 1818c2ecf20Sopenharmony_ci} qam64_snr_tab[] = { 1828c2ecf20Sopenharmony_ci { 0x0001, 0, }, 1838c2ecf20Sopenharmony_ci { 0x0af0, 300, }, 1848c2ecf20Sopenharmony_ci { 0x0d80, 290, }, 1858c2ecf20Sopenharmony_ci { 0x10a0, 280, }, 1868c2ecf20Sopenharmony_ci { 0x14b5, 270, }, 1878c2ecf20Sopenharmony_ci { 0x1590, 268, }, 1888c2ecf20Sopenharmony_ci { 0x1680, 266, }, 1898c2ecf20Sopenharmony_ci { 0x17b0, 264, }, 1908c2ecf20Sopenharmony_ci { 0x18c0, 262, }, 1918c2ecf20Sopenharmony_ci { 0x19b0, 260, }, 1928c2ecf20Sopenharmony_ci { 0x1ad0, 258, }, 1938c2ecf20Sopenharmony_ci { 0x1d00, 256, }, 1948c2ecf20Sopenharmony_ci { 0x1da0, 254, }, 1958c2ecf20Sopenharmony_ci { 0x1ef0, 252, }, 1968c2ecf20Sopenharmony_ci { 0x2050, 250, }, 1978c2ecf20Sopenharmony_ci { 0x20f0, 249, }, 1988c2ecf20Sopenharmony_ci { 0x21d0, 248, }, 1998c2ecf20Sopenharmony_ci { 0x22b0, 247, }, 2008c2ecf20Sopenharmony_ci { 0x23a0, 246, }, 2018c2ecf20Sopenharmony_ci { 0x2470, 245, }, 2028c2ecf20Sopenharmony_ci { 0x24f0, 244, }, 2038c2ecf20Sopenharmony_ci { 0x25a0, 243, }, 2048c2ecf20Sopenharmony_ci { 0x26c0, 242, }, 2058c2ecf20Sopenharmony_ci { 0x27b0, 241, }, 2068c2ecf20Sopenharmony_ci { 0x28d0, 240, }, 2078c2ecf20Sopenharmony_ci { 0x29b0, 239, }, 2088c2ecf20Sopenharmony_ci { 0x2ad0, 238, }, 2098c2ecf20Sopenharmony_ci { 0x2ba0, 237, }, 2108c2ecf20Sopenharmony_ci { 0x2c80, 236, }, 2118c2ecf20Sopenharmony_ci { 0x2d20, 235, }, 2128c2ecf20Sopenharmony_ci { 0x2e00, 234, }, 2138c2ecf20Sopenharmony_ci { 0x2f10, 233, }, 2148c2ecf20Sopenharmony_ci { 0x3050, 232, }, 2158c2ecf20Sopenharmony_ci { 0x3190, 231, }, 2168c2ecf20Sopenharmony_ci { 0x3300, 230, }, 2178c2ecf20Sopenharmony_ci { 0x3340, 229, }, 2188c2ecf20Sopenharmony_ci { 0x3200, 228, }, 2198c2ecf20Sopenharmony_ci { 0x3550, 227, }, 2208c2ecf20Sopenharmony_ci { 0x3610, 226, }, 2218c2ecf20Sopenharmony_ci { 0x3600, 225, }, 2228c2ecf20Sopenharmony_ci { 0x3700, 224, }, 2238c2ecf20Sopenharmony_ci { 0x3800, 223, }, 2248c2ecf20Sopenharmony_ci { 0x3920, 222, }, 2258c2ecf20Sopenharmony_ci { 0x3a20, 221, }, 2268c2ecf20Sopenharmony_ci { 0x3b30, 220, }, 2278c2ecf20Sopenharmony_ci { 0x3d00, 219, }, 2288c2ecf20Sopenharmony_ci { 0x3e00, 218, }, 2298c2ecf20Sopenharmony_ci { 0x4000, 217, }, 2308c2ecf20Sopenharmony_ci { 0x4100, 216, }, 2318c2ecf20Sopenharmony_ci { 0x4300, 215, }, 2328c2ecf20Sopenharmony_ci { 0x4400, 214, }, 2338c2ecf20Sopenharmony_ci { 0x4600, 213, }, 2348c2ecf20Sopenharmony_ci { 0x4700, 212, }, 2358c2ecf20Sopenharmony_ci { 0x4800, 211, }, 2368c2ecf20Sopenharmony_ci { 0x4a00, 210, }, 2378c2ecf20Sopenharmony_ci { 0x4b00, 209, }, 2388c2ecf20Sopenharmony_ci { 0x4d00, 208, }, 2398c2ecf20Sopenharmony_ci { 0x4f00, 207, }, 2408c2ecf20Sopenharmony_ci { 0x5050, 206, }, 2418c2ecf20Sopenharmony_ci { 0x5200, 205, }, 2428c2ecf20Sopenharmony_ci { 0x53c0, 204, }, 2438c2ecf20Sopenharmony_ci { 0x5450, 203, }, 2448c2ecf20Sopenharmony_ci { 0x5650, 202, }, 2458c2ecf20Sopenharmony_ci { 0x5820, 201, }, 2468c2ecf20Sopenharmony_ci { 0x6000, 200, }, 2478c2ecf20Sopenharmony_ci { 0xffff, 0, }, 2488c2ecf20Sopenharmony_ci}; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci/* QAM256 SNR lookup table */ 2518c2ecf20Sopenharmony_cistatic struct qam256_snr_tab { 2528c2ecf20Sopenharmony_ci u16 val; 2538c2ecf20Sopenharmony_ci u16 data; 2548c2ecf20Sopenharmony_ci} qam256_snr_tab[] = { 2558c2ecf20Sopenharmony_ci { 0x0001, 0, }, 2568c2ecf20Sopenharmony_ci { 0x0970, 400, }, 2578c2ecf20Sopenharmony_ci { 0x0a90, 390, }, 2588c2ecf20Sopenharmony_ci { 0x0b90, 380, }, 2598c2ecf20Sopenharmony_ci { 0x0d90, 370, }, 2608c2ecf20Sopenharmony_ci { 0x0ff0, 360, }, 2618c2ecf20Sopenharmony_ci { 0x1240, 350, }, 2628c2ecf20Sopenharmony_ci { 0x1345, 348, }, 2638c2ecf20Sopenharmony_ci { 0x13c0, 346, }, 2648c2ecf20Sopenharmony_ci { 0x14c0, 344, }, 2658c2ecf20Sopenharmony_ci { 0x1500, 342, }, 2668c2ecf20Sopenharmony_ci { 0x1610, 340, }, 2678c2ecf20Sopenharmony_ci { 0x1700, 338, }, 2688c2ecf20Sopenharmony_ci { 0x1800, 336, }, 2698c2ecf20Sopenharmony_ci { 0x18b0, 334, }, 2708c2ecf20Sopenharmony_ci { 0x1900, 332, }, 2718c2ecf20Sopenharmony_ci { 0x1ab0, 330, }, 2728c2ecf20Sopenharmony_ci { 0x1bc0, 328, }, 2738c2ecf20Sopenharmony_ci { 0x1cb0, 326, }, 2748c2ecf20Sopenharmony_ci { 0x1db0, 324, }, 2758c2ecf20Sopenharmony_ci { 0x1eb0, 322, }, 2768c2ecf20Sopenharmony_ci { 0x2030, 320, }, 2778c2ecf20Sopenharmony_ci { 0x2200, 318, }, 2788c2ecf20Sopenharmony_ci { 0x2280, 316, }, 2798c2ecf20Sopenharmony_ci { 0x2410, 314, }, 2808c2ecf20Sopenharmony_ci { 0x25b0, 312, }, 2818c2ecf20Sopenharmony_ci { 0x27a0, 310, }, 2828c2ecf20Sopenharmony_ci { 0x2840, 308, }, 2838c2ecf20Sopenharmony_ci { 0x29d0, 306, }, 2848c2ecf20Sopenharmony_ci { 0x2b10, 304, }, 2858c2ecf20Sopenharmony_ci { 0x2d30, 302, }, 2868c2ecf20Sopenharmony_ci { 0x2f20, 300, }, 2878c2ecf20Sopenharmony_ci { 0x30c0, 298, }, 2888c2ecf20Sopenharmony_ci { 0x3260, 297, }, 2898c2ecf20Sopenharmony_ci { 0x32c0, 296, }, 2908c2ecf20Sopenharmony_ci { 0x3300, 295, }, 2918c2ecf20Sopenharmony_ci { 0x33b0, 294, }, 2928c2ecf20Sopenharmony_ci { 0x34b0, 293, }, 2938c2ecf20Sopenharmony_ci { 0x35a0, 292, }, 2948c2ecf20Sopenharmony_ci { 0x3650, 291, }, 2958c2ecf20Sopenharmony_ci { 0x3800, 290, }, 2968c2ecf20Sopenharmony_ci { 0x3900, 289, }, 2978c2ecf20Sopenharmony_ci { 0x3a50, 288, }, 2988c2ecf20Sopenharmony_ci { 0x3b30, 287, }, 2998c2ecf20Sopenharmony_ci { 0x3cb0, 286, }, 3008c2ecf20Sopenharmony_ci { 0x3e20, 285, }, 3018c2ecf20Sopenharmony_ci { 0x3fa0, 284, }, 3028c2ecf20Sopenharmony_ci { 0x40a0, 283, }, 3038c2ecf20Sopenharmony_ci { 0x41c0, 282, }, 3048c2ecf20Sopenharmony_ci { 0x42f0, 281, }, 3058c2ecf20Sopenharmony_ci { 0x44a0, 280, }, 3068c2ecf20Sopenharmony_ci { 0x4600, 279, }, 3078c2ecf20Sopenharmony_ci { 0x47b0, 278, }, 3088c2ecf20Sopenharmony_ci { 0x4900, 277, }, 3098c2ecf20Sopenharmony_ci { 0x4a00, 276, }, 3108c2ecf20Sopenharmony_ci { 0x4ba0, 275, }, 3118c2ecf20Sopenharmony_ci { 0x4d00, 274, }, 3128c2ecf20Sopenharmony_ci { 0x4f00, 273, }, 3138c2ecf20Sopenharmony_ci { 0x5000, 272, }, 3148c2ecf20Sopenharmony_ci { 0x51f0, 272, }, 3158c2ecf20Sopenharmony_ci { 0x53a0, 270, }, 3168c2ecf20Sopenharmony_ci { 0x5520, 269, }, 3178c2ecf20Sopenharmony_ci { 0x5700, 268, }, 3188c2ecf20Sopenharmony_ci { 0x5800, 267, }, 3198c2ecf20Sopenharmony_ci { 0x5a00, 266, }, 3208c2ecf20Sopenharmony_ci { 0x5c00, 265, }, 3218c2ecf20Sopenharmony_ci { 0x5d00, 264, }, 3228c2ecf20Sopenharmony_ci { 0x5f00, 263, }, 3238c2ecf20Sopenharmony_ci { 0x6000, 262, }, 3248c2ecf20Sopenharmony_ci { 0x6200, 261, }, 3258c2ecf20Sopenharmony_ci { 0x6400, 260, }, 3268c2ecf20Sopenharmony_ci { 0xffff, 0, }, 3278c2ecf20Sopenharmony_ci}; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci/* 8 bit registers, 16 bit values */ 3308c2ecf20Sopenharmony_cistatic int s5h1411_writereg(struct s5h1411_state *state, 3318c2ecf20Sopenharmony_ci u8 addr, u8 reg, u16 data) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci int ret; 3348c2ecf20Sopenharmony_ci u8 buf[] = { reg, data >> 8, data & 0xff }; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 }; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci ret = i2c_transfer(state->i2c, &msg, 1); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci if (ret != 1) 3418c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: writereg error 0x%02x 0x%02x 0x%04x, ret == %i)\n", 3428c2ecf20Sopenharmony_ci __func__, addr, reg, data, ret); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci return (ret != 1) ? -1 : 0; 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic u16 s5h1411_readreg(struct s5h1411_state *state, u8 addr, u8 reg) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci int ret; 3508c2ecf20Sopenharmony_ci u8 b0[] = { reg }; 3518c2ecf20Sopenharmony_ci u8 b1[] = { 0, 0 }; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci struct i2c_msg msg[] = { 3548c2ecf20Sopenharmony_ci { .addr = addr, .flags = 0, .buf = b0, .len = 1 }, 3558c2ecf20Sopenharmony_ci { .addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 2 } }; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci ret = i2c_transfer(state->i2c, msg, 2); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (ret != 2) 3608c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: readreg error (ret == %i)\n", 3618c2ecf20Sopenharmony_ci __func__, ret); 3628c2ecf20Sopenharmony_ci return (b1[0] << 8) | b1[1]; 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic int s5h1411_softreset(struct dvb_frontend *fe) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci struct s5h1411_state *state = fe->demodulator_priv; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci dprintk("%s()\n", __func__); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf7, 0); 3728c2ecf20Sopenharmony_ci s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf7, 1); 3738c2ecf20Sopenharmony_ci return 0; 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistatic int s5h1411_set_if_freq(struct dvb_frontend *fe, int KHz) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci struct s5h1411_state *state = fe->demodulator_priv; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci dprintk("%s(%d KHz)\n", __func__, KHz); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci switch (KHz) { 3838c2ecf20Sopenharmony_ci case 3250: 3848c2ecf20Sopenharmony_ci s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x10d5); 3858c2ecf20Sopenharmony_ci s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x5342); 3868c2ecf20Sopenharmony_ci s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x10d9); 3878c2ecf20Sopenharmony_ci break; 3888c2ecf20Sopenharmony_ci case 3500: 3898c2ecf20Sopenharmony_ci s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x1225); 3908c2ecf20Sopenharmony_ci s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x1e96); 3918c2ecf20Sopenharmony_ci s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x1225); 3928c2ecf20Sopenharmony_ci break; 3938c2ecf20Sopenharmony_ci case 4000: 3948c2ecf20Sopenharmony_ci s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x14bc); 3958c2ecf20Sopenharmony_ci s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0xb53e); 3968c2ecf20Sopenharmony_ci s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x14bd); 3978c2ecf20Sopenharmony_ci break; 3988c2ecf20Sopenharmony_ci default: 3998c2ecf20Sopenharmony_ci dprintk("%s(%d KHz) Invalid, defaulting to 5380\n", 4008c2ecf20Sopenharmony_ci __func__, KHz); 4018c2ecf20Sopenharmony_ci fallthrough; 4028c2ecf20Sopenharmony_ci case 5380: 4038c2ecf20Sopenharmony_ci case 44000: 4048c2ecf20Sopenharmony_ci s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x1be4); 4058c2ecf20Sopenharmony_ci s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x3655); 4068c2ecf20Sopenharmony_ci s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x1be4); 4078c2ecf20Sopenharmony_ci break; 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci state->if_freq = KHz; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci return 0; 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic int s5h1411_set_mpeg_timing(struct dvb_frontend *fe, int mode) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci struct s5h1411_state *state = fe->demodulator_priv; 4188c2ecf20Sopenharmony_ci u16 val; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci dprintk("%s(%d)\n", __func__, mode); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xbe) & 0xcfff; 4238c2ecf20Sopenharmony_ci switch (mode) { 4248c2ecf20Sopenharmony_ci case S5H1411_MPEGTIMING_CONTINUOUS_INVERTING_CLOCK: 4258c2ecf20Sopenharmony_ci val |= 0x0000; 4268c2ecf20Sopenharmony_ci break; 4278c2ecf20Sopenharmony_ci case S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK: 4288c2ecf20Sopenharmony_ci dprintk("%s(%d) Mode1 or Defaulting\n", __func__, mode); 4298c2ecf20Sopenharmony_ci val |= 0x1000; 4308c2ecf20Sopenharmony_ci break; 4318c2ecf20Sopenharmony_ci case S5H1411_MPEGTIMING_NONCONTINUOUS_INVERTING_CLOCK: 4328c2ecf20Sopenharmony_ci val |= 0x2000; 4338c2ecf20Sopenharmony_ci break; 4348c2ecf20Sopenharmony_ci case S5H1411_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK: 4358c2ecf20Sopenharmony_ci val |= 0x3000; 4368c2ecf20Sopenharmony_ci break; 4378c2ecf20Sopenharmony_ci default: 4388c2ecf20Sopenharmony_ci return -EINVAL; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci /* Configure MPEG Signal Timing charactistics */ 4428c2ecf20Sopenharmony_ci return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbe, val); 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic int s5h1411_set_spectralinversion(struct dvb_frontend *fe, int inversion) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci struct s5h1411_state *state = fe->demodulator_priv; 4488c2ecf20Sopenharmony_ci u16 val; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci dprintk("%s(%d)\n", __func__, inversion); 4518c2ecf20Sopenharmony_ci val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x24) & ~0x1000; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (inversion == 1) 4548c2ecf20Sopenharmony_ci val |= 0x1000; /* Inverted */ 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci state->inversion = inversion; 4578c2ecf20Sopenharmony_ci return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x24, val); 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cistatic int s5h1411_set_serialmode(struct dvb_frontend *fe, int serial) 4618c2ecf20Sopenharmony_ci{ 4628c2ecf20Sopenharmony_ci struct s5h1411_state *state = fe->demodulator_priv; 4638c2ecf20Sopenharmony_ci u16 val; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci dprintk("%s(%d)\n", __func__, serial); 4668c2ecf20Sopenharmony_ci val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xbd) & ~0x100; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci if (serial == 1) 4698c2ecf20Sopenharmony_ci val |= 0x100; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbd, val); 4728c2ecf20Sopenharmony_ci} 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_cistatic int s5h1411_enable_modulation(struct dvb_frontend *fe, 4758c2ecf20Sopenharmony_ci enum fe_modulation m) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci struct s5h1411_state *state = fe->demodulator_priv; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci dprintk("%s(0x%08x)\n", __func__, m); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci if ((state->first_tune == 0) && (m == state->current_modulation)) { 4828c2ecf20Sopenharmony_ci dprintk("%s() Already at desired modulation. Skipping...\n", 4838c2ecf20Sopenharmony_ci __func__); 4848c2ecf20Sopenharmony_ci return 0; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci switch (m) { 4888c2ecf20Sopenharmony_ci case VSB_8: 4898c2ecf20Sopenharmony_ci dprintk("%s() VSB_8\n", __func__); 4908c2ecf20Sopenharmony_ci s5h1411_set_if_freq(fe, state->config->vsb_if); 4918c2ecf20Sopenharmony_ci s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x00, 0x71); 4928c2ecf20Sopenharmony_ci s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf6, 0x00); 4938c2ecf20Sopenharmony_ci s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xcd, 0xf1); 4948c2ecf20Sopenharmony_ci break; 4958c2ecf20Sopenharmony_ci case QAM_64: 4968c2ecf20Sopenharmony_ci case QAM_256: 4978c2ecf20Sopenharmony_ci case QAM_AUTO: 4988c2ecf20Sopenharmony_ci dprintk("%s() QAM_AUTO (64/256)\n", __func__); 4998c2ecf20Sopenharmony_ci s5h1411_set_if_freq(fe, state->config->qam_if); 5008c2ecf20Sopenharmony_ci s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x00, 0x0171); 5018c2ecf20Sopenharmony_ci s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf6, 0x0001); 5028c2ecf20Sopenharmony_ci s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x16, 0x1101); 5038c2ecf20Sopenharmony_ci s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xcd, 0x00f0); 5048c2ecf20Sopenharmony_ci break; 5058c2ecf20Sopenharmony_ci default: 5068c2ecf20Sopenharmony_ci dprintk("%s() Invalid modulation\n", __func__); 5078c2ecf20Sopenharmony_ci return -EINVAL; 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci state->current_modulation = m; 5118c2ecf20Sopenharmony_ci state->first_tune = 0; 5128c2ecf20Sopenharmony_ci s5h1411_softreset(fe); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci return 0; 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_cistatic int s5h1411_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) 5188c2ecf20Sopenharmony_ci{ 5198c2ecf20Sopenharmony_ci struct s5h1411_state *state = fe->demodulator_priv; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci dprintk("%s(%d)\n", __func__, enable); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci if (enable) 5248c2ecf20Sopenharmony_ci return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 1); 5258c2ecf20Sopenharmony_ci else 5268c2ecf20Sopenharmony_ci return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 0); 5278c2ecf20Sopenharmony_ci} 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_cistatic int s5h1411_set_gpio(struct dvb_frontend *fe, int enable) 5308c2ecf20Sopenharmony_ci{ 5318c2ecf20Sopenharmony_ci struct s5h1411_state *state = fe->demodulator_priv; 5328c2ecf20Sopenharmony_ci u16 val; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci dprintk("%s(%d)\n", __func__, enable); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xe0) & ~0x02; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci if (enable) 5398c2ecf20Sopenharmony_ci return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xe0, 5408c2ecf20Sopenharmony_ci val | 0x02); 5418c2ecf20Sopenharmony_ci else 5428c2ecf20Sopenharmony_ci return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xe0, val); 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_cistatic int s5h1411_set_powerstate(struct dvb_frontend *fe, int enable) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci struct s5h1411_state *state = fe->demodulator_priv; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci dprintk("%s(%d)\n", __func__, enable); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci if (enable) 5528c2ecf20Sopenharmony_ci s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf4, 1); 5538c2ecf20Sopenharmony_ci else { 5548c2ecf20Sopenharmony_ci s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf4, 0); 5558c2ecf20Sopenharmony_ci s5h1411_softreset(fe); 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci return 0; 5598c2ecf20Sopenharmony_ci} 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_cistatic int s5h1411_sleep(struct dvb_frontend *fe) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci return s5h1411_set_powerstate(fe, 1); 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_cistatic int s5h1411_register_reset(struct dvb_frontend *fe) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci struct s5h1411_state *state = fe->demodulator_priv; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci dprintk("%s()\n", __func__); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf3, 0); 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci/* Talk to the demod, set the FEC, GUARD, QAM settings etc */ 5768c2ecf20Sopenharmony_cistatic int s5h1411_set_frontend(struct dvb_frontend *fe) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci struct dtv_frontend_properties *p = &fe->dtv_property_cache; 5798c2ecf20Sopenharmony_ci struct s5h1411_state *state = fe->demodulator_priv; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci dprintk("%s(frequency=%d)\n", __func__, p->frequency); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci s5h1411_softreset(fe); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci state->current_frequency = p->frequency; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci s5h1411_enable_modulation(fe, p->modulation); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci if (fe->ops.tuner_ops.set_params) { 5908c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 5918c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci fe->ops.tuner_ops.set_params(fe); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 5968c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci /* Issue a reset to the demod so it knows to resync against the 6008c2ecf20Sopenharmony_ci newly tuned frequency */ 6018c2ecf20Sopenharmony_ci s5h1411_softreset(fe); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci return 0; 6048c2ecf20Sopenharmony_ci} 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci/* Reset the demod hardware and reset all of the configuration registers 6078c2ecf20Sopenharmony_ci to a default state. */ 6088c2ecf20Sopenharmony_cistatic int s5h1411_init(struct dvb_frontend *fe) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci struct s5h1411_state *state = fe->demodulator_priv; 6118c2ecf20Sopenharmony_ci int i; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci dprintk("%s()\n", __func__); 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci s5h1411_set_powerstate(fe, 0); 6168c2ecf20Sopenharmony_ci s5h1411_register_reset(fe); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(init_tab); i++) 6198c2ecf20Sopenharmony_ci s5h1411_writereg(state, init_tab[i].addr, 6208c2ecf20Sopenharmony_ci init_tab[i].reg, 6218c2ecf20Sopenharmony_ci init_tab[i].data); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci /* The datasheet says that after initialisation, VSB is default */ 6248c2ecf20Sopenharmony_ci state->current_modulation = VSB_8; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci /* Although the datasheet says it's in VSB, empirical evidence 6278c2ecf20Sopenharmony_ci shows problems getting lock on the first tuning request. Make 6288c2ecf20Sopenharmony_ci sure we call enable_modulation the first time around */ 6298c2ecf20Sopenharmony_ci state->first_tune = 1; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci if (state->config->output_mode == S5H1411_SERIAL_OUTPUT) 6328c2ecf20Sopenharmony_ci /* Serial */ 6338c2ecf20Sopenharmony_ci s5h1411_set_serialmode(fe, 1); 6348c2ecf20Sopenharmony_ci else 6358c2ecf20Sopenharmony_ci /* Parallel */ 6368c2ecf20Sopenharmony_ci s5h1411_set_serialmode(fe, 0); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci s5h1411_set_spectralinversion(fe, state->config->inversion); 6398c2ecf20Sopenharmony_ci s5h1411_set_if_freq(fe, state->config->vsb_if); 6408c2ecf20Sopenharmony_ci s5h1411_set_gpio(fe, state->config->gpio); 6418c2ecf20Sopenharmony_ci s5h1411_set_mpeg_timing(fe, state->config->mpeg_timing); 6428c2ecf20Sopenharmony_ci s5h1411_softreset(fe); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci /* Note: Leaving the I2C gate closed. */ 6458c2ecf20Sopenharmony_ci s5h1411_i2c_gate_ctrl(fe, 0); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci return 0; 6488c2ecf20Sopenharmony_ci} 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_cistatic int s5h1411_read_status(struct dvb_frontend *fe, enum fe_status *status) 6518c2ecf20Sopenharmony_ci{ 6528c2ecf20Sopenharmony_ci struct s5h1411_state *state = fe->demodulator_priv; 6538c2ecf20Sopenharmony_ci u16 reg; 6548c2ecf20Sopenharmony_ci u32 tuner_status = 0; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci *status = 0; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci /* Register F2 bit 15 = Master Lock, removed */ 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci switch (state->current_modulation) { 6618c2ecf20Sopenharmony_ci case QAM_64: 6628c2ecf20Sopenharmony_ci case QAM_256: 6638c2ecf20Sopenharmony_ci reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf0); 6648c2ecf20Sopenharmony_ci if (reg & 0x10) /* QAM FEC Lock */ 6658c2ecf20Sopenharmony_ci *status |= FE_HAS_SYNC | FE_HAS_LOCK; 6668c2ecf20Sopenharmony_ci if (reg & 0x100) /* QAM EQ Lock */ 6678c2ecf20Sopenharmony_ci *status |= FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci break; 6708c2ecf20Sopenharmony_ci case VSB_8: 6718c2ecf20Sopenharmony_ci reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf2); 6728c2ecf20Sopenharmony_ci if (reg & 0x1000) /* FEC Lock */ 6738c2ecf20Sopenharmony_ci *status |= FE_HAS_SYNC | FE_HAS_LOCK; 6748c2ecf20Sopenharmony_ci if (reg & 0x2000) /* EQ Lock */ 6758c2ecf20Sopenharmony_ci *status |= FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x53); 6788c2ecf20Sopenharmony_ci if (reg & 0x1) /* AFC Lock */ 6798c2ecf20Sopenharmony_ci *status |= FE_HAS_SIGNAL; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci break; 6828c2ecf20Sopenharmony_ci default: 6838c2ecf20Sopenharmony_ci return -EINVAL; 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci switch (state->config->status_mode) { 6878c2ecf20Sopenharmony_ci case S5H1411_DEMODLOCKING: 6888c2ecf20Sopenharmony_ci if (*status & FE_HAS_VITERBI) 6898c2ecf20Sopenharmony_ci *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; 6908c2ecf20Sopenharmony_ci break; 6918c2ecf20Sopenharmony_ci case S5H1411_TUNERLOCKING: 6928c2ecf20Sopenharmony_ci /* Get the tuner status */ 6938c2ecf20Sopenharmony_ci if (fe->ops.tuner_ops.get_status) { 6948c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 6958c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci fe->ops.tuner_ops.get_status(fe, &tuner_status); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 7008c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 7018c2ecf20Sopenharmony_ci } 7028c2ecf20Sopenharmony_ci if (tuner_status) 7038c2ecf20Sopenharmony_ci *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; 7048c2ecf20Sopenharmony_ci break; 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci dprintk("%s() status 0x%08x\n", __func__, *status); 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci return 0; 7108c2ecf20Sopenharmony_ci} 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_cistatic int s5h1411_qam256_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v) 7138c2ecf20Sopenharmony_ci{ 7148c2ecf20Sopenharmony_ci int i, ret = -EINVAL; 7158c2ecf20Sopenharmony_ci dprintk("%s()\n", __func__); 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(qam256_snr_tab); i++) { 7188c2ecf20Sopenharmony_ci if (v < qam256_snr_tab[i].val) { 7198c2ecf20Sopenharmony_ci *snr = qam256_snr_tab[i].data; 7208c2ecf20Sopenharmony_ci ret = 0; 7218c2ecf20Sopenharmony_ci break; 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci return ret; 7258c2ecf20Sopenharmony_ci} 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_cistatic int s5h1411_qam64_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v) 7288c2ecf20Sopenharmony_ci{ 7298c2ecf20Sopenharmony_ci int i, ret = -EINVAL; 7308c2ecf20Sopenharmony_ci dprintk("%s()\n", __func__); 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(qam64_snr_tab); i++) { 7338c2ecf20Sopenharmony_ci if (v < qam64_snr_tab[i].val) { 7348c2ecf20Sopenharmony_ci *snr = qam64_snr_tab[i].data; 7358c2ecf20Sopenharmony_ci ret = 0; 7368c2ecf20Sopenharmony_ci break; 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci return ret; 7408c2ecf20Sopenharmony_ci} 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_cistatic int s5h1411_vsb_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v) 7438c2ecf20Sopenharmony_ci{ 7448c2ecf20Sopenharmony_ci int i, ret = -EINVAL; 7458c2ecf20Sopenharmony_ci dprintk("%s()\n", __func__); 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(vsb_snr_tab); i++) { 7488c2ecf20Sopenharmony_ci if (v > vsb_snr_tab[i].val) { 7498c2ecf20Sopenharmony_ci *snr = vsb_snr_tab[i].data; 7508c2ecf20Sopenharmony_ci ret = 0; 7518c2ecf20Sopenharmony_ci break; 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci } 7548c2ecf20Sopenharmony_ci dprintk("%s() snr=%d\n", __func__, *snr); 7558c2ecf20Sopenharmony_ci return ret; 7568c2ecf20Sopenharmony_ci} 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_cistatic int s5h1411_read_snr(struct dvb_frontend *fe, u16 *snr) 7598c2ecf20Sopenharmony_ci{ 7608c2ecf20Sopenharmony_ci struct s5h1411_state *state = fe->demodulator_priv; 7618c2ecf20Sopenharmony_ci u16 reg; 7628c2ecf20Sopenharmony_ci dprintk("%s()\n", __func__); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci switch (state->current_modulation) { 7658c2ecf20Sopenharmony_ci case QAM_64: 7668c2ecf20Sopenharmony_ci reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf1); 7678c2ecf20Sopenharmony_ci return s5h1411_qam64_lookup_snr(fe, snr, reg); 7688c2ecf20Sopenharmony_ci case QAM_256: 7698c2ecf20Sopenharmony_ci reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf1); 7708c2ecf20Sopenharmony_ci return s5h1411_qam256_lookup_snr(fe, snr, reg); 7718c2ecf20Sopenharmony_ci case VSB_8: 7728c2ecf20Sopenharmony_ci reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 7738c2ecf20Sopenharmony_ci 0xf2) & 0x3ff; 7748c2ecf20Sopenharmony_ci return s5h1411_vsb_lookup_snr(fe, snr, reg); 7758c2ecf20Sopenharmony_ci default: 7768c2ecf20Sopenharmony_ci break; 7778c2ecf20Sopenharmony_ci } 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci return -EINVAL; 7808c2ecf20Sopenharmony_ci} 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_cistatic int s5h1411_read_signal_strength(struct dvb_frontend *fe, 7838c2ecf20Sopenharmony_ci u16 *signal_strength) 7848c2ecf20Sopenharmony_ci{ 7858c2ecf20Sopenharmony_ci /* borrowed from lgdt330x.c 7868c2ecf20Sopenharmony_ci * 7878c2ecf20Sopenharmony_ci * Calculate strength from SNR up to 35dB 7888c2ecf20Sopenharmony_ci * Even though the SNR can go higher than 35dB, 7898c2ecf20Sopenharmony_ci * there is some comfort factor in having a range of 7908c2ecf20Sopenharmony_ci * strong signals that can show at 100% 7918c2ecf20Sopenharmony_ci */ 7928c2ecf20Sopenharmony_ci u16 snr; 7938c2ecf20Sopenharmony_ci u32 tmp; 7948c2ecf20Sopenharmony_ci int ret = s5h1411_read_snr(fe, &snr); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci *signal_strength = 0; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci if (0 == ret) { 7998c2ecf20Sopenharmony_ci /* The following calculation method was chosen 8008c2ecf20Sopenharmony_ci * purely for the sake of code re-use from the 8018c2ecf20Sopenharmony_ci * other demod drivers that use this method */ 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci /* Convert from SNR in dB * 10 to 8.24 fixed-point */ 8048c2ecf20Sopenharmony_ci tmp = (snr * ((1 << 24) / 10)); 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci /* Convert from 8.24 fixed-point to 8078c2ecf20Sopenharmony_ci * scale the range 0 - 35*2^24 into 0 - 65535*/ 8088c2ecf20Sopenharmony_ci if (tmp >= 8960 * 0x10000) 8098c2ecf20Sopenharmony_ci *signal_strength = 0xffff; 8108c2ecf20Sopenharmony_ci else 8118c2ecf20Sopenharmony_ci *signal_strength = tmp / 8960; 8128c2ecf20Sopenharmony_ci } 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci return ret; 8158c2ecf20Sopenharmony_ci} 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_cistatic int s5h1411_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) 8188c2ecf20Sopenharmony_ci{ 8198c2ecf20Sopenharmony_ci struct s5h1411_state *state = fe->demodulator_priv; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci *ucblocks = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xc9); 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci return 0; 8248c2ecf20Sopenharmony_ci} 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_cistatic int s5h1411_read_ber(struct dvb_frontend *fe, u32 *ber) 8278c2ecf20Sopenharmony_ci{ 8288c2ecf20Sopenharmony_ci return s5h1411_read_ucblocks(fe, ber); 8298c2ecf20Sopenharmony_ci} 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_cistatic int s5h1411_get_frontend(struct dvb_frontend *fe, 8328c2ecf20Sopenharmony_ci struct dtv_frontend_properties *p) 8338c2ecf20Sopenharmony_ci{ 8348c2ecf20Sopenharmony_ci struct s5h1411_state *state = fe->demodulator_priv; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci p->frequency = state->current_frequency; 8378c2ecf20Sopenharmony_ci p->modulation = state->current_modulation; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci return 0; 8408c2ecf20Sopenharmony_ci} 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_cistatic int s5h1411_get_tune_settings(struct dvb_frontend *fe, 8438c2ecf20Sopenharmony_ci struct dvb_frontend_tune_settings *tune) 8448c2ecf20Sopenharmony_ci{ 8458c2ecf20Sopenharmony_ci tune->min_delay_ms = 1000; 8468c2ecf20Sopenharmony_ci return 0; 8478c2ecf20Sopenharmony_ci} 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_cistatic void s5h1411_release(struct dvb_frontend *fe) 8508c2ecf20Sopenharmony_ci{ 8518c2ecf20Sopenharmony_ci struct s5h1411_state *state = fe->demodulator_priv; 8528c2ecf20Sopenharmony_ci kfree(state); 8538c2ecf20Sopenharmony_ci} 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops s5h1411_ops; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_cistruct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config, 8588c2ecf20Sopenharmony_ci struct i2c_adapter *i2c) 8598c2ecf20Sopenharmony_ci{ 8608c2ecf20Sopenharmony_ci struct s5h1411_state *state = NULL; 8618c2ecf20Sopenharmony_ci u16 reg; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci /* allocate memory for the internal state */ 8648c2ecf20Sopenharmony_ci state = kzalloc(sizeof(struct s5h1411_state), GFP_KERNEL); 8658c2ecf20Sopenharmony_ci if (state == NULL) 8668c2ecf20Sopenharmony_ci goto error; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci /* setup the state */ 8698c2ecf20Sopenharmony_ci state->config = config; 8708c2ecf20Sopenharmony_ci state->i2c = i2c; 8718c2ecf20Sopenharmony_ci state->current_modulation = VSB_8; 8728c2ecf20Sopenharmony_ci state->inversion = state->config->inversion; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci /* check if the demod exists */ 8758c2ecf20Sopenharmony_ci reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x05); 8768c2ecf20Sopenharmony_ci if (reg != 0x0066) 8778c2ecf20Sopenharmony_ci goto error; 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci /* create dvb_frontend */ 8808c2ecf20Sopenharmony_ci memcpy(&state->frontend.ops, &s5h1411_ops, 8818c2ecf20Sopenharmony_ci sizeof(struct dvb_frontend_ops)); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci state->frontend.demodulator_priv = state; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci if (s5h1411_init(&state->frontend) != 0) { 8868c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Failed to initialize correctly\n", 8878c2ecf20Sopenharmony_ci __func__); 8888c2ecf20Sopenharmony_ci goto error; 8898c2ecf20Sopenharmony_ci } 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci /* Note: Leaving the I2C gate open here. */ 8928c2ecf20Sopenharmony_ci s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 1); 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci /* Put the device into low-power mode until first use */ 8958c2ecf20Sopenharmony_ci s5h1411_set_powerstate(&state->frontend, 1); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci return &state->frontend; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_cierror: 9008c2ecf20Sopenharmony_ci kfree(state); 9018c2ecf20Sopenharmony_ci return NULL; 9028c2ecf20Sopenharmony_ci} 9038c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(s5h1411_attach); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops s5h1411_ops = { 9068c2ecf20Sopenharmony_ci .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, 9078c2ecf20Sopenharmony_ci .info = { 9088c2ecf20Sopenharmony_ci .name = "Samsung S5H1411 QAM/8VSB Frontend", 9098c2ecf20Sopenharmony_ci .frequency_min_hz = 54 * MHz, 9108c2ecf20Sopenharmony_ci .frequency_max_hz = 858 * MHz, 9118c2ecf20Sopenharmony_ci .frequency_stepsize_hz = 62500, 9128c2ecf20Sopenharmony_ci .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB 9138c2ecf20Sopenharmony_ci }, 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci .init = s5h1411_init, 9168c2ecf20Sopenharmony_ci .sleep = s5h1411_sleep, 9178c2ecf20Sopenharmony_ci .i2c_gate_ctrl = s5h1411_i2c_gate_ctrl, 9188c2ecf20Sopenharmony_ci .set_frontend = s5h1411_set_frontend, 9198c2ecf20Sopenharmony_ci .get_frontend = s5h1411_get_frontend, 9208c2ecf20Sopenharmony_ci .get_tune_settings = s5h1411_get_tune_settings, 9218c2ecf20Sopenharmony_ci .read_status = s5h1411_read_status, 9228c2ecf20Sopenharmony_ci .read_ber = s5h1411_read_ber, 9238c2ecf20Sopenharmony_ci .read_signal_strength = s5h1411_read_signal_strength, 9248c2ecf20Sopenharmony_ci .read_snr = s5h1411_read_snr, 9258c2ecf20Sopenharmony_ci .read_ucblocks = s5h1411_read_ucblocks, 9268c2ecf20Sopenharmony_ci .release = s5h1411_release, 9278c2ecf20Sopenharmony_ci}; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_cimodule_param(debug, int, 0644); 9308c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Enable verbose debug messages"); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Samsung S5H1411 QAM-B/ATSC Demodulator driver"); 9338c2ecf20Sopenharmony_ciMODULE_AUTHOR("Steven Toth"); 9348c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 935