18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Support for NXT2002 and NXT2004 - VSB/QAM 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2005 Kirk Lapray <kirk.lapray@gmail.com> 68c2ecf20Sopenharmony_ci * Copyright (C) 2006-2014 Michael Krufky <mkrufky@linuxtv.org> 78c2ecf20Sopenharmony_ci * based on nxt2002 by Taylor Jacob <rtjacob@earthlink.net> 88c2ecf20Sopenharmony_ci * and nxt2004 by Jean-Francois Thibert <jeanfrancois@sagetv.com> 98c2ecf20Sopenharmony_ci*/ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci/* 128c2ecf20Sopenharmony_ci * NOTES ABOUT THIS DRIVER 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * This Linux driver supports: 158c2ecf20Sopenharmony_ci * B2C2/BBTI Technisat Air2PC - ATSC (NXT2002) 168c2ecf20Sopenharmony_ci * AverTVHD MCE A180 (NXT2004) 178c2ecf20Sopenharmony_ci * ATI HDTV Wonder (NXT2004) 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * This driver needs external firmware. Please use the command 208c2ecf20Sopenharmony_ci * "<kerneldir>/scripts/get_dvb_firmware nxt2002" or 218c2ecf20Sopenharmony_ci * "<kerneldir>/scripts/get_dvb_firmware nxt2004" to 228c2ecf20Sopenharmony_ci * download/extract the appropriate firmware, and then copy it to 238c2ecf20Sopenharmony_ci * /usr/lib/hotplug/firmware/ or /lib/firmware/ 248c2ecf20Sopenharmony_ci * (depending on configuration of firmware hotplug). 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* Max transfer size done by I2C transfer functions */ 298c2ecf20Sopenharmony_ci#define MAX_XFER_SIZE 256 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw" 328c2ecf20Sopenharmony_ci#define NXT2004_DEFAULT_FIRMWARE "dvb-fe-nxt2004.fw" 338c2ecf20Sopenharmony_ci#define CRC_CCIT_MASK 0x1021 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include <linux/kernel.h> 368c2ecf20Sopenharmony_ci#include <linux/init.h> 378c2ecf20Sopenharmony_ci#include <linux/module.h> 388c2ecf20Sopenharmony_ci#include <linux/slab.h> 398c2ecf20Sopenharmony_ci#include <linux/string.h> 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h> 428c2ecf20Sopenharmony_ci#include "nxt200x.h" 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistruct nxt200x_state { 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci struct i2c_adapter* i2c; 478c2ecf20Sopenharmony_ci const struct nxt200x_config* config; 488c2ecf20Sopenharmony_ci struct dvb_frontend frontend; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci /* demodulator private data */ 518c2ecf20Sopenharmony_ci nxt_chip_type demod_chip; 528c2ecf20Sopenharmony_ci u8 initialised:1; 538c2ecf20Sopenharmony_ci}; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic int debug; 568c2ecf20Sopenharmony_ci#define dprintk(args...) do { if (debug) pr_debug(args); } while (0) 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic int i2c_writebytes (struct nxt200x_state* state, u8 addr, u8 *buf, u8 len) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci int err; 618c2ecf20Sopenharmony_ci struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = len }; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { 648c2ecf20Sopenharmony_ci pr_warn("%s: i2c write error (addr 0x%02x, err == %i)\n", 658c2ecf20Sopenharmony_ci __func__, addr, err); 668c2ecf20Sopenharmony_ci return -EREMOTEIO; 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci return 0; 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic int i2c_readbytes(struct nxt200x_state *state, u8 addr, u8 *buf, u8 len) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci int err; 748c2ecf20Sopenharmony_ci struct i2c_msg msg = { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len }; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { 778c2ecf20Sopenharmony_ci pr_warn("%s: i2c read error (addr 0x%02x, err == %i)\n", 788c2ecf20Sopenharmony_ci __func__, addr, err); 798c2ecf20Sopenharmony_ci return -EREMOTEIO; 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci return 0; 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic int nxt200x_writebytes (struct nxt200x_state* state, u8 reg, 858c2ecf20Sopenharmony_ci const u8 *buf, u8 len) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci u8 buf2[MAX_XFER_SIZE]; 888c2ecf20Sopenharmony_ci int err; 898c2ecf20Sopenharmony_ci struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf2, .len = len + 1 }; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci if (1 + len > sizeof(buf2)) { 928c2ecf20Sopenharmony_ci pr_warn("%s: i2c wr reg=%04x: len=%d is too big!\n", 938c2ecf20Sopenharmony_ci __func__, reg, len); 948c2ecf20Sopenharmony_ci return -EINVAL; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci buf2[0] = reg; 988c2ecf20Sopenharmony_ci memcpy(&buf2[1], buf, len); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { 1018c2ecf20Sopenharmony_ci pr_warn("%s: i2c write error (addr 0x%02x, err == %i)\n", 1028c2ecf20Sopenharmony_ci __func__, state->config->demod_address, err); 1038c2ecf20Sopenharmony_ci return -EREMOTEIO; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci return 0; 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic int nxt200x_readbytes(struct nxt200x_state *state, u8 reg, u8 *buf, u8 len) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci u8 reg2 [] = { reg }; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = reg2, .len = 1 }, 1138c2ecf20Sopenharmony_ci { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf, .len = len } }; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci int err; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) { 1188c2ecf20Sopenharmony_ci pr_warn("%s: i2c read error (addr 0x%02x, err == %i)\n", 1198c2ecf20Sopenharmony_ci __func__, state->config->demod_address, err); 1208c2ecf20Sopenharmony_ci return -EREMOTEIO; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci return 0; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic u16 nxt200x_crc(u16 crc, u8 c) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci u8 i; 1288c2ecf20Sopenharmony_ci u16 input = (u16) c & 0xFF; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci input<<=8; 1318c2ecf20Sopenharmony_ci for(i=0; i<8; i++) { 1328c2ecf20Sopenharmony_ci if((crc^input) & 0x8000) 1338c2ecf20Sopenharmony_ci crc=(crc<<1)^CRC_CCIT_MASK; 1348c2ecf20Sopenharmony_ci else 1358c2ecf20Sopenharmony_ci crc<<=1; 1368c2ecf20Sopenharmony_ci input<<=1; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci return crc; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic int nxt200x_writereg_multibyte (struct nxt200x_state* state, u8 reg, u8* data, u8 len) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci u8 attr, len2, buf; 1448c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci /* set multi register register */ 1478c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x35, ®, 1); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci /* send the actual data */ 1508c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x36, data, len); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci switch (state->demod_chip) { 1538c2ecf20Sopenharmony_ci case NXT2002: 1548c2ecf20Sopenharmony_ci len2 = len; 1558c2ecf20Sopenharmony_ci buf = 0x02; 1568c2ecf20Sopenharmony_ci break; 1578c2ecf20Sopenharmony_ci case NXT2004: 1588c2ecf20Sopenharmony_ci /* probably not right, but gives correct values */ 1598c2ecf20Sopenharmony_ci attr = 0x02; 1608c2ecf20Sopenharmony_ci if (reg & 0x80) { 1618c2ecf20Sopenharmony_ci attr = attr << 1; 1628c2ecf20Sopenharmony_ci if (reg & 0x04) 1638c2ecf20Sopenharmony_ci attr = attr >> 1; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci /* set write bit */ 1668c2ecf20Sopenharmony_ci len2 = ((attr << 4) | 0x10) | len; 1678c2ecf20Sopenharmony_ci buf = 0x80; 1688c2ecf20Sopenharmony_ci break; 1698c2ecf20Sopenharmony_ci default: 1708c2ecf20Sopenharmony_ci return -EINVAL; 1718c2ecf20Sopenharmony_ci break; 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci /* set multi register length */ 1758c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x34, &len2, 1); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci /* toggle the multireg write bit */ 1788c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x21, &buf, 1); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci nxt200x_readbytes(state, 0x21, &buf, 1); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci switch (state->demod_chip) { 1838c2ecf20Sopenharmony_ci case NXT2002: 1848c2ecf20Sopenharmony_ci if ((buf & 0x02) == 0) 1858c2ecf20Sopenharmony_ci return 0; 1868c2ecf20Sopenharmony_ci break; 1878c2ecf20Sopenharmony_ci case NXT2004: 1888c2ecf20Sopenharmony_ci if (buf == 0) 1898c2ecf20Sopenharmony_ci return 0; 1908c2ecf20Sopenharmony_ci break; 1918c2ecf20Sopenharmony_ci default: 1928c2ecf20Sopenharmony_ci return -EINVAL; 1938c2ecf20Sopenharmony_ci break; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci pr_warn("Error writing multireg register 0x%02X\n", reg); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci return 0; 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic int nxt200x_readreg_multibyte (struct nxt200x_state* state, u8 reg, u8* data, u8 len) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci int i; 2048c2ecf20Sopenharmony_ci u8 buf, len2, attr; 2058c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci /* set multi register register */ 2088c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x35, ®, 1); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci switch (state->demod_chip) { 2118c2ecf20Sopenharmony_ci case NXT2002: 2128c2ecf20Sopenharmony_ci /* set multi register length */ 2138c2ecf20Sopenharmony_ci len2 = len & 0x80; 2148c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x34, &len2, 1); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci /* read the actual data */ 2178c2ecf20Sopenharmony_ci nxt200x_readbytes(state, reg, data, len); 2188c2ecf20Sopenharmony_ci return 0; 2198c2ecf20Sopenharmony_ci break; 2208c2ecf20Sopenharmony_ci case NXT2004: 2218c2ecf20Sopenharmony_ci /* probably not right, but gives correct values */ 2228c2ecf20Sopenharmony_ci attr = 0x02; 2238c2ecf20Sopenharmony_ci if (reg & 0x80) { 2248c2ecf20Sopenharmony_ci attr = attr << 1; 2258c2ecf20Sopenharmony_ci if (reg & 0x04) 2268c2ecf20Sopenharmony_ci attr = attr >> 1; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* set multi register length */ 2308c2ecf20Sopenharmony_ci len2 = (attr << 4) | len; 2318c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x34, &len2, 1); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci /* toggle the multireg bit*/ 2348c2ecf20Sopenharmony_ci buf = 0x80; 2358c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x21, &buf, 1); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci /* read the actual data */ 2388c2ecf20Sopenharmony_ci for(i = 0; i < len; i++) { 2398c2ecf20Sopenharmony_ci nxt200x_readbytes(state, 0x36 + i, &data[i], 1); 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci return 0; 2428c2ecf20Sopenharmony_ci break; 2438c2ecf20Sopenharmony_ci default: 2448c2ecf20Sopenharmony_ci return -EINVAL; 2458c2ecf20Sopenharmony_ci break; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic void nxt200x_microcontroller_stop (struct nxt200x_state* state) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci u8 buf, stopval, counter = 0; 2528c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci /* set correct stop value */ 2558c2ecf20Sopenharmony_ci switch (state->demod_chip) { 2568c2ecf20Sopenharmony_ci case NXT2002: 2578c2ecf20Sopenharmony_ci stopval = 0x40; 2588c2ecf20Sopenharmony_ci break; 2598c2ecf20Sopenharmony_ci case NXT2004: 2608c2ecf20Sopenharmony_ci stopval = 0x10; 2618c2ecf20Sopenharmony_ci break; 2628c2ecf20Sopenharmony_ci default: 2638c2ecf20Sopenharmony_ci stopval = 0; 2648c2ecf20Sopenharmony_ci break; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci buf = 0x80; 2688c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x22, &buf, 1); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci while (counter < 20) { 2718c2ecf20Sopenharmony_ci nxt200x_readbytes(state, 0x31, &buf, 1); 2728c2ecf20Sopenharmony_ci if (buf & stopval) 2738c2ecf20Sopenharmony_ci return; 2748c2ecf20Sopenharmony_ci msleep(10); 2758c2ecf20Sopenharmony_ci counter++; 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci pr_warn("Timeout waiting for nxt200x to stop. This is ok after firmware upload.\n"); 2798c2ecf20Sopenharmony_ci return; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic void nxt200x_microcontroller_start (struct nxt200x_state* state) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci u8 buf; 2858c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci buf = 0x00; 2888c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x22, &buf, 1); 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic void nxt2004_microcontroller_init (struct nxt200x_state* state) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci u8 buf[9]; 2948c2ecf20Sopenharmony_ci u8 counter = 0; 2958c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci buf[0] = 0x00; 2988c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x2b, buf, 1); 2998c2ecf20Sopenharmony_ci buf[0] = 0x70; 3008c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x34, buf, 1); 3018c2ecf20Sopenharmony_ci buf[0] = 0x04; 3028c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x35, buf, 1); 3038c2ecf20Sopenharmony_ci buf[0] = 0x01; buf[1] = 0x23; buf[2] = 0x45; buf[3] = 0x67; buf[4] = 0x89; 3048c2ecf20Sopenharmony_ci buf[5] = 0xAB; buf[6] = 0xCD; buf[7] = 0xEF; buf[8] = 0xC0; 3058c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x36, buf, 9); 3068c2ecf20Sopenharmony_ci buf[0] = 0x80; 3078c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x21, buf, 1); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci while (counter < 20) { 3108c2ecf20Sopenharmony_ci nxt200x_readbytes(state, 0x21, buf, 1); 3118c2ecf20Sopenharmony_ci if (buf[0] == 0) 3128c2ecf20Sopenharmony_ci return; 3138c2ecf20Sopenharmony_ci msleep(10); 3148c2ecf20Sopenharmony_ci counter++; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci pr_warn("Timeout waiting for nxt2004 to init.\n"); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci return; 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic int nxt200x_writetuner (struct nxt200x_state* state, u8* data) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci u8 buf, count = 0; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci dprintk("Tuner Bytes: %*ph\n", 4, data + 1); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci /* if NXT2004, write directly to tuner. if NXT2002, write through NXT chip. 3318c2ecf20Sopenharmony_ci * direct write is required for Philips TUV1236D and ALPS TDHU2 */ 3328c2ecf20Sopenharmony_ci switch (state->demod_chip) { 3338c2ecf20Sopenharmony_ci case NXT2004: 3348c2ecf20Sopenharmony_ci if (i2c_writebytes(state, data[0], data+1, 4)) 3358c2ecf20Sopenharmony_ci pr_warn("error writing to tuner\n"); 3368c2ecf20Sopenharmony_ci /* wait until we have a lock */ 3378c2ecf20Sopenharmony_ci while (count < 20) { 3388c2ecf20Sopenharmony_ci i2c_readbytes(state, data[0], &buf, 1); 3398c2ecf20Sopenharmony_ci if (buf & 0x40) 3408c2ecf20Sopenharmony_ci return 0; 3418c2ecf20Sopenharmony_ci msleep(100); 3428c2ecf20Sopenharmony_ci count++; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci pr_warn("timeout waiting for tuner lock\n"); 3458c2ecf20Sopenharmony_ci break; 3468c2ecf20Sopenharmony_ci case NXT2002: 3478c2ecf20Sopenharmony_ci /* set the i2c transfer speed to the tuner */ 3488c2ecf20Sopenharmony_ci buf = 0x03; 3498c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x20, &buf, 1); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci /* setup to transfer 4 bytes via i2c */ 3528c2ecf20Sopenharmony_ci buf = 0x04; 3538c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x34, &buf, 1); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci /* write actual tuner bytes */ 3568c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x36, data+1, 4); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci /* set tuner i2c address */ 3598c2ecf20Sopenharmony_ci buf = data[0] << 1; 3608c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x35, &buf, 1); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci /* write UC Opmode to begin transfer */ 3638c2ecf20Sopenharmony_ci buf = 0x80; 3648c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x21, &buf, 1); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci while (count < 20) { 3678c2ecf20Sopenharmony_ci nxt200x_readbytes(state, 0x21, &buf, 1); 3688c2ecf20Sopenharmony_ci if ((buf & 0x80)== 0x00) 3698c2ecf20Sopenharmony_ci return 0; 3708c2ecf20Sopenharmony_ci msleep(100); 3718c2ecf20Sopenharmony_ci count++; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci pr_warn("timeout error writing to tuner\n"); 3748c2ecf20Sopenharmony_ci break; 3758c2ecf20Sopenharmony_ci default: 3768c2ecf20Sopenharmony_ci return -EINVAL; 3778c2ecf20Sopenharmony_ci break; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci return 0; 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_cistatic void nxt200x_agc_reset(struct nxt200x_state* state) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci u8 buf; 3858c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci switch (state->demod_chip) { 3888c2ecf20Sopenharmony_ci case NXT2002: 3898c2ecf20Sopenharmony_ci buf = 0x08; 3908c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x08, &buf, 1); 3918c2ecf20Sopenharmony_ci buf = 0x00; 3928c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x08, &buf, 1); 3938c2ecf20Sopenharmony_ci break; 3948c2ecf20Sopenharmony_ci case NXT2004: 3958c2ecf20Sopenharmony_ci nxt200x_readreg_multibyte(state, 0x08, &buf, 1); 3968c2ecf20Sopenharmony_ci buf = 0x08; 3978c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x08, &buf, 1); 3988c2ecf20Sopenharmony_ci buf = 0x00; 3998c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x08, &buf, 1); 4008c2ecf20Sopenharmony_ci break; 4018c2ecf20Sopenharmony_ci default: 4028c2ecf20Sopenharmony_ci break; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci return; 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic int nxt2002_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci struct nxt200x_state* state = fe->demodulator_priv; 4118c2ecf20Sopenharmony_ci u8 buf[3], written = 0, chunkpos = 0; 4128c2ecf20Sopenharmony_ci u16 rambase, position, crc = 0; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 4158c2ecf20Sopenharmony_ci dprintk("Firmware is %zu bytes\n", fw->size); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci /* Get the RAM base for this nxt2002 */ 4188c2ecf20Sopenharmony_ci nxt200x_readbytes(state, 0x10, buf, 1); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci if (buf[0] & 0x10) 4218c2ecf20Sopenharmony_ci rambase = 0x1000; 4228c2ecf20Sopenharmony_ci else 4238c2ecf20Sopenharmony_ci rambase = 0x0000; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci dprintk("rambase on this nxt2002 is %04X\n", rambase); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci /* Hold the micro in reset while loading firmware */ 4288c2ecf20Sopenharmony_ci buf[0] = 0x80; 4298c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x2B, buf, 1); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci for (position = 0; position < fw->size; position++) { 4328c2ecf20Sopenharmony_ci if (written == 0) { 4338c2ecf20Sopenharmony_ci crc = 0; 4348c2ecf20Sopenharmony_ci chunkpos = 0x28; 4358c2ecf20Sopenharmony_ci buf[0] = ((rambase + position) >> 8); 4368c2ecf20Sopenharmony_ci buf[1] = (rambase + position) & 0xFF; 4378c2ecf20Sopenharmony_ci buf[2] = 0x81; 4388c2ecf20Sopenharmony_ci /* write starting address */ 4398c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x29, buf, 3); 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci written++; 4428c2ecf20Sopenharmony_ci chunkpos++; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci if ((written % 4) == 0) 4458c2ecf20Sopenharmony_ci nxt200x_writebytes(state, chunkpos, &fw->data[position-3], 4); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci crc = nxt200x_crc(crc, fw->data[position]); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci if ((written == 255) || (position+1 == fw->size)) { 4508c2ecf20Sopenharmony_ci /* write remaining bytes of firmware */ 4518c2ecf20Sopenharmony_ci nxt200x_writebytes(state, chunkpos+4-(written %4), 4528c2ecf20Sopenharmony_ci &fw->data[position-(written %4) + 1], 4538c2ecf20Sopenharmony_ci written %4); 4548c2ecf20Sopenharmony_ci buf[0] = crc << 8; 4558c2ecf20Sopenharmony_ci buf[1] = crc & 0xFF; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci /* write crc */ 4588c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x2C, buf, 2); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci /* do a read to stop things */ 4618c2ecf20Sopenharmony_ci nxt200x_readbytes(state, 0x2A, buf, 1); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci /* set transfer mode to complete */ 4648c2ecf20Sopenharmony_ci buf[0] = 0x80; 4658c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x2B, buf, 1); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci written = 0; 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci return 0; 4728c2ecf20Sopenharmony_ci}; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_cistatic int nxt2004_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) 4758c2ecf20Sopenharmony_ci{ 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci struct nxt200x_state* state = fe->demodulator_priv; 4788c2ecf20Sopenharmony_ci u8 buf[3]; 4798c2ecf20Sopenharmony_ci u16 rambase, position, crc=0; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 4828c2ecf20Sopenharmony_ci dprintk("Firmware is %zu bytes\n", fw->size); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci /* set rambase */ 4858c2ecf20Sopenharmony_ci rambase = 0x1000; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci /* hold the micro in reset while loading firmware */ 4888c2ecf20Sopenharmony_ci buf[0] = 0x80; 4898c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x2B, buf,1); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci /* calculate firmware CRC */ 4928c2ecf20Sopenharmony_ci for (position = 0; position < fw->size; position++) { 4938c2ecf20Sopenharmony_ci crc = nxt200x_crc(crc, fw->data[position]); 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci buf[0] = rambase >> 8; 4978c2ecf20Sopenharmony_ci buf[1] = rambase & 0xFF; 4988c2ecf20Sopenharmony_ci buf[2] = 0x81; 4998c2ecf20Sopenharmony_ci /* write starting address */ 5008c2ecf20Sopenharmony_ci nxt200x_writebytes(state,0x29,buf,3); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci for (position = 0; position < fw->size;) { 5038c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x2C, &fw->data[position], 5048c2ecf20Sopenharmony_ci fw->size-position > 255 ? 255 : fw->size-position); 5058c2ecf20Sopenharmony_ci position += (fw->size-position > 255 ? 255 : fw->size-position); 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci buf[0] = crc >> 8; 5088c2ecf20Sopenharmony_ci buf[1] = crc & 0xFF; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci dprintk("firmware crc is 0x%02X 0x%02X\n", buf[0], buf[1]); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci /* write crc */ 5138c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x2C, buf,2); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci /* do a read to stop things */ 5168c2ecf20Sopenharmony_ci nxt200x_readbytes(state, 0x2C, buf, 1); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci /* set transfer mode to complete */ 5198c2ecf20Sopenharmony_ci buf[0] = 0x80; 5208c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x2B, buf,1); 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci return 0; 5238c2ecf20Sopenharmony_ci}; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cistatic int nxt200x_setup_frontend_parameters(struct dvb_frontend *fe) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci struct dtv_frontend_properties *p = &fe->dtv_property_cache; 5288c2ecf20Sopenharmony_ci struct nxt200x_state* state = fe->demodulator_priv; 5298c2ecf20Sopenharmony_ci u8 buf[5]; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci /* stop the micro first */ 5328c2ecf20Sopenharmony_ci nxt200x_microcontroller_stop(state); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci if (state->demod_chip == NXT2004) { 5358c2ecf20Sopenharmony_ci /* make sure demod is set to digital */ 5368c2ecf20Sopenharmony_ci buf[0] = 0x04; 5378c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x14, buf, 1); 5388c2ecf20Sopenharmony_ci buf[0] = 0x00; 5398c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x17, buf, 1); 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci /* set additional params */ 5438c2ecf20Sopenharmony_ci switch (p->modulation) { 5448c2ecf20Sopenharmony_ci case QAM_64: 5458c2ecf20Sopenharmony_ci case QAM_256: 5468c2ecf20Sopenharmony_ci /* Set punctured clock for QAM */ 5478c2ecf20Sopenharmony_ci /* This is just a guess since I am unable to test it */ 5488c2ecf20Sopenharmony_ci if (state->config->set_ts_params) 5498c2ecf20Sopenharmony_ci state->config->set_ts_params(fe, 1); 5508c2ecf20Sopenharmony_ci break; 5518c2ecf20Sopenharmony_ci case VSB_8: 5528c2ecf20Sopenharmony_ci /* Set non-punctured clock for VSB */ 5538c2ecf20Sopenharmony_ci if (state->config->set_ts_params) 5548c2ecf20Sopenharmony_ci state->config->set_ts_params(fe, 0); 5558c2ecf20Sopenharmony_ci break; 5568c2ecf20Sopenharmony_ci default: 5578c2ecf20Sopenharmony_ci return -EINVAL; 5588c2ecf20Sopenharmony_ci break; 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci if (fe->ops.tuner_ops.calc_regs) { 5628c2ecf20Sopenharmony_ci /* get tuning information */ 5638c2ecf20Sopenharmony_ci fe->ops.tuner_ops.calc_regs(fe, buf, 5); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci /* write frequency information */ 5668c2ecf20Sopenharmony_ci nxt200x_writetuner(state, buf); 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci /* reset the agc now that tuning has been completed */ 5708c2ecf20Sopenharmony_ci nxt200x_agc_reset(state); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci /* set target power level */ 5738c2ecf20Sopenharmony_ci switch (p->modulation) { 5748c2ecf20Sopenharmony_ci case QAM_64: 5758c2ecf20Sopenharmony_ci case QAM_256: 5768c2ecf20Sopenharmony_ci buf[0] = 0x74; 5778c2ecf20Sopenharmony_ci break; 5788c2ecf20Sopenharmony_ci case VSB_8: 5798c2ecf20Sopenharmony_ci buf[0] = 0x70; 5808c2ecf20Sopenharmony_ci break; 5818c2ecf20Sopenharmony_ci default: 5828c2ecf20Sopenharmony_ci return -EINVAL; 5838c2ecf20Sopenharmony_ci break; 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x42, buf, 1); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci /* configure sdm */ 5888c2ecf20Sopenharmony_ci switch (state->demod_chip) { 5898c2ecf20Sopenharmony_ci case NXT2002: 5908c2ecf20Sopenharmony_ci buf[0] = 0x87; 5918c2ecf20Sopenharmony_ci break; 5928c2ecf20Sopenharmony_ci case NXT2004: 5938c2ecf20Sopenharmony_ci buf[0] = 0x07; 5948c2ecf20Sopenharmony_ci break; 5958c2ecf20Sopenharmony_ci default: 5968c2ecf20Sopenharmony_ci return -EINVAL; 5978c2ecf20Sopenharmony_ci break; 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x57, buf, 1); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci /* write sdm1 input */ 6028c2ecf20Sopenharmony_ci buf[0] = 0x10; 6038c2ecf20Sopenharmony_ci buf[1] = 0x00; 6048c2ecf20Sopenharmony_ci switch (state->demod_chip) { 6058c2ecf20Sopenharmony_ci case NXT2002: 6068c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x58, buf, 2); 6078c2ecf20Sopenharmony_ci break; 6088c2ecf20Sopenharmony_ci case NXT2004: 6098c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x58, buf, 2); 6108c2ecf20Sopenharmony_ci break; 6118c2ecf20Sopenharmony_ci default: 6128c2ecf20Sopenharmony_ci return -EINVAL; 6138c2ecf20Sopenharmony_ci break; 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci /* write sdmx input */ 6178c2ecf20Sopenharmony_ci switch (p->modulation) { 6188c2ecf20Sopenharmony_ci case QAM_64: 6198c2ecf20Sopenharmony_ci buf[0] = 0x68; 6208c2ecf20Sopenharmony_ci break; 6218c2ecf20Sopenharmony_ci case QAM_256: 6228c2ecf20Sopenharmony_ci buf[0] = 0x64; 6238c2ecf20Sopenharmony_ci break; 6248c2ecf20Sopenharmony_ci case VSB_8: 6258c2ecf20Sopenharmony_ci buf[0] = 0x60; 6268c2ecf20Sopenharmony_ci break; 6278c2ecf20Sopenharmony_ci default: 6288c2ecf20Sopenharmony_ci return -EINVAL; 6298c2ecf20Sopenharmony_ci break; 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci buf[1] = 0x00; 6328c2ecf20Sopenharmony_ci switch (state->demod_chip) { 6338c2ecf20Sopenharmony_ci case NXT2002: 6348c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x5C, buf, 2); 6358c2ecf20Sopenharmony_ci break; 6368c2ecf20Sopenharmony_ci case NXT2004: 6378c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x5C, buf, 2); 6388c2ecf20Sopenharmony_ci break; 6398c2ecf20Sopenharmony_ci default: 6408c2ecf20Sopenharmony_ci return -EINVAL; 6418c2ecf20Sopenharmony_ci break; 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci /* write adc power lpf fc */ 6458c2ecf20Sopenharmony_ci buf[0] = 0x05; 6468c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x43, buf, 1); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci if (state->demod_chip == NXT2004) { 6498c2ecf20Sopenharmony_ci /* write ??? */ 6508c2ecf20Sopenharmony_ci buf[0] = 0x00; 6518c2ecf20Sopenharmony_ci buf[1] = 0x00; 6528c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x46, buf, 2); 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci /* write accumulator2 input */ 6568c2ecf20Sopenharmony_ci buf[0] = 0x80; 6578c2ecf20Sopenharmony_ci buf[1] = 0x00; 6588c2ecf20Sopenharmony_ci switch (state->demod_chip) { 6598c2ecf20Sopenharmony_ci case NXT2002: 6608c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x4B, buf, 2); 6618c2ecf20Sopenharmony_ci break; 6628c2ecf20Sopenharmony_ci case NXT2004: 6638c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x4B, buf, 2); 6648c2ecf20Sopenharmony_ci break; 6658c2ecf20Sopenharmony_ci default: 6668c2ecf20Sopenharmony_ci return -EINVAL; 6678c2ecf20Sopenharmony_ci break; 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci /* write kg1 */ 6718c2ecf20Sopenharmony_ci buf[0] = 0x00; 6728c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x4D, buf, 1); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci /* write sdm12 lpf fc */ 6758c2ecf20Sopenharmony_ci buf[0] = 0x44; 6768c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x55, buf, 1); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci /* write agc control reg */ 6798c2ecf20Sopenharmony_ci buf[0] = 0x04; 6808c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x41, buf, 1); 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci if (state->demod_chip == NXT2004) { 6838c2ecf20Sopenharmony_ci nxt200x_readreg_multibyte(state, 0x80, buf, 1); 6848c2ecf20Sopenharmony_ci buf[0] = 0x24; 6858c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x80, buf, 1); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci /* soft reset? */ 6888c2ecf20Sopenharmony_ci nxt200x_readreg_multibyte(state, 0x08, buf, 1); 6898c2ecf20Sopenharmony_ci buf[0] = 0x10; 6908c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x08, buf, 1); 6918c2ecf20Sopenharmony_ci nxt200x_readreg_multibyte(state, 0x08, buf, 1); 6928c2ecf20Sopenharmony_ci buf[0] = 0x00; 6938c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x08, buf, 1); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci nxt200x_readreg_multibyte(state, 0x80, buf, 1); 6968c2ecf20Sopenharmony_ci buf[0] = 0x04; 6978c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x80, buf, 1); 6988c2ecf20Sopenharmony_ci buf[0] = 0x00; 6998c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x81, buf, 1); 7008c2ecf20Sopenharmony_ci buf[0] = 0x80; buf[1] = 0x00; buf[2] = 0x00; 7018c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x82, buf, 3); 7028c2ecf20Sopenharmony_ci nxt200x_readreg_multibyte(state, 0x88, buf, 1); 7038c2ecf20Sopenharmony_ci buf[0] = 0x11; 7048c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x88, buf, 1); 7058c2ecf20Sopenharmony_ci nxt200x_readreg_multibyte(state, 0x80, buf, 1); 7068c2ecf20Sopenharmony_ci buf[0] = 0x44; 7078c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x80, buf, 1); 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci /* write agc ucgp0 */ 7118c2ecf20Sopenharmony_ci switch (p->modulation) { 7128c2ecf20Sopenharmony_ci case QAM_64: 7138c2ecf20Sopenharmony_ci buf[0] = 0x02; 7148c2ecf20Sopenharmony_ci break; 7158c2ecf20Sopenharmony_ci case QAM_256: 7168c2ecf20Sopenharmony_ci buf[0] = 0x03; 7178c2ecf20Sopenharmony_ci break; 7188c2ecf20Sopenharmony_ci case VSB_8: 7198c2ecf20Sopenharmony_ci buf[0] = 0x00; 7208c2ecf20Sopenharmony_ci break; 7218c2ecf20Sopenharmony_ci default: 7228c2ecf20Sopenharmony_ci return -EINVAL; 7238c2ecf20Sopenharmony_ci break; 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x30, buf, 1); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci /* write agc control reg */ 7288c2ecf20Sopenharmony_ci buf[0] = 0x00; 7298c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x41, buf, 1); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci /* write accumulator2 input */ 7328c2ecf20Sopenharmony_ci buf[0] = 0x80; 7338c2ecf20Sopenharmony_ci buf[1] = 0x00; 7348c2ecf20Sopenharmony_ci switch (state->demod_chip) { 7358c2ecf20Sopenharmony_ci case NXT2002: 7368c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x49, buf, 2); 7378c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x4B, buf, 2); 7388c2ecf20Sopenharmony_ci break; 7398c2ecf20Sopenharmony_ci case NXT2004: 7408c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x49, buf, 2); 7418c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x4B, buf, 2); 7428c2ecf20Sopenharmony_ci break; 7438c2ecf20Sopenharmony_ci default: 7448c2ecf20Sopenharmony_ci return -EINVAL; 7458c2ecf20Sopenharmony_ci break; 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci /* write agc control reg */ 7498c2ecf20Sopenharmony_ci buf[0] = 0x04; 7508c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x41, buf, 1); 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci nxt200x_microcontroller_start(state); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci if (state->demod_chip == NXT2004) { 7558c2ecf20Sopenharmony_ci nxt2004_microcontroller_init(state); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci /* ???? */ 7588c2ecf20Sopenharmony_ci buf[0] = 0xF0; 7598c2ecf20Sopenharmony_ci buf[1] = 0x00; 7608c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x5C, buf, 2); 7618c2ecf20Sopenharmony_ci } 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci /* adjacent channel detection should be done here, but I don't 7648c2ecf20Sopenharmony_ci have any stations with this need so I cannot test it */ 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci return 0; 7678c2ecf20Sopenharmony_ci} 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_cistatic int nxt200x_read_status(struct dvb_frontend *fe, enum fe_status *status) 7708c2ecf20Sopenharmony_ci{ 7718c2ecf20Sopenharmony_ci struct nxt200x_state* state = fe->demodulator_priv; 7728c2ecf20Sopenharmony_ci u8 lock; 7738c2ecf20Sopenharmony_ci nxt200x_readbytes(state, 0x31, &lock, 1); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci *status = 0; 7768c2ecf20Sopenharmony_ci if (lock & 0x20) { 7778c2ecf20Sopenharmony_ci *status |= FE_HAS_SIGNAL; 7788c2ecf20Sopenharmony_ci *status |= FE_HAS_CARRIER; 7798c2ecf20Sopenharmony_ci *status |= FE_HAS_VITERBI; 7808c2ecf20Sopenharmony_ci *status |= FE_HAS_SYNC; 7818c2ecf20Sopenharmony_ci *status |= FE_HAS_LOCK; 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci return 0; 7848c2ecf20Sopenharmony_ci} 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_cistatic int nxt200x_read_ber(struct dvb_frontend* fe, u32* ber) 7878c2ecf20Sopenharmony_ci{ 7888c2ecf20Sopenharmony_ci struct nxt200x_state* state = fe->demodulator_priv; 7898c2ecf20Sopenharmony_ci u8 b[3]; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci nxt200x_readreg_multibyte(state, 0xE6, b, 3); 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci *ber = ((b[0] << 8) + b[1]) * 8; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci return 0; 7968c2ecf20Sopenharmony_ci} 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_cistatic int nxt200x_read_signal_strength(struct dvb_frontend* fe, u16* strength) 7998c2ecf20Sopenharmony_ci{ 8008c2ecf20Sopenharmony_ci struct nxt200x_state* state = fe->demodulator_priv; 8018c2ecf20Sopenharmony_ci u8 b[2]; 8028c2ecf20Sopenharmony_ci u16 temp = 0; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci /* setup to read cluster variance */ 8058c2ecf20Sopenharmony_ci b[0] = 0x00; 8068c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0xA1, b, 1); 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci /* get multreg val */ 8098c2ecf20Sopenharmony_ci nxt200x_readreg_multibyte(state, 0xA6, b, 2); 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci temp = (b[0] << 8) | b[1]; 8128c2ecf20Sopenharmony_ci *strength = ((0x7FFF - temp) & 0x0FFF) * 16; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci return 0; 8158c2ecf20Sopenharmony_ci} 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_cistatic int nxt200x_read_snr(struct dvb_frontend* fe, u16* snr) 8188c2ecf20Sopenharmony_ci{ 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci struct nxt200x_state* state = fe->demodulator_priv; 8218c2ecf20Sopenharmony_ci u8 b[2]; 8228c2ecf20Sopenharmony_ci u16 temp = 0, temp2; 8238c2ecf20Sopenharmony_ci u32 snrdb = 0; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci /* setup to read cluster variance */ 8268c2ecf20Sopenharmony_ci b[0] = 0x00; 8278c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0xA1, b, 1); 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci /* get multreg val from 0xA6 */ 8308c2ecf20Sopenharmony_ci nxt200x_readreg_multibyte(state, 0xA6, b, 2); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci temp = (b[0] << 8) | b[1]; 8338c2ecf20Sopenharmony_ci temp2 = 0x7FFF - temp; 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci /* snr will be in db */ 8368c2ecf20Sopenharmony_ci if (temp2 > 0x7F00) 8378c2ecf20Sopenharmony_ci snrdb = 1000*24 + ( 1000*(30-24) * ( temp2 - 0x7F00 ) / ( 0x7FFF - 0x7F00 ) ); 8388c2ecf20Sopenharmony_ci else if (temp2 > 0x7EC0) 8398c2ecf20Sopenharmony_ci snrdb = 1000*18 + ( 1000*(24-18) * ( temp2 - 0x7EC0 ) / ( 0x7F00 - 0x7EC0 ) ); 8408c2ecf20Sopenharmony_ci else if (temp2 > 0x7C00) 8418c2ecf20Sopenharmony_ci snrdb = 1000*12 + ( 1000*(18-12) * ( temp2 - 0x7C00 ) / ( 0x7EC0 - 0x7C00 ) ); 8428c2ecf20Sopenharmony_ci else 8438c2ecf20Sopenharmony_ci snrdb = 1000*0 + ( 1000*(12-0) * ( temp2 - 0 ) / ( 0x7C00 - 0 ) ); 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci /* the value reported back from the frontend will be FFFF=32db 0000=0db */ 8468c2ecf20Sopenharmony_ci *snr = snrdb * (0xFFFF/32000); 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci return 0; 8498c2ecf20Sopenharmony_ci} 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_cistatic int nxt200x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) 8528c2ecf20Sopenharmony_ci{ 8538c2ecf20Sopenharmony_ci struct nxt200x_state* state = fe->demodulator_priv; 8548c2ecf20Sopenharmony_ci u8 b[3]; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci nxt200x_readreg_multibyte(state, 0xE6, b, 3); 8578c2ecf20Sopenharmony_ci *ucblocks = b[2]; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci return 0; 8608c2ecf20Sopenharmony_ci} 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_cistatic int nxt200x_sleep(struct dvb_frontend* fe) 8638c2ecf20Sopenharmony_ci{ 8648c2ecf20Sopenharmony_ci return 0; 8658c2ecf20Sopenharmony_ci} 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_cistatic int nxt2002_init(struct dvb_frontend* fe) 8688c2ecf20Sopenharmony_ci{ 8698c2ecf20Sopenharmony_ci struct nxt200x_state* state = fe->demodulator_priv; 8708c2ecf20Sopenharmony_ci const struct firmware *fw; 8718c2ecf20Sopenharmony_ci int ret; 8728c2ecf20Sopenharmony_ci u8 buf[2]; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci /* request the firmware, this will block until someone uploads it */ 8758c2ecf20Sopenharmony_ci pr_debug("%s: Waiting for firmware upload (%s)...\n", 8768c2ecf20Sopenharmony_ci __func__, NXT2002_DEFAULT_FIRMWARE); 8778c2ecf20Sopenharmony_ci ret = request_firmware(&fw, NXT2002_DEFAULT_FIRMWARE, 8788c2ecf20Sopenharmony_ci state->i2c->dev.parent); 8798c2ecf20Sopenharmony_ci pr_debug("%s: Waiting for firmware upload(2)...\n", __func__); 8808c2ecf20Sopenharmony_ci if (ret) { 8818c2ecf20Sopenharmony_ci pr_err("%s: No firmware uploaded (timeout or file not found?)\n", 8828c2ecf20Sopenharmony_ci __func__); 8838c2ecf20Sopenharmony_ci return ret; 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci ret = nxt2002_load_firmware(fe, fw); 8878c2ecf20Sopenharmony_ci release_firmware(fw); 8888c2ecf20Sopenharmony_ci if (ret) { 8898c2ecf20Sopenharmony_ci pr_err("%s: Writing firmware to device failed\n", __func__); 8908c2ecf20Sopenharmony_ci return ret; 8918c2ecf20Sopenharmony_ci } 8928c2ecf20Sopenharmony_ci pr_info("%s: Firmware upload complete\n", __func__); 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci /* Put the micro into reset */ 8958c2ecf20Sopenharmony_ci nxt200x_microcontroller_stop(state); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci /* ensure transfer is complete */ 8988c2ecf20Sopenharmony_ci buf[0]=0x00; 8998c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x2B, buf, 1); 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci /* Put the micro into reset for real this time */ 9028c2ecf20Sopenharmony_ci nxt200x_microcontroller_stop(state); 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci /* soft reset everything (agc,frontend,eq,fec)*/ 9058c2ecf20Sopenharmony_ci buf[0] = 0x0F; 9068c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x08, buf, 1); 9078c2ecf20Sopenharmony_ci buf[0] = 0x00; 9088c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x08, buf, 1); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci /* write agc sdm configure */ 9118c2ecf20Sopenharmony_ci buf[0] = 0xF1; 9128c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x57, buf, 1); 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci /* write mod output format */ 9158c2ecf20Sopenharmony_ci buf[0] = 0x20; 9168c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x09, buf, 1); 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci /* write fec mpeg mode */ 9198c2ecf20Sopenharmony_ci buf[0] = 0x7E; 9208c2ecf20Sopenharmony_ci buf[1] = 0x00; 9218c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0xE9, buf, 2); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci /* write mux selection */ 9248c2ecf20Sopenharmony_ci buf[0] = 0x00; 9258c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0xCC, buf, 1); 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci return 0; 9288c2ecf20Sopenharmony_ci} 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_cistatic int nxt2004_init(struct dvb_frontend* fe) 9318c2ecf20Sopenharmony_ci{ 9328c2ecf20Sopenharmony_ci struct nxt200x_state* state = fe->demodulator_priv; 9338c2ecf20Sopenharmony_ci const struct firmware *fw; 9348c2ecf20Sopenharmony_ci int ret; 9358c2ecf20Sopenharmony_ci u8 buf[3]; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci /* ??? */ 9388c2ecf20Sopenharmony_ci buf[0]=0x00; 9398c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x1E, buf, 1); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci /* request the firmware, this will block until someone uploads it */ 9428c2ecf20Sopenharmony_ci pr_debug("%s: Waiting for firmware upload (%s)...\n", 9438c2ecf20Sopenharmony_ci __func__, NXT2004_DEFAULT_FIRMWARE); 9448c2ecf20Sopenharmony_ci ret = request_firmware(&fw, NXT2004_DEFAULT_FIRMWARE, 9458c2ecf20Sopenharmony_ci state->i2c->dev.parent); 9468c2ecf20Sopenharmony_ci pr_debug("%s: Waiting for firmware upload(2)...\n", __func__); 9478c2ecf20Sopenharmony_ci if (ret) { 9488c2ecf20Sopenharmony_ci pr_err("%s: No firmware uploaded (timeout or file not found?)\n", 9498c2ecf20Sopenharmony_ci __func__); 9508c2ecf20Sopenharmony_ci return ret; 9518c2ecf20Sopenharmony_ci } 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci ret = nxt2004_load_firmware(fe, fw); 9548c2ecf20Sopenharmony_ci release_firmware(fw); 9558c2ecf20Sopenharmony_ci if (ret) { 9568c2ecf20Sopenharmony_ci pr_err("%s: Writing firmware to device failed\n", __func__); 9578c2ecf20Sopenharmony_ci return ret; 9588c2ecf20Sopenharmony_ci } 9598c2ecf20Sopenharmony_ci pr_info("%s: Firmware upload complete\n", __func__); 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci /* ensure transfer is complete */ 9628c2ecf20Sopenharmony_ci buf[0] = 0x01; 9638c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x19, buf, 1); 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci nxt2004_microcontroller_init(state); 9668c2ecf20Sopenharmony_ci nxt200x_microcontroller_stop(state); 9678c2ecf20Sopenharmony_ci nxt200x_microcontroller_stop(state); 9688c2ecf20Sopenharmony_ci nxt2004_microcontroller_init(state); 9698c2ecf20Sopenharmony_ci nxt200x_microcontroller_stop(state); 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci /* soft reset everything (agc,frontend,eq,fec)*/ 9728c2ecf20Sopenharmony_ci buf[0] = 0xFF; 9738c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x08, buf, 1); 9748c2ecf20Sopenharmony_ci buf[0] = 0x00; 9758c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x08, buf, 1); 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci /* write agc sdm configure */ 9788c2ecf20Sopenharmony_ci buf[0] = 0xD7; 9798c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x57, buf, 1); 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci /* ???*/ 9828c2ecf20Sopenharmony_ci buf[0] = 0x07; 9838c2ecf20Sopenharmony_ci buf[1] = 0xfe; 9848c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x35, buf, 2); 9858c2ecf20Sopenharmony_ci buf[0] = 0x12; 9868c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x34, buf, 1); 9878c2ecf20Sopenharmony_ci buf[0] = 0x80; 9888c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x21, buf, 1); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci /* ???*/ 9918c2ecf20Sopenharmony_ci buf[0] = 0x21; 9928c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x0A, buf, 1); 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci /* ???*/ 9958c2ecf20Sopenharmony_ci buf[0] = 0x01; 9968c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x80, buf, 1); 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci /* write fec mpeg mode */ 9998c2ecf20Sopenharmony_ci buf[0] = 0x7E; 10008c2ecf20Sopenharmony_ci buf[1] = 0x00; 10018c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0xE9, buf, 2); 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci /* write mux selection */ 10048c2ecf20Sopenharmony_ci buf[0] = 0x00; 10058c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0xCC, buf, 1); 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci /* ???*/ 10088c2ecf20Sopenharmony_ci nxt200x_readreg_multibyte(state, 0x80, buf, 1); 10098c2ecf20Sopenharmony_ci buf[0] = 0x00; 10108c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x80, buf, 1); 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci /* soft reset? */ 10138c2ecf20Sopenharmony_ci nxt200x_readreg_multibyte(state, 0x08, buf, 1); 10148c2ecf20Sopenharmony_ci buf[0] = 0x10; 10158c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x08, buf, 1); 10168c2ecf20Sopenharmony_ci nxt200x_readreg_multibyte(state, 0x08, buf, 1); 10178c2ecf20Sopenharmony_ci buf[0] = 0x00; 10188c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x08, buf, 1); 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci /* ???*/ 10218c2ecf20Sopenharmony_ci nxt200x_readreg_multibyte(state, 0x80, buf, 1); 10228c2ecf20Sopenharmony_ci buf[0] = 0x01; 10238c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x80, buf, 1); 10248c2ecf20Sopenharmony_ci buf[0] = 0x70; 10258c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x81, buf, 1); 10268c2ecf20Sopenharmony_ci buf[0] = 0x31; buf[1] = 0x5E; buf[2] = 0x66; 10278c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x82, buf, 3); 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci nxt200x_readreg_multibyte(state, 0x88, buf, 1); 10308c2ecf20Sopenharmony_ci buf[0] = 0x11; 10318c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x88, buf, 1); 10328c2ecf20Sopenharmony_ci nxt200x_readreg_multibyte(state, 0x80, buf, 1); 10338c2ecf20Sopenharmony_ci buf[0] = 0x40; 10348c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x80, buf, 1); 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci nxt200x_readbytes(state, 0x10, buf, 1); 10378c2ecf20Sopenharmony_ci buf[0] = 0x10; 10388c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x10, buf, 1); 10398c2ecf20Sopenharmony_ci nxt200x_readbytes(state, 0x0A, buf, 1); 10408c2ecf20Sopenharmony_ci buf[0] = 0x21; 10418c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x0A, buf, 1); 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci nxt2004_microcontroller_init(state); 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci buf[0] = 0x21; 10468c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x0A, buf, 1); 10478c2ecf20Sopenharmony_ci buf[0] = 0x7E; 10488c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0xE9, buf, 1); 10498c2ecf20Sopenharmony_ci buf[0] = 0x00; 10508c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0xEA, buf, 1); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci nxt200x_readreg_multibyte(state, 0x80, buf, 1); 10538c2ecf20Sopenharmony_ci buf[0] = 0x00; 10548c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x80, buf, 1); 10558c2ecf20Sopenharmony_ci nxt200x_readreg_multibyte(state, 0x80, buf, 1); 10568c2ecf20Sopenharmony_ci buf[0] = 0x00; 10578c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x80, buf, 1); 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci /* soft reset? */ 10608c2ecf20Sopenharmony_ci nxt200x_readreg_multibyte(state, 0x08, buf, 1); 10618c2ecf20Sopenharmony_ci buf[0] = 0x10; 10628c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x08, buf, 1); 10638c2ecf20Sopenharmony_ci nxt200x_readreg_multibyte(state, 0x08, buf, 1); 10648c2ecf20Sopenharmony_ci buf[0] = 0x00; 10658c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x08, buf, 1); 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci nxt200x_readreg_multibyte(state, 0x80, buf, 1); 10688c2ecf20Sopenharmony_ci buf[0] = 0x04; 10698c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x80, buf, 1); 10708c2ecf20Sopenharmony_ci buf[0] = 0x00; 10718c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x81, buf, 1); 10728c2ecf20Sopenharmony_ci buf[0] = 0x80; buf[1] = 0x00; buf[2] = 0x00; 10738c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x82, buf, 3); 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci nxt200x_readreg_multibyte(state, 0x88, buf, 1); 10768c2ecf20Sopenharmony_ci buf[0] = 0x11; 10778c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x88, buf, 1); 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci nxt200x_readreg_multibyte(state, 0x80, buf, 1); 10808c2ecf20Sopenharmony_ci buf[0] = 0x44; 10818c2ecf20Sopenharmony_ci nxt200x_writereg_multibyte(state, 0x80, buf, 1); 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci /* initialize tuner */ 10848c2ecf20Sopenharmony_ci nxt200x_readbytes(state, 0x10, buf, 1); 10858c2ecf20Sopenharmony_ci buf[0] = 0x12; 10868c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x10, buf, 1); 10878c2ecf20Sopenharmony_ci buf[0] = 0x04; 10888c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x13, buf, 1); 10898c2ecf20Sopenharmony_ci buf[0] = 0x00; 10908c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x16, buf, 1); 10918c2ecf20Sopenharmony_ci buf[0] = 0x04; 10928c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x14, buf, 1); 10938c2ecf20Sopenharmony_ci buf[0] = 0x00; 10948c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x14, buf, 1); 10958c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x17, buf, 1); 10968c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x14, buf, 1); 10978c2ecf20Sopenharmony_ci nxt200x_writebytes(state, 0x17, buf, 1); 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci return 0; 11008c2ecf20Sopenharmony_ci} 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_cistatic int nxt200x_init(struct dvb_frontend* fe) 11038c2ecf20Sopenharmony_ci{ 11048c2ecf20Sopenharmony_ci struct nxt200x_state* state = fe->demodulator_priv; 11058c2ecf20Sopenharmony_ci int ret = 0; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci if (!state->initialised) { 11088c2ecf20Sopenharmony_ci switch (state->demod_chip) { 11098c2ecf20Sopenharmony_ci case NXT2002: 11108c2ecf20Sopenharmony_ci ret = nxt2002_init(fe); 11118c2ecf20Sopenharmony_ci break; 11128c2ecf20Sopenharmony_ci case NXT2004: 11138c2ecf20Sopenharmony_ci ret = nxt2004_init(fe); 11148c2ecf20Sopenharmony_ci break; 11158c2ecf20Sopenharmony_ci default: 11168c2ecf20Sopenharmony_ci return -EINVAL; 11178c2ecf20Sopenharmony_ci break; 11188c2ecf20Sopenharmony_ci } 11198c2ecf20Sopenharmony_ci state->initialised = 1; 11208c2ecf20Sopenharmony_ci } 11218c2ecf20Sopenharmony_ci return ret; 11228c2ecf20Sopenharmony_ci} 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_cistatic int nxt200x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) 11258c2ecf20Sopenharmony_ci{ 11268c2ecf20Sopenharmony_ci fesettings->min_delay_ms = 500; 11278c2ecf20Sopenharmony_ci fesettings->step_size = 0; 11288c2ecf20Sopenharmony_ci fesettings->max_drift = 0; 11298c2ecf20Sopenharmony_ci return 0; 11308c2ecf20Sopenharmony_ci} 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_cistatic void nxt200x_release(struct dvb_frontend* fe) 11338c2ecf20Sopenharmony_ci{ 11348c2ecf20Sopenharmony_ci struct nxt200x_state* state = fe->demodulator_priv; 11358c2ecf20Sopenharmony_ci kfree(state); 11368c2ecf20Sopenharmony_ci} 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops nxt200x_ops; 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_cistruct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config, 11418c2ecf20Sopenharmony_ci struct i2c_adapter* i2c) 11428c2ecf20Sopenharmony_ci{ 11438c2ecf20Sopenharmony_ci struct nxt200x_state* state = NULL; 11448c2ecf20Sopenharmony_ci u8 buf [] = {0,0,0,0,0}; 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci /* allocate memory for the internal state */ 11478c2ecf20Sopenharmony_ci state = kzalloc(sizeof(struct nxt200x_state), GFP_KERNEL); 11488c2ecf20Sopenharmony_ci if (state == NULL) 11498c2ecf20Sopenharmony_ci goto error; 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci /* setup the state */ 11528c2ecf20Sopenharmony_ci state->config = config; 11538c2ecf20Sopenharmony_ci state->i2c = i2c; 11548c2ecf20Sopenharmony_ci state->initialised = 0; 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci /* read card id */ 11578c2ecf20Sopenharmony_ci nxt200x_readbytes(state, 0x00, buf, 5); 11588c2ecf20Sopenharmony_ci dprintk("NXT info: %*ph\n", 5, buf); 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci /* set demod chip */ 11618c2ecf20Sopenharmony_ci switch (buf[0]) { 11628c2ecf20Sopenharmony_ci case 0x04: 11638c2ecf20Sopenharmony_ci state->demod_chip = NXT2002; 11648c2ecf20Sopenharmony_ci pr_info("NXT2002 Detected\n"); 11658c2ecf20Sopenharmony_ci break; 11668c2ecf20Sopenharmony_ci case 0x05: 11678c2ecf20Sopenharmony_ci state->demod_chip = NXT2004; 11688c2ecf20Sopenharmony_ci pr_info("NXT2004 Detected\n"); 11698c2ecf20Sopenharmony_ci break; 11708c2ecf20Sopenharmony_ci default: 11718c2ecf20Sopenharmony_ci goto error; 11728c2ecf20Sopenharmony_ci } 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci /* make sure demod chip is supported */ 11758c2ecf20Sopenharmony_ci switch (state->demod_chip) { 11768c2ecf20Sopenharmony_ci case NXT2002: 11778c2ecf20Sopenharmony_ci if (buf[0] != 0x04) goto error; /* device id */ 11788c2ecf20Sopenharmony_ci if (buf[1] != 0x02) goto error; /* fab id */ 11798c2ecf20Sopenharmony_ci if (buf[2] != 0x11) goto error; /* month */ 11808c2ecf20Sopenharmony_ci if (buf[3] != 0x20) goto error; /* year msb */ 11818c2ecf20Sopenharmony_ci if (buf[4] != 0x00) goto error; /* year lsb */ 11828c2ecf20Sopenharmony_ci break; 11838c2ecf20Sopenharmony_ci case NXT2004: 11848c2ecf20Sopenharmony_ci if (buf[0] != 0x05) goto error; /* device id */ 11858c2ecf20Sopenharmony_ci break; 11868c2ecf20Sopenharmony_ci default: 11878c2ecf20Sopenharmony_ci goto error; 11888c2ecf20Sopenharmony_ci } 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci /* create dvb_frontend */ 11918c2ecf20Sopenharmony_ci memcpy(&state->frontend.ops, &nxt200x_ops, sizeof(struct dvb_frontend_ops)); 11928c2ecf20Sopenharmony_ci state->frontend.demodulator_priv = state; 11938c2ecf20Sopenharmony_ci return &state->frontend; 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_cierror: 11968c2ecf20Sopenharmony_ci kfree(state); 11978c2ecf20Sopenharmony_ci pr_err("Unknown/Unsupported NXT chip: %*ph\n", 5, buf); 11988c2ecf20Sopenharmony_ci return NULL; 11998c2ecf20Sopenharmony_ci} 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops nxt200x_ops = { 12028c2ecf20Sopenharmony_ci .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, 12038c2ecf20Sopenharmony_ci .info = { 12048c2ecf20Sopenharmony_ci .name = "Nextwave NXT200X VSB/QAM frontend", 12058c2ecf20Sopenharmony_ci .frequency_min_hz = 54 * MHz, 12068c2ecf20Sopenharmony_ci .frequency_max_hz = 860 * MHz, 12078c2ecf20Sopenharmony_ci .frequency_stepsize_hz = 166666, /* stepsize is just a guess */ 12088c2ecf20Sopenharmony_ci .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 12098c2ecf20Sopenharmony_ci FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | 12108c2ecf20Sopenharmony_ci FE_CAN_8VSB | FE_CAN_QAM_64 | FE_CAN_QAM_256 12118c2ecf20Sopenharmony_ci }, 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci .release = nxt200x_release, 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci .init = nxt200x_init, 12168c2ecf20Sopenharmony_ci .sleep = nxt200x_sleep, 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci .set_frontend = nxt200x_setup_frontend_parameters, 12198c2ecf20Sopenharmony_ci .get_tune_settings = nxt200x_get_tune_settings, 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci .read_status = nxt200x_read_status, 12228c2ecf20Sopenharmony_ci .read_ber = nxt200x_read_ber, 12238c2ecf20Sopenharmony_ci .read_signal_strength = nxt200x_read_signal_strength, 12248c2ecf20Sopenharmony_ci .read_snr = nxt200x_read_snr, 12258c2ecf20Sopenharmony_ci .read_ucblocks = nxt200x_read_ucblocks, 12268c2ecf20Sopenharmony_ci}; 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_cimodule_param(debug, int, 0644); 12298c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("NXT200X (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver"); 12328c2ecf20Sopenharmony_ciMODULE_AUTHOR("Kirk Lapray, Michael Krufky, Jean-Francois Thibert, and Taylor Jacob"); 12338c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nxt200x_attach); 12368c2ecf20Sopenharmony_ci 1237