19a0bf528SMauro Carvalho Chehab /* 29a0bf528SMauro Carvalho Chehab * Support for NXT2002 and NXT2004 - VSB/QAM 39a0bf528SMauro Carvalho Chehab * 49a0bf528SMauro Carvalho Chehab * Copyright (C) 2005 Kirk Lapray <kirk.lapray@gmail.com> 59a0bf528SMauro Carvalho Chehab * Copyright (C) 2006 Michael Krufky <mkrufky@m1k.net> 69a0bf528SMauro Carvalho Chehab * based on nxt2002 by Taylor Jacob <rtjacob@earthlink.net> 79a0bf528SMauro Carvalho Chehab * and nxt2004 by Jean-Francois Thibert <jeanfrancois@sagetv.com> 89a0bf528SMauro Carvalho Chehab * 99a0bf528SMauro Carvalho Chehab * This program is free software; you can redistribute it and/or modify 109a0bf528SMauro Carvalho Chehab * it under the terms of the GNU General Public License as published by 119a0bf528SMauro Carvalho Chehab * the Free Software Foundation; either version 2 of the License, or 129a0bf528SMauro Carvalho Chehab * (at your option) any later version. 139a0bf528SMauro Carvalho Chehab * 149a0bf528SMauro Carvalho Chehab * This program is distributed in the hope that it will be useful, 159a0bf528SMauro Carvalho Chehab * but WITHOUT ANY WARRANTY; without even the implied warranty of 169a0bf528SMauro Carvalho Chehab * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 179a0bf528SMauro Carvalho Chehab * GNU General Public License for more details. 189a0bf528SMauro Carvalho Chehab * 199a0bf528SMauro Carvalho Chehab * You should have received a copy of the GNU General Public License 209a0bf528SMauro Carvalho Chehab * along with this program; if not, write to the Free Software 219a0bf528SMauro Carvalho Chehab * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 229a0bf528SMauro Carvalho Chehab * 239a0bf528SMauro Carvalho Chehab */ 249a0bf528SMauro Carvalho Chehab 259a0bf528SMauro Carvalho Chehab /* 269a0bf528SMauro Carvalho Chehab * NOTES ABOUT THIS DRIVER 279a0bf528SMauro Carvalho Chehab * 289a0bf528SMauro Carvalho Chehab * This Linux driver supports: 299a0bf528SMauro Carvalho Chehab * B2C2/BBTI Technisat Air2PC - ATSC (NXT2002) 309a0bf528SMauro Carvalho Chehab * AverTVHD MCE A180 (NXT2004) 319a0bf528SMauro Carvalho Chehab * ATI HDTV Wonder (NXT2004) 329a0bf528SMauro Carvalho Chehab * 339a0bf528SMauro Carvalho Chehab * This driver needs external firmware. Please use the command 349a0bf528SMauro Carvalho Chehab * "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" or 359a0bf528SMauro Carvalho Chehab * "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2004" to 369a0bf528SMauro Carvalho Chehab * download/extract the appropriate firmware, and then copy it to 379a0bf528SMauro Carvalho Chehab * /usr/lib/hotplug/firmware/ or /lib/firmware/ 389a0bf528SMauro Carvalho Chehab * (depending on configuration of firmware hotplug). 399a0bf528SMauro Carvalho Chehab */ 409a0bf528SMauro Carvalho Chehab #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 419a0bf528SMauro Carvalho Chehab 428393796dSMauro Carvalho Chehab /* Max transfer size done by I2C transfer functions */ 438393796dSMauro Carvalho Chehab #define MAX_XFER_SIZE 64 448393796dSMauro Carvalho Chehab 459a0bf528SMauro Carvalho Chehab #define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw" 469a0bf528SMauro Carvalho Chehab #define NXT2004_DEFAULT_FIRMWARE "dvb-fe-nxt2004.fw" 479a0bf528SMauro Carvalho Chehab #define CRC_CCIT_MASK 0x1021 489a0bf528SMauro Carvalho Chehab 499a0bf528SMauro Carvalho Chehab #include <linux/kernel.h> 509a0bf528SMauro Carvalho Chehab #include <linux/init.h> 519a0bf528SMauro Carvalho Chehab #include <linux/module.h> 529a0bf528SMauro Carvalho Chehab #include <linux/slab.h> 539a0bf528SMauro Carvalho Chehab #include <linux/string.h> 549a0bf528SMauro Carvalho Chehab 559a0bf528SMauro Carvalho Chehab #include "dvb_frontend.h" 569a0bf528SMauro Carvalho Chehab #include "nxt200x.h" 579a0bf528SMauro Carvalho Chehab 589a0bf528SMauro Carvalho Chehab struct nxt200x_state { 599a0bf528SMauro Carvalho Chehab 609a0bf528SMauro Carvalho Chehab struct i2c_adapter* i2c; 619a0bf528SMauro Carvalho Chehab const struct nxt200x_config* config; 629a0bf528SMauro Carvalho Chehab struct dvb_frontend frontend; 639a0bf528SMauro Carvalho Chehab 649a0bf528SMauro Carvalho Chehab /* demodulator private data */ 659a0bf528SMauro Carvalho Chehab nxt_chip_type demod_chip; 669a0bf528SMauro Carvalho Chehab u8 initialised:1; 679a0bf528SMauro Carvalho Chehab }; 689a0bf528SMauro Carvalho Chehab 699a0bf528SMauro Carvalho Chehab static int debug; 709a0bf528SMauro Carvalho Chehab #define dprintk(args...) do { if (debug) pr_debug(args); } while (0) 719a0bf528SMauro Carvalho Chehab 729a0bf528SMauro Carvalho Chehab static int i2c_writebytes (struct nxt200x_state* state, u8 addr, u8 *buf, u8 len) 739a0bf528SMauro Carvalho Chehab { 749a0bf528SMauro Carvalho Chehab int err; 759a0bf528SMauro Carvalho Chehab struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = len }; 769a0bf528SMauro Carvalho Chehab 779a0bf528SMauro Carvalho Chehab if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { 789a0bf528SMauro Carvalho Chehab pr_warn("%s: i2c write error (addr 0x%02x, err == %i)\n", 799a0bf528SMauro Carvalho Chehab __func__, addr, err); 809a0bf528SMauro Carvalho Chehab return -EREMOTEIO; 819a0bf528SMauro Carvalho Chehab } 829a0bf528SMauro Carvalho Chehab return 0; 839a0bf528SMauro Carvalho Chehab } 849a0bf528SMauro Carvalho Chehab 859a0bf528SMauro Carvalho Chehab static int i2c_readbytes(struct nxt200x_state *state, u8 addr, u8 *buf, u8 len) 869a0bf528SMauro Carvalho Chehab { 879a0bf528SMauro Carvalho Chehab int err; 889a0bf528SMauro Carvalho Chehab struct i2c_msg msg = { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len }; 899a0bf528SMauro Carvalho Chehab 909a0bf528SMauro Carvalho Chehab if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { 919a0bf528SMauro Carvalho Chehab pr_warn("%s: i2c read error (addr 0x%02x, err == %i)\n", 929a0bf528SMauro Carvalho Chehab __func__, addr, err); 939a0bf528SMauro Carvalho Chehab return -EREMOTEIO; 949a0bf528SMauro Carvalho Chehab } 959a0bf528SMauro Carvalho Chehab return 0; 969a0bf528SMauro Carvalho Chehab } 979a0bf528SMauro Carvalho Chehab 989a0bf528SMauro Carvalho Chehab static int nxt200x_writebytes (struct nxt200x_state* state, u8 reg, 999a0bf528SMauro Carvalho Chehab const u8 *buf, u8 len) 1009a0bf528SMauro Carvalho Chehab { 1018393796dSMauro Carvalho Chehab u8 buf2[MAX_XFER_SIZE]; 1029a0bf528SMauro Carvalho Chehab int err; 1039a0bf528SMauro Carvalho Chehab struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf2, .len = len + 1 }; 1049a0bf528SMauro Carvalho Chehab 1058393796dSMauro Carvalho Chehab if (1 + len > sizeof(buf2)) { 1068393796dSMauro Carvalho Chehab pr_warn("%s: i2c wr reg=%04x: len=%d is too big!\n", 1078393796dSMauro Carvalho Chehab __func__, reg, len); 1088393796dSMauro Carvalho Chehab return -EINVAL; 1098393796dSMauro Carvalho Chehab } 1108393796dSMauro Carvalho Chehab 1119a0bf528SMauro Carvalho Chehab buf2[0] = reg; 1129a0bf528SMauro Carvalho Chehab memcpy(&buf2[1], buf, len); 1139a0bf528SMauro Carvalho Chehab 1149a0bf528SMauro Carvalho Chehab if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { 1159a0bf528SMauro Carvalho Chehab pr_warn("%s: i2c write error (addr 0x%02x, err == %i)\n", 1169a0bf528SMauro Carvalho Chehab __func__, state->config->demod_address, err); 1179a0bf528SMauro Carvalho Chehab return -EREMOTEIO; 1189a0bf528SMauro Carvalho Chehab } 1199a0bf528SMauro Carvalho Chehab return 0; 1209a0bf528SMauro Carvalho Chehab } 1219a0bf528SMauro Carvalho Chehab 1229a0bf528SMauro Carvalho Chehab static int nxt200x_readbytes(struct nxt200x_state *state, u8 reg, u8 *buf, u8 len) 1239a0bf528SMauro Carvalho Chehab { 1249a0bf528SMauro Carvalho Chehab u8 reg2 [] = { reg }; 1259a0bf528SMauro Carvalho Chehab 1269a0bf528SMauro Carvalho Chehab struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = reg2, .len = 1 }, 1279a0bf528SMauro Carvalho Chehab { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf, .len = len } }; 1289a0bf528SMauro Carvalho Chehab 1299a0bf528SMauro Carvalho Chehab int err; 1309a0bf528SMauro Carvalho Chehab 1319a0bf528SMauro Carvalho Chehab if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) { 1329a0bf528SMauro Carvalho Chehab pr_warn("%s: i2c read error (addr 0x%02x, err == %i)\n", 1339a0bf528SMauro Carvalho Chehab __func__, state->config->demod_address, err); 1349a0bf528SMauro Carvalho Chehab return -EREMOTEIO; 1359a0bf528SMauro Carvalho Chehab } 1369a0bf528SMauro Carvalho Chehab return 0; 1379a0bf528SMauro Carvalho Chehab } 1389a0bf528SMauro Carvalho Chehab 1399a0bf528SMauro Carvalho Chehab static u16 nxt200x_crc(u16 crc, u8 c) 1409a0bf528SMauro Carvalho Chehab { 1419a0bf528SMauro Carvalho Chehab u8 i; 1429a0bf528SMauro Carvalho Chehab u16 input = (u16) c & 0xFF; 1439a0bf528SMauro Carvalho Chehab 1449a0bf528SMauro Carvalho Chehab input<<=8; 1459a0bf528SMauro Carvalho Chehab for(i=0; i<8; i++) { 1469a0bf528SMauro Carvalho Chehab if((crc^input) & 0x8000) 1479a0bf528SMauro Carvalho Chehab crc=(crc<<1)^CRC_CCIT_MASK; 1489a0bf528SMauro Carvalho Chehab else 1499a0bf528SMauro Carvalho Chehab crc<<=1; 1509a0bf528SMauro Carvalho Chehab input<<=1; 1519a0bf528SMauro Carvalho Chehab } 1529a0bf528SMauro Carvalho Chehab return crc; 1539a0bf528SMauro Carvalho Chehab } 1549a0bf528SMauro Carvalho Chehab 1559a0bf528SMauro Carvalho Chehab static int nxt200x_writereg_multibyte (struct nxt200x_state* state, u8 reg, u8* data, u8 len) 1569a0bf528SMauro Carvalho Chehab { 1579a0bf528SMauro Carvalho Chehab u8 attr, len2, buf; 1589a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__); 1599a0bf528SMauro Carvalho Chehab 1609a0bf528SMauro Carvalho Chehab /* set mutli register register */ 1619a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x35, ®, 1); 1629a0bf528SMauro Carvalho Chehab 1639a0bf528SMauro Carvalho Chehab /* send the actual data */ 1649a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x36, data, len); 1659a0bf528SMauro Carvalho Chehab 1669a0bf528SMauro Carvalho Chehab switch (state->demod_chip) { 1679a0bf528SMauro Carvalho Chehab case NXT2002: 1689a0bf528SMauro Carvalho Chehab len2 = len; 1699a0bf528SMauro Carvalho Chehab buf = 0x02; 1709a0bf528SMauro Carvalho Chehab break; 1719a0bf528SMauro Carvalho Chehab case NXT2004: 1729a0bf528SMauro Carvalho Chehab /* probably not right, but gives correct values */ 1739a0bf528SMauro Carvalho Chehab attr = 0x02; 1749a0bf528SMauro Carvalho Chehab if (reg & 0x80) { 1759a0bf528SMauro Carvalho Chehab attr = attr << 1; 1769a0bf528SMauro Carvalho Chehab if (reg & 0x04) 1779a0bf528SMauro Carvalho Chehab attr = attr >> 1; 1789a0bf528SMauro Carvalho Chehab } 1799a0bf528SMauro Carvalho Chehab /* set write bit */ 1809a0bf528SMauro Carvalho Chehab len2 = ((attr << 4) | 0x10) | len; 1819a0bf528SMauro Carvalho Chehab buf = 0x80; 1829a0bf528SMauro Carvalho Chehab break; 1839a0bf528SMauro Carvalho Chehab default: 1849a0bf528SMauro Carvalho Chehab return -EINVAL; 1859a0bf528SMauro Carvalho Chehab break; 1869a0bf528SMauro Carvalho Chehab } 1879a0bf528SMauro Carvalho Chehab 1889a0bf528SMauro Carvalho Chehab /* set multi register length */ 1899a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x34, &len2, 1); 1909a0bf528SMauro Carvalho Chehab 1919a0bf528SMauro Carvalho Chehab /* toggle the multireg write bit */ 1929a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x21, &buf, 1); 1939a0bf528SMauro Carvalho Chehab 1949a0bf528SMauro Carvalho Chehab nxt200x_readbytes(state, 0x21, &buf, 1); 1959a0bf528SMauro Carvalho Chehab 1969a0bf528SMauro Carvalho Chehab switch (state->demod_chip) { 1979a0bf528SMauro Carvalho Chehab case NXT2002: 1989a0bf528SMauro Carvalho Chehab if ((buf & 0x02) == 0) 1999a0bf528SMauro Carvalho Chehab return 0; 2009a0bf528SMauro Carvalho Chehab break; 2019a0bf528SMauro Carvalho Chehab case NXT2004: 2029a0bf528SMauro Carvalho Chehab if (buf == 0) 2039a0bf528SMauro Carvalho Chehab return 0; 2049a0bf528SMauro Carvalho Chehab break; 2059a0bf528SMauro Carvalho Chehab default: 2069a0bf528SMauro Carvalho Chehab return -EINVAL; 2079a0bf528SMauro Carvalho Chehab break; 2089a0bf528SMauro Carvalho Chehab } 2099a0bf528SMauro Carvalho Chehab 2109a0bf528SMauro Carvalho Chehab pr_warn("Error writing multireg register 0x%02X\n", reg); 2119a0bf528SMauro Carvalho Chehab 2129a0bf528SMauro Carvalho Chehab return 0; 2139a0bf528SMauro Carvalho Chehab } 2149a0bf528SMauro Carvalho Chehab 2159a0bf528SMauro Carvalho Chehab static int nxt200x_readreg_multibyte (struct nxt200x_state* state, u8 reg, u8* data, u8 len) 2169a0bf528SMauro Carvalho Chehab { 2179a0bf528SMauro Carvalho Chehab int i; 2189a0bf528SMauro Carvalho Chehab u8 buf, len2, attr; 2199a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__); 2209a0bf528SMauro Carvalho Chehab 2219a0bf528SMauro Carvalho Chehab /* set mutli register register */ 2229a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x35, ®, 1); 2239a0bf528SMauro Carvalho Chehab 2249a0bf528SMauro Carvalho Chehab switch (state->demod_chip) { 2259a0bf528SMauro Carvalho Chehab case NXT2002: 2269a0bf528SMauro Carvalho Chehab /* set multi register length */ 2279a0bf528SMauro Carvalho Chehab len2 = len & 0x80; 2289a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x34, &len2, 1); 2299a0bf528SMauro Carvalho Chehab 2309a0bf528SMauro Carvalho Chehab /* read the actual data */ 2319a0bf528SMauro Carvalho Chehab nxt200x_readbytes(state, reg, data, len); 2329a0bf528SMauro Carvalho Chehab return 0; 2339a0bf528SMauro Carvalho Chehab break; 2349a0bf528SMauro Carvalho Chehab case NXT2004: 2359a0bf528SMauro Carvalho Chehab /* probably not right, but gives correct values */ 2369a0bf528SMauro Carvalho Chehab attr = 0x02; 2379a0bf528SMauro Carvalho Chehab if (reg & 0x80) { 2389a0bf528SMauro Carvalho Chehab attr = attr << 1; 2399a0bf528SMauro Carvalho Chehab if (reg & 0x04) 2409a0bf528SMauro Carvalho Chehab attr = attr >> 1; 2419a0bf528SMauro Carvalho Chehab } 2429a0bf528SMauro Carvalho Chehab 2439a0bf528SMauro Carvalho Chehab /* set multi register length */ 2449a0bf528SMauro Carvalho Chehab len2 = (attr << 4) | len; 2459a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x34, &len2, 1); 2469a0bf528SMauro Carvalho Chehab 2479a0bf528SMauro Carvalho Chehab /* toggle the multireg bit*/ 2489a0bf528SMauro Carvalho Chehab buf = 0x80; 2499a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x21, &buf, 1); 2509a0bf528SMauro Carvalho Chehab 2519a0bf528SMauro Carvalho Chehab /* read the actual data */ 2529a0bf528SMauro Carvalho Chehab for(i = 0; i < len; i++) { 2539a0bf528SMauro Carvalho Chehab nxt200x_readbytes(state, 0x36 + i, &data[i], 1); 2549a0bf528SMauro Carvalho Chehab } 2559a0bf528SMauro Carvalho Chehab return 0; 2569a0bf528SMauro Carvalho Chehab break; 2579a0bf528SMauro Carvalho Chehab default: 2589a0bf528SMauro Carvalho Chehab return -EINVAL; 2599a0bf528SMauro Carvalho Chehab break; 2609a0bf528SMauro Carvalho Chehab } 2619a0bf528SMauro Carvalho Chehab } 2629a0bf528SMauro Carvalho Chehab 2639a0bf528SMauro Carvalho Chehab static void nxt200x_microcontroller_stop (struct nxt200x_state* state) 2649a0bf528SMauro Carvalho Chehab { 2659a0bf528SMauro Carvalho Chehab u8 buf, stopval, counter = 0; 2669a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__); 2679a0bf528SMauro Carvalho Chehab 2689a0bf528SMauro Carvalho Chehab /* set correct stop value */ 2699a0bf528SMauro Carvalho Chehab switch (state->demod_chip) { 2709a0bf528SMauro Carvalho Chehab case NXT2002: 2719a0bf528SMauro Carvalho Chehab stopval = 0x40; 2729a0bf528SMauro Carvalho Chehab break; 2739a0bf528SMauro Carvalho Chehab case NXT2004: 2749a0bf528SMauro Carvalho Chehab stopval = 0x10; 2759a0bf528SMauro Carvalho Chehab break; 2769a0bf528SMauro Carvalho Chehab default: 2779a0bf528SMauro Carvalho Chehab stopval = 0; 2789a0bf528SMauro Carvalho Chehab break; 2799a0bf528SMauro Carvalho Chehab } 2809a0bf528SMauro Carvalho Chehab 2819a0bf528SMauro Carvalho Chehab buf = 0x80; 2829a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x22, &buf, 1); 2839a0bf528SMauro Carvalho Chehab 2849a0bf528SMauro Carvalho Chehab while (counter < 20) { 2859a0bf528SMauro Carvalho Chehab nxt200x_readbytes(state, 0x31, &buf, 1); 2869a0bf528SMauro Carvalho Chehab if (buf & stopval) 2879a0bf528SMauro Carvalho Chehab return; 2889a0bf528SMauro Carvalho Chehab msleep(10); 2899a0bf528SMauro Carvalho Chehab counter++; 2909a0bf528SMauro Carvalho Chehab } 2919a0bf528SMauro Carvalho Chehab 2929a0bf528SMauro Carvalho Chehab pr_warn("Timeout waiting for nxt200x to stop. This is ok after " 2939a0bf528SMauro Carvalho Chehab "firmware upload.\n"); 2949a0bf528SMauro Carvalho Chehab return; 2959a0bf528SMauro Carvalho Chehab } 2969a0bf528SMauro Carvalho Chehab 2979a0bf528SMauro Carvalho Chehab static void nxt200x_microcontroller_start (struct nxt200x_state* state) 2989a0bf528SMauro Carvalho Chehab { 2999a0bf528SMauro Carvalho Chehab u8 buf; 3009a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__); 3019a0bf528SMauro Carvalho Chehab 3029a0bf528SMauro Carvalho Chehab buf = 0x00; 3039a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x22, &buf, 1); 3049a0bf528SMauro Carvalho Chehab } 3059a0bf528SMauro Carvalho Chehab 3069a0bf528SMauro Carvalho Chehab static void nxt2004_microcontroller_init (struct nxt200x_state* state) 3079a0bf528SMauro Carvalho Chehab { 3089a0bf528SMauro Carvalho Chehab u8 buf[9]; 3099a0bf528SMauro Carvalho Chehab u8 counter = 0; 3109a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__); 3119a0bf528SMauro Carvalho Chehab 3129a0bf528SMauro Carvalho Chehab buf[0] = 0x00; 3139a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x2b, buf, 1); 3149a0bf528SMauro Carvalho Chehab buf[0] = 0x70; 3159a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x34, buf, 1); 3169a0bf528SMauro Carvalho Chehab buf[0] = 0x04; 3179a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x35, buf, 1); 3189a0bf528SMauro Carvalho Chehab buf[0] = 0x01; buf[1] = 0x23; buf[2] = 0x45; buf[3] = 0x67; buf[4] = 0x89; 3199a0bf528SMauro Carvalho Chehab buf[5] = 0xAB; buf[6] = 0xCD; buf[7] = 0xEF; buf[8] = 0xC0; 3209a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x36, buf, 9); 3219a0bf528SMauro Carvalho Chehab buf[0] = 0x80; 3229a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x21, buf, 1); 3239a0bf528SMauro Carvalho Chehab 3249a0bf528SMauro Carvalho Chehab while (counter < 20) { 3259a0bf528SMauro Carvalho Chehab nxt200x_readbytes(state, 0x21, buf, 1); 3269a0bf528SMauro Carvalho Chehab if (buf[0] == 0) 3279a0bf528SMauro Carvalho Chehab return; 3289a0bf528SMauro Carvalho Chehab msleep(10); 3299a0bf528SMauro Carvalho Chehab counter++; 3309a0bf528SMauro Carvalho Chehab } 3319a0bf528SMauro Carvalho Chehab 3329a0bf528SMauro Carvalho Chehab pr_warn("Timeout waiting for nxt2004 to init.\n"); 3339a0bf528SMauro Carvalho Chehab 3349a0bf528SMauro Carvalho Chehab return; 3359a0bf528SMauro Carvalho Chehab } 3369a0bf528SMauro Carvalho Chehab 3379a0bf528SMauro Carvalho Chehab static int nxt200x_writetuner (struct nxt200x_state* state, u8* data) 3389a0bf528SMauro Carvalho Chehab { 3399a0bf528SMauro Carvalho Chehab u8 buf, count = 0; 3409a0bf528SMauro Carvalho Chehab 3419a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__); 3429a0bf528SMauro Carvalho Chehab 3439a0bf528SMauro Carvalho Chehab dprintk("Tuner Bytes: %*ph\n", 4, data + 1); 3449a0bf528SMauro Carvalho Chehab 3459a0bf528SMauro Carvalho Chehab /* if NXT2004, write directly to tuner. if NXT2002, write through NXT chip. 3469a0bf528SMauro Carvalho Chehab * direct write is required for Philips TUV1236D and ALPS TDHU2 */ 3479a0bf528SMauro Carvalho Chehab switch (state->demod_chip) { 3489a0bf528SMauro Carvalho Chehab case NXT2004: 3499a0bf528SMauro Carvalho Chehab if (i2c_writebytes(state, data[0], data+1, 4)) 3509a0bf528SMauro Carvalho Chehab pr_warn("error writing to tuner\n"); 3519a0bf528SMauro Carvalho Chehab /* wait until we have a lock */ 3529a0bf528SMauro Carvalho Chehab while (count < 20) { 3539a0bf528SMauro Carvalho Chehab i2c_readbytes(state, data[0], &buf, 1); 3549a0bf528SMauro Carvalho Chehab if (buf & 0x40) 3559a0bf528SMauro Carvalho Chehab return 0; 3569a0bf528SMauro Carvalho Chehab msleep(100); 3579a0bf528SMauro Carvalho Chehab count++; 3589a0bf528SMauro Carvalho Chehab } 3599a0bf528SMauro Carvalho Chehab pr_warn("timeout waiting for tuner lock\n"); 3609a0bf528SMauro Carvalho Chehab break; 3619a0bf528SMauro Carvalho Chehab case NXT2002: 3629a0bf528SMauro Carvalho Chehab /* set the i2c transfer speed to the tuner */ 3639a0bf528SMauro Carvalho Chehab buf = 0x03; 3649a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x20, &buf, 1); 3659a0bf528SMauro Carvalho Chehab 3669a0bf528SMauro Carvalho Chehab /* setup to transfer 4 bytes via i2c */ 3679a0bf528SMauro Carvalho Chehab buf = 0x04; 3689a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x34, &buf, 1); 3699a0bf528SMauro Carvalho Chehab 3709a0bf528SMauro Carvalho Chehab /* write actual tuner bytes */ 3719a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x36, data+1, 4); 3729a0bf528SMauro Carvalho Chehab 3739a0bf528SMauro Carvalho Chehab /* set tuner i2c address */ 3749a0bf528SMauro Carvalho Chehab buf = data[0] << 1; 3759a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x35, &buf, 1); 3769a0bf528SMauro Carvalho Chehab 3779a0bf528SMauro Carvalho Chehab /* write UC Opmode to begin transfer */ 3789a0bf528SMauro Carvalho Chehab buf = 0x80; 3799a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x21, &buf, 1); 3809a0bf528SMauro Carvalho Chehab 3819a0bf528SMauro Carvalho Chehab while (count < 20) { 3829a0bf528SMauro Carvalho Chehab nxt200x_readbytes(state, 0x21, &buf, 1); 3839a0bf528SMauro Carvalho Chehab if ((buf & 0x80)== 0x00) 3849a0bf528SMauro Carvalho Chehab return 0; 3859a0bf528SMauro Carvalho Chehab msleep(100); 3869a0bf528SMauro Carvalho Chehab count++; 3879a0bf528SMauro Carvalho Chehab } 3889a0bf528SMauro Carvalho Chehab pr_warn("timeout error writing to tuner\n"); 3899a0bf528SMauro Carvalho Chehab break; 3909a0bf528SMauro Carvalho Chehab default: 3919a0bf528SMauro Carvalho Chehab return -EINVAL; 3929a0bf528SMauro Carvalho Chehab break; 3939a0bf528SMauro Carvalho Chehab } 3949a0bf528SMauro Carvalho Chehab return 0; 3959a0bf528SMauro Carvalho Chehab } 3969a0bf528SMauro Carvalho Chehab 3979a0bf528SMauro Carvalho Chehab static void nxt200x_agc_reset(struct nxt200x_state* state) 3989a0bf528SMauro Carvalho Chehab { 3999a0bf528SMauro Carvalho Chehab u8 buf; 4009a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__); 4019a0bf528SMauro Carvalho Chehab 4029a0bf528SMauro Carvalho Chehab switch (state->demod_chip) { 4039a0bf528SMauro Carvalho Chehab case NXT2002: 4049a0bf528SMauro Carvalho Chehab buf = 0x08; 4059a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x08, &buf, 1); 4069a0bf528SMauro Carvalho Chehab buf = 0x00; 4079a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x08, &buf, 1); 4089a0bf528SMauro Carvalho Chehab break; 4099a0bf528SMauro Carvalho Chehab case NXT2004: 4109a0bf528SMauro Carvalho Chehab nxt200x_readreg_multibyte(state, 0x08, &buf, 1); 4119a0bf528SMauro Carvalho Chehab buf = 0x08; 4129a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x08, &buf, 1); 4139a0bf528SMauro Carvalho Chehab buf = 0x00; 4149a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x08, &buf, 1); 4159a0bf528SMauro Carvalho Chehab break; 4169a0bf528SMauro Carvalho Chehab default: 4179a0bf528SMauro Carvalho Chehab break; 4189a0bf528SMauro Carvalho Chehab } 4199a0bf528SMauro Carvalho Chehab return; 4209a0bf528SMauro Carvalho Chehab } 4219a0bf528SMauro Carvalho Chehab 4229a0bf528SMauro Carvalho Chehab static int nxt2002_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) 4239a0bf528SMauro Carvalho Chehab { 4249a0bf528SMauro Carvalho Chehab 4259a0bf528SMauro Carvalho Chehab struct nxt200x_state* state = fe->demodulator_priv; 4269a0bf528SMauro Carvalho Chehab u8 buf[3], written = 0, chunkpos = 0; 4279a0bf528SMauro Carvalho Chehab u16 rambase, position, crc = 0; 4289a0bf528SMauro Carvalho Chehab 4299a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__); 4309a0bf528SMauro Carvalho Chehab dprintk("Firmware is %zu bytes\n", fw->size); 4319a0bf528SMauro Carvalho Chehab 4329a0bf528SMauro Carvalho Chehab /* Get the RAM base for this nxt2002 */ 4339a0bf528SMauro Carvalho Chehab nxt200x_readbytes(state, 0x10, buf, 1); 4349a0bf528SMauro Carvalho Chehab 4359a0bf528SMauro Carvalho Chehab if (buf[0] & 0x10) 4369a0bf528SMauro Carvalho Chehab rambase = 0x1000; 4379a0bf528SMauro Carvalho Chehab else 4389a0bf528SMauro Carvalho Chehab rambase = 0x0000; 4399a0bf528SMauro Carvalho Chehab 4409a0bf528SMauro Carvalho Chehab dprintk("rambase on this nxt2002 is %04X\n", rambase); 4419a0bf528SMauro Carvalho Chehab 4429a0bf528SMauro Carvalho Chehab /* Hold the micro in reset while loading firmware */ 4439a0bf528SMauro Carvalho Chehab buf[0] = 0x80; 4449a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x2B, buf, 1); 4459a0bf528SMauro Carvalho Chehab 4469a0bf528SMauro Carvalho Chehab for (position = 0; position < fw->size; position++) { 4479a0bf528SMauro Carvalho Chehab if (written == 0) { 4489a0bf528SMauro Carvalho Chehab crc = 0; 4499a0bf528SMauro Carvalho Chehab chunkpos = 0x28; 4509a0bf528SMauro Carvalho Chehab buf[0] = ((rambase + position) >> 8); 4519a0bf528SMauro Carvalho Chehab buf[1] = (rambase + position) & 0xFF; 4529a0bf528SMauro Carvalho Chehab buf[2] = 0x81; 4539a0bf528SMauro Carvalho Chehab /* write starting address */ 4549a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x29, buf, 3); 4559a0bf528SMauro Carvalho Chehab } 4569a0bf528SMauro Carvalho Chehab written++; 4579a0bf528SMauro Carvalho Chehab chunkpos++; 4589a0bf528SMauro Carvalho Chehab 4599a0bf528SMauro Carvalho Chehab if ((written % 4) == 0) 4609a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, chunkpos, &fw->data[position-3], 4); 4619a0bf528SMauro Carvalho Chehab 4629a0bf528SMauro Carvalho Chehab crc = nxt200x_crc(crc, fw->data[position]); 4639a0bf528SMauro Carvalho Chehab 4649a0bf528SMauro Carvalho Chehab if ((written == 255) || (position+1 == fw->size)) { 4659a0bf528SMauro Carvalho Chehab /* write remaining bytes of firmware */ 4669a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, chunkpos+4-(written %4), 4679a0bf528SMauro Carvalho Chehab &fw->data[position-(written %4) + 1], 4689a0bf528SMauro Carvalho Chehab written %4); 4699a0bf528SMauro Carvalho Chehab buf[0] = crc << 8; 4709a0bf528SMauro Carvalho Chehab buf[1] = crc & 0xFF; 4719a0bf528SMauro Carvalho Chehab 4729a0bf528SMauro Carvalho Chehab /* write crc */ 4739a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x2C, buf, 2); 4749a0bf528SMauro Carvalho Chehab 4759a0bf528SMauro Carvalho Chehab /* do a read to stop things */ 4769a0bf528SMauro Carvalho Chehab nxt200x_readbytes(state, 0x2A, buf, 1); 4779a0bf528SMauro Carvalho Chehab 4789a0bf528SMauro Carvalho Chehab /* set transfer mode to complete */ 4799a0bf528SMauro Carvalho Chehab buf[0] = 0x80; 4809a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x2B, buf, 1); 4819a0bf528SMauro Carvalho Chehab 4829a0bf528SMauro Carvalho Chehab written = 0; 4839a0bf528SMauro Carvalho Chehab } 4849a0bf528SMauro Carvalho Chehab } 4859a0bf528SMauro Carvalho Chehab 4869a0bf528SMauro Carvalho Chehab return 0; 4879a0bf528SMauro Carvalho Chehab }; 4889a0bf528SMauro Carvalho Chehab 4899a0bf528SMauro Carvalho Chehab static int nxt2004_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) 4909a0bf528SMauro Carvalho Chehab { 4919a0bf528SMauro Carvalho Chehab 4929a0bf528SMauro Carvalho Chehab struct nxt200x_state* state = fe->demodulator_priv; 4939a0bf528SMauro Carvalho Chehab u8 buf[3]; 4949a0bf528SMauro Carvalho Chehab u16 rambase, position, crc=0; 4959a0bf528SMauro Carvalho Chehab 4969a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__); 4979a0bf528SMauro Carvalho Chehab dprintk("Firmware is %zu bytes\n", fw->size); 4989a0bf528SMauro Carvalho Chehab 4999a0bf528SMauro Carvalho Chehab /* set rambase */ 5009a0bf528SMauro Carvalho Chehab rambase = 0x1000; 5019a0bf528SMauro Carvalho Chehab 5029a0bf528SMauro Carvalho Chehab /* hold the micro in reset while loading firmware */ 5039a0bf528SMauro Carvalho Chehab buf[0] = 0x80; 5049a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x2B, buf,1); 5059a0bf528SMauro Carvalho Chehab 5069a0bf528SMauro Carvalho Chehab /* calculate firmware CRC */ 5079a0bf528SMauro Carvalho Chehab for (position = 0; position < fw->size; position++) { 5089a0bf528SMauro Carvalho Chehab crc = nxt200x_crc(crc, fw->data[position]); 5099a0bf528SMauro Carvalho Chehab } 5109a0bf528SMauro Carvalho Chehab 5119a0bf528SMauro Carvalho Chehab buf[0] = rambase >> 8; 5129a0bf528SMauro Carvalho Chehab buf[1] = rambase & 0xFF; 5139a0bf528SMauro Carvalho Chehab buf[2] = 0x81; 5149a0bf528SMauro Carvalho Chehab /* write starting address */ 5159a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state,0x29,buf,3); 5169a0bf528SMauro Carvalho Chehab 5179a0bf528SMauro Carvalho Chehab for (position = 0; position < fw->size;) { 5189a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x2C, &fw->data[position], 5199a0bf528SMauro Carvalho Chehab fw->size-position > 255 ? 255 : fw->size-position); 5209a0bf528SMauro Carvalho Chehab position += (fw->size-position > 255 ? 255 : fw->size-position); 5219a0bf528SMauro Carvalho Chehab } 5229a0bf528SMauro Carvalho Chehab buf[0] = crc >> 8; 5239a0bf528SMauro Carvalho Chehab buf[1] = crc & 0xFF; 5249a0bf528SMauro Carvalho Chehab 5259a0bf528SMauro Carvalho Chehab dprintk("firmware crc is 0x%02X 0x%02X\n", buf[0], buf[1]); 5269a0bf528SMauro Carvalho Chehab 5279a0bf528SMauro Carvalho Chehab /* write crc */ 5289a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x2C, buf,2); 5299a0bf528SMauro Carvalho Chehab 5309a0bf528SMauro Carvalho Chehab /* do a read to stop things */ 5319a0bf528SMauro Carvalho Chehab nxt200x_readbytes(state, 0x2C, buf, 1); 5329a0bf528SMauro Carvalho Chehab 5339a0bf528SMauro Carvalho Chehab /* set transfer mode to complete */ 5349a0bf528SMauro Carvalho Chehab buf[0] = 0x80; 5359a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x2B, buf,1); 5369a0bf528SMauro Carvalho Chehab 5379a0bf528SMauro Carvalho Chehab return 0; 5389a0bf528SMauro Carvalho Chehab }; 5399a0bf528SMauro Carvalho Chehab 5409a0bf528SMauro Carvalho Chehab static int nxt200x_setup_frontend_parameters(struct dvb_frontend *fe) 5419a0bf528SMauro Carvalho Chehab { 5429a0bf528SMauro Carvalho Chehab struct dtv_frontend_properties *p = &fe->dtv_property_cache; 5439a0bf528SMauro Carvalho Chehab struct nxt200x_state* state = fe->demodulator_priv; 5449a0bf528SMauro Carvalho Chehab u8 buf[5]; 5459a0bf528SMauro Carvalho Chehab 5469a0bf528SMauro Carvalho Chehab /* stop the micro first */ 5479a0bf528SMauro Carvalho Chehab nxt200x_microcontroller_stop(state); 5489a0bf528SMauro Carvalho Chehab 5499a0bf528SMauro Carvalho Chehab if (state->demod_chip == NXT2004) { 5509a0bf528SMauro Carvalho Chehab /* make sure demod is set to digital */ 5519a0bf528SMauro Carvalho Chehab buf[0] = 0x04; 5529a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x14, buf, 1); 5539a0bf528SMauro Carvalho Chehab buf[0] = 0x00; 5549a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x17, buf, 1); 5559a0bf528SMauro Carvalho Chehab } 5569a0bf528SMauro Carvalho Chehab 5579a0bf528SMauro Carvalho Chehab /* set additional params */ 5589a0bf528SMauro Carvalho Chehab switch (p->modulation) { 5599a0bf528SMauro Carvalho Chehab case QAM_64: 5609a0bf528SMauro Carvalho Chehab case QAM_256: 5619a0bf528SMauro Carvalho Chehab /* Set punctured clock for QAM */ 5629a0bf528SMauro Carvalho Chehab /* This is just a guess since I am unable to test it */ 5639a0bf528SMauro Carvalho Chehab if (state->config->set_ts_params) 5649a0bf528SMauro Carvalho Chehab state->config->set_ts_params(fe, 1); 5659a0bf528SMauro Carvalho Chehab break; 5669a0bf528SMauro Carvalho Chehab case VSB_8: 5679a0bf528SMauro Carvalho Chehab /* Set non-punctured clock for VSB */ 5689a0bf528SMauro Carvalho Chehab if (state->config->set_ts_params) 5699a0bf528SMauro Carvalho Chehab state->config->set_ts_params(fe, 0); 5709a0bf528SMauro Carvalho Chehab break; 5719a0bf528SMauro Carvalho Chehab default: 5729a0bf528SMauro Carvalho Chehab return -EINVAL; 5739a0bf528SMauro Carvalho Chehab break; 5749a0bf528SMauro Carvalho Chehab } 5759a0bf528SMauro Carvalho Chehab 5769a0bf528SMauro Carvalho Chehab if (fe->ops.tuner_ops.calc_regs) { 5779a0bf528SMauro Carvalho Chehab /* get tuning information */ 5789a0bf528SMauro Carvalho Chehab fe->ops.tuner_ops.calc_regs(fe, buf, 5); 5799a0bf528SMauro Carvalho Chehab 5809a0bf528SMauro Carvalho Chehab /* write frequency information */ 5819a0bf528SMauro Carvalho Chehab nxt200x_writetuner(state, buf); 5829a0bf528SMauro Carvalho Chehab } 5839a0bf528SMauro Carvalho Chehab 5849a0bf528SMauro Carvalho Chehab /* reset the agc now that tuning has been completed */ 5859a0bf528SMauro Carvalho Chehab nxt200x_agc_reset(state); 5869a0bf528SMauro Carvalho Chehab 5879a0bf528SMauro Carvalho Chehab /* set target power level */ 5889a0bf528SMauro Carvalho Chehab switch (p->modulation) { 5899a0bf528SMauro Carvalho Chehab case QAM_64: 5909a0bf528SMauro Carvalho Chehab case QAM_256: 5919a0bf528SMauro Carvalho Chehab buf[0] = 0x74; 5929a0bf528SMauro Carvalho Chehab break; 5939a0bf528SMauro Carvalho Chehab case VSB_8: 5949a0bf528SMauro Carvalho Chehab buf[0] = 0x70; 5959a0bf528SMauro Carvalho Chehab break; 5969a0bf528SMauro Carvalho Chehab default: 5979a0bf528SMauro Carvalho Chehab return -EINVAL; 5989a0bf528SMauro Carvalho Chehab break; 5999a0bf528SMauro Carvalho Chehab } 6009a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x42, buf, 1); 6019a0bf528SMauro Carvalho Chehab 6029a0bf528SMauro Carvalho Chehab /* configure sdm */ 6039a0bf528SMauro Carvalho Chehab switch (state->demod_chip) { 6049a0bf528SMauro Carvalho Chehab case NXT2002: 6059a0bf528SMauro Carvalho Chehab buf[0] = 0x87; 6069a0bf528SMauro Carvalho Chehab break; 6079a0bf528SMauro Carvalho Chehab case NXT2004: 6089a0bf528SMauro Carvalho Chehab buf[0] = 0x07; 6099a0bf528SMauro Carvalho Chehab break; 6109a0bf528SMauro Carvalho Chehab default: 6119a0bf528SMauro Carvalho Chehab return -EINVAL; 6129a0bf528SMauro Carvalho Chehab break; 6139a0bf528SMauro Carvalho Chehab } 6149a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x57, buf, 1); 6159a0bf528SMauro Carvalho Chehab 6169a0bf528SMauro Carvalho Chehab /* write sdm1 input */ 6179a0bf528SMauro Carvalho Chehab buf[0] = 0x10; 6189a0bf528SMauro Carvalho Chehab buf[1] = 0x00; 6199a0bf528SMauro Carvalho Chehab switch (state->demod_chip) { 6209a0bf528SMauro Carvalho Chehab case NXT2002: 6219a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x58, buf, 2); 6229a0bf528SMauro Carvalho Chehab break; 6239a0bf528SMauro Carvalho Chehab case NXT2004: 6249a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x58, buf, 2); 6259a0bf528SMauro Carvalho Chehab break; 6269a0bf528SMauro Carvalho Chehab default: 6279a0bf528SMauro Carvalho Chehab return -EINVAL; 6289a0bf528SMauro Carvalho Chehab break; 6299a0bf528SMauro Carvalho Chehab } 6309a0bf528SMauro Carvalho Chehab 6319a0bf528SMauro Carvalho Chehab /* write sdmx input */ 6329a0bf528SMauro Carvalho Chehab switch (p->modulation) { 6339a0bf528SMauro Carvalho Chehab case QAM_64: 6349a0bf528SMauro Carvalho Chehab buf[0] = 0x68; 6359a0bf528SMauro Carvalho Chehab break; 6369a0bf528SMauro Carvalho Chehab case QAM_256: 6379a0bf528SMauro Carvalho Chehab buf[0] = 0x64; 6389a0bf528SMauro Carvalho Chehab break; 6399a0bf528SMauro Carvalho Chehab case VSB_8: 6409a0bf528SMauro Carvalho Chehab buf[0] = 0x60; 6419a0bf528SMauro Carvalho Chehab break; 6429a0bf528SMauro Carvalho Chehab default: 6439a0bf528SMauro Carvalho Chehab return -EINVAL; 6449a0bf528SMauro Carvalho Chehab break; 6459a0bf528SMauro Carvalho Chehab } 6469a0bf528SMauro Carvalho Chehab buf[1] = 0x00; 6479a0bf528SMauro Carvalho Chehab switch (state->demod_chip) { 6489a0bf528SMauro Carvalho Chehab case NXT2002: 6499a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x5C, buf, 2); 6509a0bf528SMauro Carvalho Chehab break; 6519a0bf528SMauro Carvalho Chehab case NXT2004: 6529a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x5C, buf, 2); 6539a0bf528SMauro Carvalho Chehab break; 6549a0bf528SMauro Carvalho Chehab default: 6559a0bf528SMauro Carvalho Chehab return -EINVAL; 6569a0bf528SMauro Carvalho Chehab break; 6579a0bf528SMauro Carvalho Chehab } 6589a0bf528SMauro Carvalho Chehab 6599a0bf528SMauro Carvalho Chehab /* write adc power lpf fc */ 6609a0bf528SMauro Carvalho Chehab buf[0] = 0x05; 6619a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x43, buf, 1); 6629a0bf528SMauro Carvalho Chehab 6639a0bf528SMauro Carvalho Chehab if (state->demod_chip == NXT2004) { 6649a0bf528SMauro Carvalho Chehab /* write ??? */ 6659a0bf528SMauro Carvalho Chehab buf[0] = 0x00; 6669a0bf528SMauro Carvalho Chehab buf[1] = 0x00; 6679a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x46, buf, 2); 6689a0bf528SMauro Carvalho Chehab } 6699a0bf528SMauro Carvalho Chehab 6709a0bf528SMauro Carvalho Chehab /* write accumulator2 input */ 6719a0bf528SMauro Carvalho Chehab buf[0] = 0x80; 6729a0bf528SMauro Carvalho Chehab buf[1] = 0x00; 6739a0bf528SMauro Carvalho Chehab switch (state->demod_chip) { 6749a0bf528SMauro Carvalho Chehab case NXT2002: 6759a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x4B, buf, 2); 6769a0bf528SMauro Carvalho Chehab break; 6779a0bf528SMauro Carvalho Chehab case NXT2004: 6789a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x4B, buf, 2); 6799a0bf528SMauro Carvalho Chehab break; 6809a0bf528SMauro Carvalho Chehab default: 6819a0bf528SMauro Carvalho Chehab return -EINVAL; 6829a0bf528SMauro Carvalho Chehab break; 6839a0bf528SMauro Carvalho Chehab } 6849a0bf528SMauro Carvalho Chehab 6859a0bf528SMauro Carvalho Chehab /* write kg1 */ 6869a0bf528SMauro Carvalho Chehab buf[0] = 0x00; 6879a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x4D, buf, 1); 6889a0bf528SMauro Carvalho Chehab 6899a0bf528SMauro Carvalho Chehab /* write sdm12 lpf fc */ 6909a0bf528SMauro Carvalho Chehab buf[0] = 0x44; 6919a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x55, buf, 1); 6929a0bf528SMauro Carvalho Chehab 6939a0bf528SMauro Carvalho Chehab /* write agc control reg */ 6949a0bf528SMauro Carvalho Chehab buf[0] = 0x04; 6959a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x41, buf, 1); 6969a0bf528SMauro Carvalho Chehab 6979a0bf528SMauro Carvalho Chehab if (state->demod_chip == NXT2004) { 6989a0bf528SMauro Carvalho Chehab nxt200x_readreg_multibyte(state, 0x80, buf, 1); 6999a0bf528SMauro Carvalho Chehab buf[0] = 0x24; 7009a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x80, buf, 1); 7019a0bf528SMauro Carvalho Chehab 7029a0bf528SMauro Carvalho Chehab /* soft reset? */ 7039a0bf528SMauro Carvalho Chehab nxt200x_readreg_multibyte(state, 0x08, buf, 1); 7049a0bf528SMauro Carvalho Chehab buf[0] = 0x10; 7059a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x08, buf, 1); 7069a0bf528SMauro Carvalho Chehab nxt200x_readreg_multibyte(state, 0x08, buf, 1); 7079a0bf528SMauro Carvalho Chehab buf[0] = 0x00; 7089a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x08, buf, 1); 7099a0bf528SMauro Carvalho Chehab 7109a0bf528SMauro Carvalho Chehab nxt200x_readreg_multibyte(state, 0x80, buf, 1); 7119a0bf528SMauro Carvalho Chehab buf[0] = 0x04; 7129a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x80, buf, 1); 7139a0bf528SMauro Carvalho Chehab buf[0] = 0x00; 7149a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x81, buf, 1); 7159a0bf528SMauro Carvalho Chehab buf[0] = 0x80; buf[1] = 0x00; buf[2] = 0x00; 7169a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x82, buf, 3); 7179a0bf528SMauro Carvalho Chehab nxt200x_readreg_multibyte(state, 0x88, buf, 1); 7189a0bf528SMauro Carvalho Chehab buf[0] = 0x11; 7199a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x88, buf, 1); 7209a0bf528SMauro Carvalho Chehab nxt200x_readreg_multibyte(state, 0x80, buf, 1); 7219a0bf528SMauro Carvalho Chehab buf[0] = 0x44; 7229a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x80, buf, 1); 7239a0bf528SMauro Carvalho Chehab } 7249a0bf528SMauro Carvalho Chehab 7259a0bf528SMauro Carvalho Chehab /* write agc ucgp0 */ 7269a0bf528SMauro Carvalho Chehab switch (p->modulation) { 7279a0bf528SMauro Carvalho Chehab case QAM_64: 7289a0bf528SMauro Carvalho Chehab buf[0] = 0x02; 7299a0bf528SMauro Carvalho Chehab break; 7309a0bf528SMauro Carvalho Chehab case QAM_256: 7319a0bf528SMauro Carvalho Chehab buf[0] = 0x03; 7329a0bf528SMauro Carvalho Chehab break; 7339a0bf528SMauro Carvalho Chehab case VSB_8: 7349a0bf528SMauro Carvalho Chehab buf[0] = 0x00; 7359a0bf528SMauro Carvalho Chehab break; 7369a0bf528SMauro Carvalho Chehab default: 7379a0bf528SMauro Carvalho Chehab return -EINVAL; 7389a0bf528SMauro Carvalho Chehab break; 7399a0bf528SMauro Carvalho Chehab } 7409a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x30, buf, 1); 7419a0bf528SMauro Carvalho Chehab 7429a0bf528SMauro Carvalho Chehab /* write agc control reg */ 7439a0bf528SMauro Carvalho Chehab buf[0] = 0x00; 7449a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x41, buf, 1); 7459a0bf528SMauro Carvalho Chehab 7469a0bf528SMauro Carvalho Chehab /* write accumulator2 input */ 7479a0bf528SMauro Carvalho Chehab buf[0] = 0x80; 7489a0bf528SMauro Carvalho Chehab buf[1] = 0x00; 7499a0bf528SMauro Carvalho Chehab switch (state->demod_chip) { 7509a0bf528SMauro Carvalho Chehab case NXT2002: 7519a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x49, buf, 2); 7529a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x4B, buf, 2); 7539a0bf528SMauro Carvalho Chehab break; 7549a0bf528SMauro Carvalho Chehab case NXT2004: 7559a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x49, buf, 2); 7569a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x4B, buf, 2); 7579a0bf528SMauro Carvalho Chehab break; 7589a0bf528SMauro Carvalho Chehab default: 7599a0bf528SMauro Carvalho Chehab return -EINVAL; 7609a0bf528SMauro Carvalho Chehab break; 7619a0bf528SMauro Carvalho Chehab } 7629a0bf528SMauro Carvalho Chehab 7639a0bf528SMauro Carvalho Chehab /* write agc control reg */ 7649a0bf528SMauro Carvalho Chehab buf[0] = 0x04; 7659a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x41, buf, 1); 7669a0bf528SMauro Carvalho Chehab 7679a0bf528SMauro Carvalho Chehab nxt200x_microcontroller_start(state); 7689a0bf528SMauro Carvalho Chehab 7699a0bf528SMauro Carvalho Chehab if (state->demod_chip == NXT2004) { 7709a0bf528SMauro Carvalho Chehab nxt2004_microcontroller_init(state); 7719a0bf528SMauro Carvalho Chehab 7729a0bf528SMauro Carvalho Chehab /* ???? */ 7739a0bf528SMauro Carvalho Chehab buf[0] = 0xF0; 7749a0bf528SMauro Carvalho Chehab buf[1] = 0x00; 7759a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x5C, buf, 2); 7769a0bf528SMauro Carvalho Chehab } 7779a0bf528SMauro Carvalho Chehab 7789a0bf528SMauro Carvalho Chehab /* adjacent channel detection should be done here, but I don't 7799a0bf528SMauro Carvalho Chehab have any stations with this need so I cannot test it */ 7809a0bf528SMauro Carvalho Chehab 7819a0bf528SMauro Carvalho Chehab return 0; 7829a0bf528SMauro Carvalho Chehab } 7839a0bf528SMauro Carvalho Chehab 7849a0bf528SMauro Carvalho Chehab static int nxt200x_read_status(struct dvb_frontend* fe, fe_status_t* status) 7859a0bf528SMauro Carvalho Chehab { 7869a0bf528SMauro Carvalho Chehab struct nxt200x_state* state = fe->demodulator_priv; 7879a0bf528SMauro Carvalho Chehab u8 lock; 7889a0bf528SMauro Carvalho Chehab nxt200x_readbytes(state, 0x31, &lock, 1); 7899a0bf528SMauro Carvalho Chehab 7909a0bf528SMauro Carvalho Chehab *status = 0; 7919a0bf528SMauro Carvalho Chehab if (lock & 0x20) { 7929a0bf528SMauro Carvalho Chehab *status |= FE_HAS_SIGNAL; 7939a0bf528SMauro Carvalho Chehab *status |= FE_HAS_CARRIER; 7949a0bf528SMauro Carvalho Chehab *status |= FE_HAS_VITERBI; 7959a0bf528SMauro Carvalho Chehab *status |= FE_HAS_SYNC; 7969a0bf528SMauro Carvalho Chehab *status |= FE_HAS_LOCK; 7979a0bf528SMauro Carvalho Chehab } 7989a0bf528SMauro Carvalho Chehab return 0; 7999a0bf528SMauro Carvalho Chehab } 8009a0bf528SMauro Carvalho Chehab 8019a0bf528SMauro Carvalho Chehab static int nxt200x_read_ber(struct dvb_frontend* fe, u32* ber) 8029a0bf528SMauro Carvalho Chehab { 8039a0bf528SMauro Carvalho Chehab struct nxt200x_state* state = fe->demodulator_priv; 8049a0bf528SMauro Carvalho Chehab u8 b[3]; 8059a0bf528SMauro Carvalho Chehab 8069a0bf528SMauro Carvalho Chehab nxt200x_readreg_multibyte(state, 0xE6, b, 3); 8079a0bf528SMauro Carvalho Chehab 8089a0bf528SMauro Carvalho Chehab *ber = ((b[0] << 8) + b[1]) * 8; 8099a0bf528SMauro Carvalho Chehab 8109a0bf528SMauro Carvalho Chehab return 0; 8119a0bf528SMauro Carvalho Chehab } 8129a0bf528SMauro Carvalho Chehab 8139a0bf528SMauro Carvalho Chehab static int nxt200x_read_signal_strength(struct dvb_frontend* fe, u16* strength) 8149a0bf528SMauro Carvalho Chehab { 8159a0bf528SMauro Carvalho Chehab struct nxt200x_state* state = fe->demodulator_priv; 8169a0bf528SMauro Carvalho Chehab u8 b[2]; 8179a0bf528SMauro Carvalho Chehab u16 temp = 0; 8189a0bf528SMauro Carvalho Chehab 8199a0bf528SMauro Carvalho Chehab /* setup to read cluster variance */ 8209a0bf528SMauro Carvalho Chehab b[0] = 0x00; 8219a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0xA1, b, 1); 8229a0bf528SMauro Carvalho Chehab 8239a0bf528SMauro Carvalho Chehab /* get multreg val */ 8249a0bf528SMauro Carvalho Chehab nxt200x_readreg_multibyte(state, 0xA6, b, 2); 8259a0bf528SMauro Carvalho Chehab 8269a0bf528SMauro Carvalho Chehab temp = (b[0] << 8) | b[1]; 8279a0bf528SMauro Carvalho Chehab *strength = ((0x7FFF - temp) & 0x0FFF) * 16; 8289a0bf528SMauro Carvalho Chehab 8299a0bf528SMauro Carvalho Chehab return 0; 8309a0bf528SMauro Carvalho Chehab } 8319a0bf528SMauro Carvalho Chehab 8329a0bf528SMauro Carvalho Chehab static int nxt200x_read_snr(struct dvb_frontend* fe, u16* snr) 8339a0bf528SMauro Carvalho Chehab { 8349a0bf528SMauro Carvalho Chehab 8359a0bf528SMauro Carvalho Chehab struct nxt200x_state* state = fe->demodulator_priv; 8369a0bf528SMauro Carvalho Chehab u8 b[2]; 8379a0bf528SMauro Carvalho Chehab u16 temp = 0, temp2; 8389a0bf528SMauro Carvalho Chehab u32 snrdb = 0; 8399a0bf528SMauro Carvalho Chehab 8409a0bf528SMauro Carvalho Chehab /* setup to read cluster variance */ 8419a0bf528SMauro Carvalho Chehab b[0] = 0x00; 8429a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0xA1, b, 1); 8439a0bf528SMauro Carvalho Chehab 8449a0bf528SMauro Carvalho Chehab /* get multreg val from 0xA6 */ 8459a0bf528SMauro Carvalho Chehab nxt200x_readreg_multibyte(state, 0xA6, b, 2); 8469a0bf528SMauro Carvalho Chehab 8479a0bf528SMauro Carvalho Chehab temp = (b[0] << 8) | b[1]; 8489a0bf528SMauro Carvalho Chehab temp2 = 0x7FFF - temp; 8499a0bf528SMauro Carvalho Chehab 8509a0bf528SMauro Carvalho Chehab /* snr will be in db */ 8519a0bf528SMauro Carvalho Chehab if (temp2 > 0x7F00) 8529a0bf528SMauro Carvalho Chehab snrdb = 1000*24 + ( 1000*(30-24) * ( temp2 - 0x7F00 ) / ( 0x7FFF - 0x7F00 ) ); 8539a0bf528SMauro Carvalho Chehab else if (temp2 > 0x7EC0) 8549a0bf528SMauro Carvalho Chehab snrdb = 1000*18 + ( 1000*(24-18) * ( temp2 - 0x7EC0 ) / ( 0x7F00 - 0x7EC0 ) ); 8559a0bf528SMauro Carvalho Chehab else if (temp2 > 0x7C00) 8569a0bf528SMauro Carvalho Chehab snrdb = 1000*12 + ( 1000*(18-12) * ( temp2 - 0x7C00 ) / ( 0x7EC0 - 0x7C00 ) ); 8579a0bf528SMauro Carvalho Chehab else 8589a0bf528SMauro Carvalho Chehab snrdb = 1000*0 + ( 1000*(12-0) * ( temp2 - 0 ) / ( 0x7C00 - 0 ) ); 8599a0bf528SMauro Carvalho Chehab 8609a0bf528SMauro Carvalho Chehab /* the value reported back from the frontend will be FFFF=32db 0000=0db */ 8619a0bf528SMauro Carvalho Chehab *snr = snrdb * (0xFFFF/32000); 8629a0bf528SMauro Carvalho Chehab 8639a0bf528SMauro Carvalho Chehab return 0; 8649a0bf528SMauro Carvalho Chehab } 8659a0bf528SMauro Carvalho Chehab 8669a0bf528SMauro Carvalho Chehab static int nxt200x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) 8679a0bf528SMauro Carvalho Chehab { 8689a0bf528SMauro Carvalho Chehab struct nxt200x_state* state = fe->demodulator_priv; 8699a0bf528SMauro Carvalho Chehab u8 b[3]; 8709a0bf528SMauro Carvalho Chehab 8719a0bf528SMauro Carvalho Chehab nxt200x_readreg_multibyte(state, 0xE6, b, 3); 8729a0bf528SMauro Carvalho Chehab *ucblocks = b[2]; 8739a0bf528SMauro Carvalho Chehab 8749a0bf528SMauro Carvalho Chehab return 0; 8759a0bf528SMauro Carvalho Chehab } 8769a0bf528SMauro Carvalho Chehab 8779a0bf528SMauro Carvalho Chehab static int nxt200x_sleep(struct dvb_frontend* fe) 8789a0bf528SMauro Carvalho Chehab { 8799a0bf528SMauro Carvalho Chehab return 0; 8809a0bf528SMauro Carvalho Chehab } 8819a0bf528SMauro Carvalho Chehab 8829a0bf528SMauro Carvalho Chehab static int nxt2002_init(struct dvb_frontend* fe) 8839a0bf528SMauro Carvalho Chehab { 8849a0bf528SMauro Carvalho Chehab struct nxt200x_state* state = fe->demodulator_priv; 8859a0bf528SMauro Carvalho Chehab const struct firmware *fw; 8869a0bf528SMauro Carvalho Chehab int ret; 8879a0bf528SMauro Carvalho Chehab u8 buf[2]; 8889a0bf528SMauro Carvalho Chehab 8899a0bf528SMauro Carvalho Chehab /* request the firmware, this will block until someone uploads it */ 8909a0bf528SMauro Carvalho Chehab pr_debug("%s: Waiting for firmware upload (%s)...\n", 8919a0bf528SMauro Carvalho Chehab __func__, NXT2002_DEFAULT_FIRMWARE); 8929a0bf528SMauro Carvalho Chehab ret = request_firmware(&fw, NXT2002_DEFAULT_FIRMWARE, 8939a0bf528SMauro Carvalho Chehab state->i2c->dev.parent); 8949a0bf528SMauro Carvalho Chehab pr_debug("%s: Waiting for firmware upload(2)...\n", __func__); 8959a0bf528SMauro Carvalho Chehab if (ret) { 8969a0bf528SMauro Carvalho Chehab pr_err("%s: No firmware uploaded (timeout or file not found?)" 8979a0bf528SMauro Carvalho Chehab "\n", __func__); 8989a0bf528SMauro Carvalho Chehab return ret; 8999a0bf528SMauro Carvalho Chehab } 9009a0bf528SMauro Carvalho Chehab 9019a0bf528SMauro Carvalho Chehab ret = nxt2002_load_firmware(fe, fw); 9029a0bf528SMauro Carvalho Chehab release_firmware(fw); 9039a0bf528SMauro Carvalho Chehab if (ret) { 9049a0bf528SMauro Carvalho Chehab pr_err("%s: Writing firmware to device failed\n", __func__); 9059a0bf528SMauro Carvalho Chehab return ret; 9069a0bf528SMauro Carvalho Chehab } 9079a0bf528SMauro Carvalho Chehab pr_info("%s: Firmware upload complete\n", __func__); 9089a0bf528SMauro Carvalho Chehab 9099a0bf528SMauro Carvalho Chehab /* Put the micro into reset */ 9109a0bf528SMauro Carvalho Chehab nxt200x_microcontroller_stop(state); 9119a0bf528SMauro Carvalho Chehab 9129a0bf528SMauro Carvalho Chehab /* ensure transfer is complete */ 9139a0bf528SMauro Carvalho Chehab buf[0]=0x00; 9149a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x2B, buf, 1); 9159a0bf528SMauro Carvalho Chehab 9169a0bf528SMauro Carvalho Chehab /* Put the micro into reset for real this time */ 9179a0bf528SMauro Carvalho Chehab nxt200x_microcontroller_stop(state); 9189a0bf528SMauro Carvalho Chehab 9199a0bf528SMauro Carvalho Chehab /* soft reset everything (agc,frontend,eq,fec)*/ 9209a0bf528SMauro Carvalho Chehab buf[0] = 0x0F; 9219a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x08, buf, 1); 9229a0bf528SMauro Carvalho Chehab buf[0] = 0x00; 9239a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x08, buf, 1); 9249a0bf528SMauro Carvalho Chehab 9259a0bf528SMauro Carvalho Chehab /* write agc sdm configure */ 9269a0bf528SMauro Carvalho Chehab buf[0] = 0xF1; 9279a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x57, buf, 1); 9289a0bf528SMauro Carvalho Chehab 9299a0bf528SMauro Carvalho Chehab /* write mod output format */ 9309a0bf528SMauro Carvalho Chehab buf[0] = 0x20; 9319a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x09, buf, 1); 9329a0bf528SMauro Carvalho Chehab 9339a0bf528SMauro Carvalho Chehab /* write fec mpeg mode */ 9349a0bf528SMauro Carvalho Chehab buf[0] = 0x7E; 9359a0bf528SMauro Carvalho Chehab buf[1] = 0x00; 9369a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0xE9, buf, 2); 9379a0bf528SMauro Carvalho Chehab 9389a0bf528SMauro Carvalho Chehab /* write mux selection */ 9399a0bf528SMauro Carvalho Chehab buf[0] = 0x00; 9409a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0xCC, buf, 1); 9419a0bf528SMauro Carvalho Chehab 9429a0bf528SMauro Carvalho Chehab return 0; 9439a0bf528SMauro Carvalho Chehab } 9449a0bf528SMauro Carvalho Chehab 9459a0bf528SMauro Carvalho Chehab static int nxt2004_init(struct dvb_frontend* fe) 9469a0bf528SMauro Carvalho Chehab { 9479a0bf528SMauro Carvalho Chehab struct nxt200x_state* state = fe->demodulator_priv; 9489a0bf528SMauro Carvalho Chehab const struct firmware *fw; 9499a0bf528SMauro Carvalho Chehab int ret; 9509a0bf528SMauro Carvalho Chehab u8 buf[3]; 9519a0bf528SMauro Carvalho Chehab 9529a0bf528SMauro Carvalho Chehab /* ??? */ 9539a0bf528SMauro Carvalho Chehab buf[0]=0x00; 9549a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x1E, buf, 1); 9559a0bf528SMauro Carvalho Chehab 9569a0bf528SMauro Carvalho Chehab /* request the firmware, this will block until someone uploads it */ 9579a0bf528SMauro Carvalho Chehab pr_debug("%s: Waiting for firmware upload (%s)...\n", 9589a0bf528SMauro Carvalho Chehab __func__, NXT2004_DEFAULT_FIRMWARE); 9599a0bf528SMauro Carvalho Chehab ret = request_firmware(&fw, NXT2004_DEFAULT_FIRMWARE, 9609a0bf528SMauro Carvalho Chehab state->i2c->dev.parent); 9619a0bf528SMauro Carvalho Chehab pr_debug("%s: Waiting for firmware upload(2)...\n", __func__); 9629a0bf528SMauro Carvalho Chehab if (ret) { 9639a0bf528SMauro Carvalho Chehab pr_err("%s: No firmware uploaded (timeout or file not found?)" 9649a0bf528SMauro Carvalho Chehab "\n", __func__); 9659a0bf528SMauro Carvalho Chehab return ret; 9669a0bf528SMauro Carvalho Chehab } 9679a0bf528SMauro Carvalho Chehab 9689a0bf528SMauro Carvalho Chehab ret = nxt2004_load_firmware(fe, fw); 9699a0bf528SMauro Carvalho Chehab release_firmware(fw); 9709a0bf528SMauro Carvalho Chehab if (ret) { 9719a0bf528SMauro Carvalho Chehab pr_err("%s: Writing firmware to device failed\n", __func__); 9729a0bf528SMauro Carvalho Chehab return ret; 9739a0bf528SMauro Carvalho Chehab } 9749a0bf528SMauro Carvalho Chehab pr_info("%s: Firmware upload complete\n", __func__); 9759a0bf528SMauro Carvalho Chehab 9769a0bf528SMauro Carvalho Chehab /* ensure transfer is complete */ 9779a0bf528SMauro Carvalho Chehab buf[0] = 0x01; 9789a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x19, buf, 1); 9799a0bf528SMauro Carvalho Chehab 9809a0bf528SMauro Carvalho Chehab nxt2004_microcontroller_init(state); 9819a0bf528SMauro Carvalho Chehab nxt200x_microcontroller_stop(state); 9829a0bf528SMauro Carvalho Chehab nxt200x_microcontroller_stop(state); 9839a0bf528SMauro Carvalho Chehab nxt2004_microcontroller_init(state); 9849a0bf528SMauro Carvalho Chehab nxt200x_microcontroller_stop(state); 9859a0bf528SMauro Carvalho Chehab 9869a0bf528SMauro Carvalho Chehab /* soft reset everything (agc,frontend,eq,fec)*/ 9879a0bf528SMauro Carvalho Chehab buf[0] = 0xFF; 9889a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x08, buf, 1); 9899a0bf528SMauro Carvalho Chehab buf[0] = 0x00; 9909a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x08, buf, 1); 9919a0bf528SMauro Carvalho Chehab 9929a0bf528SMauro Carvalho Chehab /* write agc sdm configure */ 9939a0bf528SMauro Carvalho Chehab buf[0] = 0xD7; 9949a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x57, buf, 1); 9959a0bf528SMauro Carvalho Chehab 9969a0bf528SMauro Carvalho Chehab /* ???*/ 9979a0bf528SMauro Carvalho Chehab buf[0] = 0x07; 9989a0bf528SMauro Carvalho Chehab buf[1] = 0xfe; 9999a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x35, buf, 2); 10009a0bf528SMauro Carvalho Chehab buf[0] = 0x12; 10019a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x34, buf, 1); 10029a0bf528SMauro Carvalho Chehab buf[0] = 0x80; 10039a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x21, buf, 1); 10049a0bf528SMauro Carvalho Chehab 10059a0bf528SMauro Carvalho Chehab /* ???*/ 10069a0bf528SMauro Carvalho Chehab buf[0] = 0x21; 10079a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x0A, buf, 1); 10089a0bf528SMauro Carvalho Chehab 10099a0bf528SMauro Carvalho Chehab /* ???*/ 10109a0bf528SMauro Carvalho Chehab buf[0] = 0x01; 10119a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x80, buf, 1); 10129a0bf528SMauro Carvalho Chehab 10139a0bf528SMauro Carvalho Chehab /* write fec mpeg mode */ 10149a0bf528SMauro Carvalho Chehab buf[0] = 0x7E; 10159a0bf528SMauro Carvalho Chehab buf[1] = 0x00; 10169a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0xE9, buf, 2); 10179a0bf528SMauro Carvalho Chehab 10189a0bf528SMauro Carvalho Chehab /* write mux selection */ 10199a0bf528SMauro Carvalho Chehab buf[0] = 0x00; 10209a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0xCC, buf, 1); 10219a0bf528SMauro Carvalho Chehab 10229a0bf528SMauro Carvalho Chehab /* ???*/ 10239a0bf528SMauro Carvalho Chehab nxt200x_readreg_multibyte(state, 0x80, buf, 1); 10249a0bf528SMauro Carvalho Chehab buf[0] = 0x00; 10259a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x80, buf, 1); 10269a0bf528SMauro Carvalho Chehab 10279a0bf528SMauro Carvalho Chehab /* soft reset? */ 10289a0bf528SMauro Carvalho Chehab nxt200x_readreg_multibyte(state, 0x08, buf, 1); 10299a0bf528SMauro Carvalho Chehab buf[0] = 0x10; 10309a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x08, buf, 1); 10319a0bf528SMauro Carvalho Chehab nxt200x_readreg_multibyte(state, 0x08, buf, 1); 10329a0bf528SMauro Carvalho Chehab buf[0] = 0x00; 10339a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x08, buf, 1); 10349a0bf528SMauro Carvalho Chehab 10359a0bf528SMauro Carvalho Chehab /* ???*/ 10369a0bf528SMauro Carvalho Chehab nxt200x_readreg_multibyte(state, 0x80, buf, 1); 10379a0bf528SMauro Carvalho Chehab buf[0] = 0x01; 10389a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x80, buf, 1); 10399a0bf528SMauro Carvalho Chehab buf[0] = 0x70; 10409a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x81, buf, 1); 10419a0bf528SMauro Carvalho Chehab buf[0] = 0x31; buf[1] = 0x5E; buf[2] = 0x66; 10429a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x82, buf, 3); 10439a0bf528SMauro Carvalho Chehab 10449a0bf528SMauro Carvalho Chehab nxt200x_readreg_multibyte(state, 0x88, buf, 1); 10459a0bf528SMauro Carvalho Chehab buf[0] = 0x11; 10469a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x88, buf, 1); 10479a0bf528SMauro Carvalho Chehab nxt200x_readreg_multibyte(state, 0x80, buf, 1); 10489a0bf528SMauro Carvalho Chehab buf[0] = 0x40; 10499a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x80, buf, 1); 10509a0bf528SMauro Carvalho Chehab 10519a0bf528SMauro Carvalho Chehab nxt200x_readbytes(state, 0x10, buf, 1); 10529a0bf528SMauro Carvalho Chehab buf[0] = 0x10; 10539a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x10, buf, 1); 10549a0bf528SMauro Carvalho Chehab nxt200x_readbytes(state, 0x0A, buf, 1); 10559a0bf528SMauro Carvalho Chehab buf[0] = 0x21; 10569a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x0A, buf, 1); 10579a0bf528SMauro Carvalho Chehab 10589a0bf528SMauro Carvalho Chehab nxt2004_microcontroller_init(state); 10599a0bf528SMauro Carvalho Chehab 10609a0bf528SMauro Carvalho Chehab buf[0] = 0x21; 10619a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x0A, buf, 1); 10629a0bf528SMauro Carvalho Chehab buf[0] = 0x7E; 10639a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0xE9, buf, 1); 10649a0bf528SMauro Carvalho Chehab buf[0] = 0x00; 10659a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0xEA, buf, 1); 10669a0bf528SMauro Carvalho Chehab 10679a0bf528SMauro Carvalho Chehab nxt200x_readreg_multibyte(state, 0x80, buf, 1); 10689a0bf528SMauro Carvalho Chehab buf[0] = 0x00; 10699a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x80, buf, 1); 10709a0bf528SMauro Carvalho Chehab nxt200x_readreg_multibyte(state, 0x80, buf, 1); 10719a0bf528SMauro Carvalho Chehab buf[0] = 0x00; 10729a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x80, buf, 1); 10739a0bf528SMauro Carvalho Chehab 10749a0bf528SMauro Carvalho Chehab /* soft reset? */ 10759a0bf528SMauro Carvalho Chehab nxt200x_readreg_multibyte(state, 0x08, buf, 1); 10769a0bf528SMauro Carvalho Chehab buf[0] = 0x10; 10779a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x08, buf, 1); 10789a0bf528SMauro Carvalho Chehab nxt200x_readreg_multibyte(state, 0x08, buf, 1); 10799a0bf528SMauro Carvalho Chehab buf[0] = 0x00; 10809a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x08, buf, 1); 10819a0bf528SMauro Carvalho Chehab 10829a0bf528SMauro Carvalho Chehab nxt200x_readreg_multibyte(state, 0x80, buf, 1); 10839a0bf528SMauro Carvalho Chehab buf[0] = 0x04; 10849a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x80, buf, 1); 10859a0bf528SMauro Carvalho Chehab buf[0] = 0x00; 10869a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x81, buf, 1); 10879a0bf528SMauro Carvalho Chehab buf[0] = 0x80; buf[1] = 0x00; buf[2] = 0x00; 10889a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x82, buf, 3); 10899a0bf528SMauro Carvalho Chehab 10909a0bf528SMauro Carvalho Chehab nxt200x_readreg_multibyte(state, 0x88, buf, 1); 10919a0bf528SMauro Carvalho Chehab buf[0] = 0x11; 10929a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x88, buf, 1); 10939a0bf528SMauro Carvalho Chehab 10949a0bf528SMauro Carvalho Chehab nxt200x_readreg_multibyte(state, 0x80, buf, 1); 10959a0bf528SMauro Carvalho Chehab buf[0] = 0x44; 10969a0bf528SMauro Carvalho Chehab nxt200x_writereg_multibyte(state, 0x80, buf, 1); 10979a0bf528SMauro Carvalho Chehab 10989a0bf528SMauro Carvalho Chehab /* initialize tuner */ 10999a0bf528SMauro Carvalho Chehab nxt200x_readbytes(state, 0x10, buf, 1); 11009a0bf528SMauro Carvalho Chehab buf[0] = 0x12; 11019a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x10, buf, 1); 11029a0bf528SMauro Carvalho Chehab buf[0] = 0x04; 11039a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x13, buf, 1); 11049a0bf528SMauro Carvalho Chehab buf[0] = 0x00; 11059a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x16, buf, 1); 11069a0bf528SMauro Carvalho Chehab buf[0] = 0x04; 11079a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x14, buf, 1); 11089a0bf528SMauro Carvalho Chehab buf[0] = 0x00; 11099a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x14, buf, 1); 11109a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x17, buf, 1); 11119a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x14, buf, 1); 11129a0bf528SMauro Carvalho Chehab nxt200x_writebytes(state, 0x17, buf, 1); 11139a0bf528SMauro Carvalho Chehab 11149a0bf528SMauro Carvalho Chehab return 0; 11159a0bf528SMauro Carvalho Chehab } 11169a0bf528SMauro Carvalho Chehab 11179a0bf528SMauro Carvalho Chehab static int nxt200x_init(struct dvb_frontend* fe) 11189a0bf528SMauro Carvalho Chehab { 11199a0bf528SMauro Carvalho Chehab struct nxt200x_state* state = fe->demodulator_priv; 11209a0bf528SMauro Carvalho Chehab int ret = 0; 11219a0bf528SMauro Carvalho Chehab 11229a0bf528SMauro Carvalho Chehab if (!state->initialised) { 11239a0bf528SMauro Carvalho Chehab switch (state->demod_chip) { 11249a0bf528SMauro Carvalho Chehab case NXT2002: 11259a0bf528SMauro Carvalho Chehab ret = nxt2002_init(fe); 11269a0bf528SMauro Carvalho Chehab break; 11279a0bf528SMauro Carvalho Chehab case NXT2004: 11289a0bf528SMauro Carvalho Chehab ret = nxt2004_init(fe); 11299a0bf528SMauro Carvalho Chehab break; 11309a0bf528SMauro Carvalho Chehab default: 11319a0bf528SMauro Carvalho Chehab return -EINVAL; 11329a0bf528SMauro Carvalho Chehab break; 11339a0bf528SMauro Carvalho Chehab } 11349a0bf528SMauro Carvalho Chehab state->initialised = 1; 11359a0bf528SMauro Carvalho Chehab } 11369a0bf528SMauro Carvalho Chehab return ret; 11379a0bf528SMauro Carvalho Chehab } 11389a0bf528SMauro Carvalho Chehab 11399a0bf528SMauro Carvalho Chehab static int nxt200x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) 11409a0bf528SMauro Carvalho Chehab { 11419a0bf528SMauro Carvalho Chehab fesettings->min_delay_ms = 500; 11429a0bf528SMauro Carvalho Chehab fesettings->step_size = 0; 11439a0bf528SMauro Carvalho Chehab fesettings->max_drift = 0; 11449a0bf528SMauro Carvalho Chehab return 0; 11459a0bf528SMauro Carvalho Chehab } 11469a0bf528SMauro Carvalho Chehab 11479a0bf528SMauro Carvalho Chehab static void nxt200x_release(struct dvb_frontend* fe) 11489a0bf528SMauro Carvalho Chehab { 11499a0bf528SMauro Carvalho Chehab struct nxt200x_state* state = fe->demodulator_priv; 11509a0bf528SMauro Carvalho Chehab kfree(state); 11519a0bf528SMauro Carvalho Chehab } 11529a0bf528SMauro Carvalho Chehab 11539a0bf528SMauro Carvalho Chehab static struct dvb_frontend_ops nxt200x_ops; 11549a0bf528SMauro Carvalho Chehab 11559a0bf528SMauro Carvalho Chehab struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config, 11569a0bf528SMauro Carvalho Chehab struct i2c_adapter* i2c) 11579a0bf528SMauro Carvalho Chehab { 11589a0bf528SMauro Carvalho Chehab struct nxt200x_state* state = NULL; 11599a0bf528SMauro Carvalho Chehab u8 buf [] = {0,0,0,0,0}; 11609a0bf528SMauro Carvalho Chehab 11619a0bf528SMauro Carvalho Chehab /* allocate memory for the internal state */ 11629a0bf528SMauro Carvalho Chehab state = kzalloc(sizeof(struct nxt200x_state), GFP_KERNEL); 11639a0bf528SMauro Carvalho Chehab if (state == NULL) 11649a0bf528SMauro Carvalho Chehab goto error; 11659a0bf528SMauro Carvalho Chehab 11669a0bf528SMauro Carvalho Chehab /* setup the state */ 11679a0bf528SMauro Carvalho Chehab state->config = config; 11689a0bf528SMauro Carvalho Chehab state->i2c = i2c; 11699a0bf528SMauro Carvalho Chehab state->initialised = 0; 11709a0bf528SMauro Carvalho Chehab 11719a0bf528SMauro Carvalho Chehab /* read card id */ 11729a0bf528SMauro Carvalho Chehab nxt200x_readbytes(state, 0x00, buf, 5); 11739a0bf528SMauro Carvalho Chehab dprintk("NXT info: %*ph\n", 5, buf); 11749a0bf528SMauro Carvalho Chehab 11759a0bf528SMauro Carvalho Chehab /* set demod chip */ 11769a0bf528SMauro Carvalho Chehab switch (buf[0]) { 11779a0bf528SMauro Carvalho Chehab case 0x04: 11789a0bf528SMauro Carvalho Chehab state->demod_chip = NXT2002; 11799a0bf528SMauro Carvalho Chehab pr_info("NXT2002 Detected\n"); 11809a0bf528SMauro Carvalho Chehab break; 11819a0bf528SMauro Carvalho Chehab case 0x05: 11829a0bf528SMauro Carvalho Chehab state->demod_chip = NXT2004; 11839a0bf528SMauro Carvalho Chehab pr_info("NXT2004 Detected\n"); 11849a0bf528SMauro Carvalho Chehab break; 11859a0bf528SMauro Carvalho Chehab default: 11869a0bf528SMauro Carvalho Chehab goto error; 11879a0bf528SMauro Carvalho Chehab } 11889a0bf528SMauro Carvalho Chehab 11899a0bf528SMauro Carvalho Chehab /* make sure demod chip is supported */ 11909a0bf528SMauro Carvalho Chehab switch (state->demod_chip) { 11919a0bf528SMauro Carvalho Chehab case NXT2002: 11929a0bf528SMauro Carvalho Chehab if (buf[0] != 0x04) goto error; /* device id */ 11939a0bf528SMauro Carvalho Chehab if (buf[1] != 0x02) goto error; /* fab id */ 11949a0bf528SMauro Carvalho Chehab if (buf[2] != 0x11) goto error; /* month */ 11959a0bf528SMauro Carvalho Chehab if (buf[3] != 0x20) goto error; /* year msb */ 11969a0bf528SMauro Carvalho Chehab if (buf[4] != 0x00) goto error; /* year lsb */ 11979a0bf528SMauro Carvalho Chehab break; 11989a0bf528SMauro Carvalho Chehab case NXT2004: 11999a0bf528SMauro Carvalho Chehab if (buf[0] != 0x05) goto error; /* device id */ 12009a0bf528SMauro Carvalho Chehab break; 12019a0bf528SMauro Carvalho Chehab default: 12029a0bf528SMauro Carvalho Chehab goto error; 12039a0bf528SMauro Carvalho Chehab } 12049a0bf528SMauro Carvalho Chehab 12059a0bf528SMauro Carvalho Chehab /* create dvb_frontend */ 12069a0bf528SMauro Carvalho Chehab memcpy(&state->frontend.ops, &nxt200x_ops, sizeof(struct dvb_frontend_ops)); 12079a0bf528SMauro Carvalho Chehab state->frontend.demodulator_priv = state; 12089a0bf528SMauro Carvalho Chehab return &state->frontend; 12099a0bf528SMauro Carvalho Chehab 12109a0bf528SMauro Carvalho Chehab error: 12119a0bf528SMauro Carvalho Chehab kfree(state); 12129a0bf528SMauro Carvalho Chehab pr_err("Unknown/Unsupported NXT chip: %*ph\n", 5, buf); 12139a0bf528SMauro Carvalho Chehab return NULL; 12149a0bf528SMauro Carvalho Chehab } 12159a0bf528SMauro Carvalho Chehab 12169a0bf528SMauro Carvalho Chehab static struct dvb_frontend_ops nxt200x_ops = { 12179a0bf528SMauro Carvalho Chehab .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, 12189a0bf528SMauro Carvalho Chehab .info = { 12199a0bf528SMauro Carvalho Chehab .name = "Nextwave NXT200X VSB/QAM frontend", 12209a0bf528SMauro Carvalho Chehab .frequency_min = 54000000, 12219a0bf528SMauro Carvalho Chehab .frequency_max = 860000000, 12229a0bf528SMauro Carvalho Chehab .frequency_stepsize = 166666, /* stepsize is just a guess */ 12239a0bf528SMauro Carvalho Chehab .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 12249a0bf528SMauro Carvalho Chehab FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | 12259a0bf528SMauro Carvalho Chehab FE_CAN_8VSB | FE_CAN_QAM_64 | FE_CAN_QAM_256 12269a0bf528SMauro Carvalho Chehab }, 12279a0bf528SMauro Carvalho Chehab 12289a0bf528SMauro Carvalho Chehab .release = nxt200x_release, 12299a0bf528SMauro Carvalho Chehab 12309a0bf528SMauro Carvalho Chehab .init = nxt200x_init, 12319a0bf528SMauro Carvalho Chehab .sleep = nxt200x_sleep, 12329a0bf528SMauro Carvalho Chehab 12339a0bf528SMauro Carvalho Chehab .set_frontend = nxt200x_setup_frontend_parameters, 12349a0bf528SMauro Carvalho Chehab .get_tune_settings = nxt200x_get_tune_settings, 12359a0bf528SMauro Carvalho Chehab 12369a0bf528SMauro Carvalho Chehab .read_status = nxt200x_read_status, 12379a0bf528SMauro Carvalho Chehab .read_ber = nxt200x_read_ber, 12389a0bf528SMauro Carvalho Chehab .read_signal_strength = nxt200x_read_signal_strength, 12399a0bf528SMauro Carvalho Chehab .read_snr = nxt200x_read_snr, 12409a0bf528SMauro Carvalho Chehab .read_ucblocks = nxt200x_read_ucblocks, 12419a0bf528SMauro Carvalho Chehab }; 12429a0bf528SMauro Carvalho Chehab 12439a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644); 12449a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); 12459a0bf528SMauro Carvalho Chehab 12469a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("NXT200X (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver"); 12479a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Kirk Lapray, Michael Krufky, Jean-Francois Thibert, and Taylor Jacob"); 12489a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL"); 12499a0bf528SMauro Carvalho Chehab 12509a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(nxt200x_attach); 12519a0bf528SMauro Carvalho Chehab 1252