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