19a0bf528SMauro Carvalho Chehab /* 29a0bf528SMauro Carvalho Chehab * Support for OR51211 (pcHDTV HD-2000) - VSB 39a0bf528SMauro Carvalho Chehab * 49a0bf528SMauro Carvalho Chehab * Copyright (C) 2005 Kirk Lapray <kirk_lapray@bigfoot.com> 59a0bf528SMauro Carvalho Chehab * 69a0bf528SMauro Carvalho Chehab * Based on code from Jack Kelliher (kelliher@xmission.com) 79a0bf528SMauro Carvalho Chehab * Copyright (C) 2002 & pcHDTV, inc. 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 25bb9e31f3SAndy Shevchenko #define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ 26bb9e31f3SAndy Shevchenko 279a0bf528SMauro Carvalho Chehab /* 289a0bf528SMauro Carvalho Chehab * This driver needs external firmware. Please use the command 299a0bf528SMauro Carvalho Chehab * "<kerneldir>/Documentation/dvb/get_dvb_firmware or51211" to 309a0bf528SMauro Carvalho Chehab * download/extract it, and then copy it to /usr/lib/hotplug/firmware 319a0bf528SMauro Carvalho Chehab * or /lib/firmware (depending on configuration of firmware hotplug). 329a0bf528SMauro Carvalho Chehab */ 339a0bf528SMauro Carvalho Chehab #define OR51211_DEFAULT_FIRMWARE "dvb-fe-or51211.fw" 349a0bf528SMauro Carvalho Chehab 359a0bf528SMauro Carvalho Chehab #include <linux/kernel.h> 369a0bf528SMauro Carvalho Chehab #include <linux/module.h> 379a0bf528SMauro Carvalho Chehab #include <linux/device.h> 389a0bf528SMauro Carvalho Chehab #include <linux/firmware.h> 399a0bf528SMauro Carvalho Chehab #include <linux/string.h> 409a0bf528SMauro Carvalho Chehab #include <linux/slab.h> 419a0bf528SMauro Carvalho Chehab #include <asm/byteorder.h> 429a0bf528SMauro Carvalho Chehab 439a0bf528SMauro Carvalho Chehab #include "dvb_math.h" 449a0bf528SMauro Carvalho Chehab #include "dvb_frontend.h" 459a0bf528SMauro Carvalho Chehab #include "or51211.h" 469a0bf528SMauro Carvalho Chehab 479a0bf528SMauro Carvalho Chehab static int debug; 489a0bf528SMauro Carvalho Chehab #define dprintk(args...) \ 49bb9e31f3SAndy Shevchenko do { if (debug) pr_debug(args); } while (0) 509a0bf528SMauro Carvalho Chehab 519a0bf528SMauro Carvalho Chehab static u8 run_buf[] = {0x7f,0x01}; 529a0bf528SMauro Carvalho Chehab static u8 cmd_buf[] = {0x04,0x01,0x50,0x80,0x06}; // ATSC 539a0bf528SMauro Carvalho Chehab 549a0bf528SMauro Carvalho Chehab struct or51211_state { 559a0bf528SMauro Carvalho Chehab 569a0bf528SMauro Carvalho Chehab struct i2c_adapter* i2c; 579a0bf528SMauro Carvalho Chehab 589a0bf528SMauro Carvalho Chehab /* Configuration settings */ 599a0bf528SMauro Carvalho Chehab const struct or51211_config* config; 609a0bf528SMauro Carvalho Chehab 619a0bf528SMauro Carvalho Chehab struct dvb_frontend frontend; 629a0bf528SMauro Carvalho Chehab struct bt878* bt; 639a0bf528SMauro Carvalho Chehab 649a0bf528SMauro Carvalho Chehab /* Demodulator private data */ 659a0bf528SMauro Carvalho Chehab u8 initialized:1; 669a0bf528SMauro Carvalho Chehab u32 snr; /* Result of last SNR claculation */ 679a0bf528SMauro Carvalho Chehab 689a0bf528SMauro Carvalho Chehab /* Tuner private data */ 699a0bf528SMauro Carvalho Chehab u32 current_frequency; 709a0bf528SMauro Carvalho Chehab }; 719a0bf528SMauro Carvalho Chehab 729a0bf528SMauro Carvalho Chehab static int i2c_writebytes (struct or51211_state* state, u8 reg, const u8 *buf, 739a0bf528SMauro Carvalho Chehab int len) 749a0bf528SMauro Carvalho Chehab { 759a0bf528SMauro Carvalho Chehab int err; 769a0bf528SMauro Carvalho Chehab struct i2c_msg msg; 779a0bf528SMauro Carvalho Chehab msg.addr = reg; 789a0bf528SMauro Carvalho Chehab msg.flags = 0; 799a0bf528SMauro Carvalho Chehab msg.len = len; 809a0bf528SMauro Carvalho Chehab msg.buf = (u8 *)buf; 819a0bf528SMauro Carvalho Chehab 829a0bf528SMauro Carvalho Chehab if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { 83bb9e31f3SAndy Shevchenko pr_warn("error (addr %02x, err == %i)\n", reg, err); 849a0bf528SMauro Carvalho Chehab return -EREMOTEIO; 859a0bf528SMauro Carvalho Chehab } 869a0bf528SMauro Carvalho Chehab 879a0bf528SMauro Carvalho Chehab return 0; 889a0bf528SMauro Carvalho Chehab } 899a0bf528SMauro Carvalho Chehab 909a0bf528SMauro Carvalho Chehab static int i2c_readbytes(struct or51211_state *state, u8 reg, u8 *buf, int len) 919a0bf528SMauro Carvalho Chehab { 929a0bf528SMauro Carvalho Chehab int err; 939a0bf528SMauro Carvalho Chehab struct i2c_msg msg; 949a0bf528SMauro Carvalho Chehab msg.addr = reg; 959a0bf528SMauro Carvalho Chehab msg.flags = I2C_M_RD; 969a0bf528SMauro Carvalho Chehab msg.len = len; 979a0bf528SMauro Carvalho Chehab msg.buf = buf; 989a0bf528SMauro Carvalho Chehab 999a0bf528SMauro Carvalho Chehab if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { 100bb9e31f3SAndy Shevchenko pr_warn("error (addr %02x, err == %i)\n", reg, err); 1019a0bf528SMauro Carvalho Chehab return -EREMOTEIO; 1029a0bf528SMauro Carvalho Chehab } 1039a0bf528SMauro Carvalho Chehab 1049a0bf528SMauro Carvalho Chehab return 0; 1059a0bf528SMauro Carvalho Chehab } 1069a0bf528SMauro Carvalho Chehab 1079a0bf528SMauro Carvalho Chehab static int or51211_load_firmware (struct dvb_frontend* fe, 1089a0bf528SMauro Carvalho Chehab const struct firmware *fw) 1099a0bf528SMauro Carvalho Chehab { 1109a0bf528SMauro Carvalho Chehab struct or51211_state* state = fe->demodulator_priv; 1119a0bf528SMauro Carvalho Chehab u8 tudata[585]; 1129a0bf528SMauro Carvalho Chehab int i; 1139a0bf528SMauro Carvalho Chehab 11435f30f36SMauro Carvalho Chehab dprintk("Firmware is %zu bytes\n", fw->size); 1159a0bf528SMauro Carvalho Chehab 1169a0bf528SMauro Carvalho Chehab /* Get eprom data */ 1179a0bf528SMauro Carvalho Chehab tudata[0] = 17; 1189a0bf528SMauro Carvalho Chehab if (i2c_writebytes(state,0x50,tudata,1)) { 119bb9e31f3SAndy Shevchenko pr_warn("error eprom addr\n"); 1209a0bf528SMauro Carvalho Chehab return -1; 1219a0bf528SMauro Carvalho Chehab } 1229a0bf528SMauro Carvalho Chehab if (i2c_readbytes(state,0x50,&tudata[145],192)) { 123bb9e31f3SAndy Shevchenko pr_warn("error eprom\n"); 1249a0bf528SMauro Carvalho Chehab return -1; 1259a0bf528SMauro Carvalho Chehab } 1269a0bf528SMauro Carvalho Chehab 1279a0bf528SMauro Carvalho Chehab /* Create firmware buffer */ 1289a0bf528SMauro Carvalho Chehab for (i = 0; i < 145; i++) 1299a0bf528SMauro Carvalho Chehab tudata[i] = fw->data[i]; 1309a0bf528SMauro Carvalho Chehab 1319a0bf528SMauro Carvalho Chehab for (i = 0; i < 248; i++) 1329a0bf528SMauro Carvalho Chehab tudata[i+337] = fw->data[145+i]; 1339a0bf528SMauro Carvalho Chehab 1349a0bf528SMauro Carvalho Chehab state->config->reset(fe); 1359a0bf528SMauro Carvalho Chehab 1369a0bf528SMauro Carvalho Chehab if (i2c_writebytes(state,state->config->demod_address,tudata,585)) { 137bb9e31f3SAndy Shevchenko pr_warn("error 1\n"); 1389a0bf528SMauro Carvalho Chehab return -1; 1399a0bf528SMauro Carvalho Chehab } 1409a0bf528SMauro Carvalho Chehab msleep(1); 1419a0bf528SMauro Carvalho Chehab 1429a0bf528SMauro Carvalho Chehab if (i2c_writebytes(state,state->config->demod_address, 1439a0bf528SMauro Carvalho Chehab &fw->data[393],8125)) { 144bb9e31f3SAndy Shevchenko pr_warn("error 2\n"); 1459a0bf528SMauro Carvalho Chehab return -1; 1469a0bf528SMauro Carvalho Chehab } 1479a0bf528SMauro Carvalho Chehab msleep(1); 1489a0bf528SMauro Carvalho Chehab 1499a0bf528SMauro Carvalho Chehab if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) { 150bb9e31f3SAndy Shevchenko pr_warn("error 3\n"); 1519a0bf528SMauro Carvalho Chehab return -1; 1529a0bf528SMauro Carvalho Chehab } 1539a0bf528SMauro Carvalho Chehab 1549a0bf528SMauro Carvalho Chehab /* Wait at least 5 msec */ 1559a0bf528SMauro Carvalho Chehab msleep(10); 1569a0bf528SMauro Carvalho Chehab if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) { 157bb9e31f3SAndy Shevchenko pr_warn("error 4\n"); 1589a0bf528SMauro Carvalho Chehab return -1; 1599a0bf528SMauro Carvalho Chehab } 1609a0bf528SMauro Carvalho Chehab msleep(10); 1619a0bf528SMauro Carvalho Chehab 162bb9e31f3SAndy Shevchenko pr_info("Done.\n"); 1639a0bf528SMauro Carvalho Chehab return 0; 1649a0bf528SMauro Carvalho Chehab }; 1659a0bf528SMauro Carvalho Chehab 1669a0bf528SMauro Carvalho Chehab static int or51211_setmode(struct dvb_frontend* fe, int mode) 1679a0bf528SMauro Carvalho Chehab { 1689a0bf528SMauro Carvalho Chehab struct or51211_state* state = fe->demodulator_priv; 1699a0bf528SMauro Carvalho Chehab u8 rec_buf[14]; 1709a0bf528SMauro Carvalho Chehab 1719a0bf528SMauro Carvalho Chehab state->config->setmode(fe, mode); 1729a0bf528SMauro Carvalho Chehab 1739a0bf528SMauro Carvalho Chehab if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) { 174bb9e31f3SAndy Shevchenko pr_warn("error 1\n"); 1759a0bf528SMauro Carvalho Chehab return -1; 1769a0bf528SMauro Carvalho Chehab } 1779a0bf528SMauro Carvalho Chehab 1789a0bf528SMauro Carvalho Chehab /* Wait at least 5 msec */ 1799a0bf528SMauro Carvalho Chehab msleep(10); 1809a0bf528SMauro Carvalho Chehab if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) { 181bb9e31f3SAndy Shevchenko pr_warn("error 2\n"); 1829a0bf528SMauro Carvalho Chehab return -1; 1839a0bf528SMauro Carvalho Chehab } 1849a0bf528SMauro Carvalho Chehab 1859a0bf528SMauro Carvalho Chehab msleep(10); 1869a0bf528SMauro Carvalho Chehab 1879a0bf528SMauro Carvalho Chehab /* Set operation mode in Receiver 1 register; 1889a0bf528SMauro Carvalho Chehab * type 1: 1899a0bf528SMauro Carvalho Chehab * data 0x50h Automatic sets receiver channel conditions 1909a0bf528SMauro Carvalho Chehab * Automatic NTSC rejection filter 1919a0bf528SMauro Carvalho Chehab * Enable MPEG serial data output 1929a0bf528SMauro Carvalho Chehab * MPEG2tr 1939a0bf528SMauro Carvalho Chehab * High tuner phase noise 1949a0bf528SMauro Carvalho Chehab * normal +/-150kHz Carrier acquisition range 1959a0bf528SMauro Carvalho Chehab */ 1969a0bf528SMauro Carvalho Chehab if (i2c_writebytes(state,state->config->demod_address,cmd_buf,3)) { 197bb9e31f3SAndy Shevchenko pr_warn("error 3\n"); 1989a0bf528SMauro Carvalho Chehab return -1; 1999a0bf528SMauro Carvalho Chehab } 2009a0bf528SMauro Carvalho Chehab 2019a0bf528SMauro Carvalho Chehab rec_buf[0] = 0x04; 2029a0bf528SMauro Carvalho Chehab rec_buf[1] = 0x00; 2039a0bf528SMauro Carvalho Chehab rec_buf[2] = 0x03; 2049a0bf528SMauro Carvalho Chehab rec_buf[3] = 0x00; 2059a0bf528SMauro Carvalho Chehab msleep(20); 2069a0bf528SMauro Carvalho Chehab if (i2c_writebytes(state,state->config->demod_address,rec_buf,3)) { 207bb9e31f3SAndy Shevchenko pr_warn("error 5\n"); 2089a0bf528SMauro Carvalho Chehab } 2099a0bf528SMauro Carvalho Chehab msleep(3); 2109a0bf528SMauro Carvalho Chehab if (i2c_readbytes(state,state->config->demod_address,&rec_buf[10],2)) { 211bb9e31f3SAndy Shevchenko pr_warn("error 6\n"); 2129a0bf528SMauro Carvalho Chehab return -1; 2139a0bf528SMauro Carvalho Chehab } 214bb9e31f3SAndy Shevchenko dprintk("rec status %02x %02x\n", rec_buf[10], rec_buf[11]); 2159a0bf528SMauro Carvalho Chehab 2169a0bf528SMauro Carvalho Chehab return 0; 2179a0bf528SMauro Carvalho Chehab } 2189a0bf528SMauro Carvalho Chehab 2199a0bf528SMauro Carvalho Chehab static int or51211_set_parameters(struct dvb_frontend *fe) 2209a0bf528SMauro Carvalho Chehab { 2219a0bf528SMauro Carvalho Chehab struct dtv_frontend_properties *p = &fe->dtv_property_cache; 2229a0bf528SMauro Carvalho Chehab struct or51211_state* state = fe->demodulator_priv; 2239a0bf528SMauro Carvalho Chehab 2249a0bf528SMauro Carvalho Chehab /* Change only if we are actually changing the channel */ 2259a0bf528SMauro Carvalho Chehab if (state->current_frequency != p->frequency) { 2269a0bf528SMauro Carvalho Chehab if (fe->ops.tuner_ops.set_params) { 2279a0bf528SMauro Carvalho Chehab fe->ops.tuner_ops.set_params(fe); 2289a0bf528SMauro Carvalho Chehab if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); 2299a0bf528SMauro Carvalho Chehab } 2309a0bf528SMauro Carvalho Chehab 2319a0bf528SMauro Carvalho Chehab /* Set to ATSC mode */ 2329a0bf528SMauro Carvalho Chehab or51211_setmode(fe,0); 2339a0bf528SMauro Carvalho Chehab 2349a0bf528SMauro Carvalho Chehab /* Update current frequency */ 2359a0bf528SMauro Carvalho Chehab state->current_frequency = p->frequency; 2369a0bf528SMauro Carvalho Chehab } 2379a0bf528SMauro Carvalho Chehab return 0; 2389a0bf528SMauro Carvalho Chehab } 2399a0bf528SMauro Carvalho Chehab 2400df289a2SMauro Carvalho Chehab static int or51211_read_status(struct dvb_frontend *fe, enum fe_status *status) 2419a0bf528SMauro Carvalho Chehab { 2429a0bf528SMauro Carvalho Chehab struct or51211_state* state = fe->demodulator_priv; 2439a0bf528SMauro Carvalho Chehab unsigned char rec_buf[2]; 2449a0bf528SMauro Carvalho Chehab unsigned char snd_buf[] = {0x04,0x00,0x03,0x00}; 2459a0bf528SMauro Carvalho Chehab *status = 0; 2469a0bf528SMauro Carvalho Chehab 2479a0bf528SMauro Carvalho Chehab /* Receiver Status */ 2489a0bf528SMauro Carvalho Chehab if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) { 249bb9e31f3SAndy Shevchenko pr_warn("write error\n"); 2509a0bf528SMauro Carvalho Chehab return -1; 2519a0bf528SMauro Carvalho Chehab } 2529a0bf528SMauro Carvalho Chehab msleep(3); 2539a0bf528SMauro Carvalho Chehab if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { 254bb9e31f3SAndy Shevchenko pr_warn("read error\n"); 2559a0bf528SMauro Carvalho Chehab return -1; 2569a0bf528SMauro Carvalho Chehab } 257bb9e31f3SAndy Shevchenko dprintk("%x %x\n", rec_buf[0], rec_buf[1]); 2589a0bf528SMauro Carvalho Chehab 2599a0bf528SMauro Carvalho Chehab if (rec_buf[0] & 0x01) { /* Receiver Lock */ 2609a0bf528SMauro Carvalho Chehab *status |= FE_HAS_SIGNAL; 2619a0bf528SMauro Carvalho Chehab *status |= FE_HAS_CARRIER; 2629a0bf528SMauro Carvalho Chehab *status |= FE_HAS_VITERBI; 2639a0bf528SMauro Carvalho Chehab *status |= FE_HAS_SYNC; 2649a0bf528SMauro Carvalho Chehab *status |= FE_HAS_LOCK; 2659a0bf528SMauro Carvalho Chehab } 2669a0bf528SMauro Carvalho Chehab return 0; 2679a0bf528SMauro Carvalho Chehab } 2689a0bf528SMauro Carvalho Chehab 2699a0bf528SMauro Carvalho Chehab /* Calculate SNR estimation (scaled by 2^24) 2709a0bf528SMauro Carvalho Chehab 2719a0bf528SMauro Carvalho Chehab 8-VSB SNR equation from Oren datasheets 2729a0bf528SMauro Carvalho Chehab 2739a0bf528SMauro Carvalho Chehab For 8-VSB: 2749a0bf528SMauro Carvalho Chehab SNR[dB] = 10 * log10(219037.9454 / MSE^2 ) 2759a0bf528SMauro Carvalho Chehab 2769a0bf528SMauro Carvalho Chehab We re-write the snr equation as: 2779a0bf528SMauro Carvalho Chehab SNR * 2^24 = 10*(c - 2*intlog10(MSE)) 2789a0bf528SMauro Carvalho Chehab Where for 8-VSB, c = log10(219037.9454) * 2^24 */ 2799a0bf528SMauro Carvalho Chehab 2809a0bf528SMauro Carvalho Chehab static u32 calculate_snr(u32 mse, u32 c) 2819a0bf528SMauro Carvalho Chehab { 2829a0bf528SMauro Carvalho Chehab if (mse == 0) /* No signal */ 2839a0bf528SMauro Carvalho Chehab return 0; 2849a0bf528SMauro Carvalho Chehab 2859a0bf528SMauro Carvalho Chehab mse = 2*intlog10(mse); 2869a0bf528SMauro Carvalho Chehab if (mse > c) { 2879a0bf528SMauro Carvalho Chehab /* Negative SNR, which is possible, but realisticly the 2889a0bf528SMauro Carvalho Chehab demod will lose lock before the signal gets this bad. The 2899a0bf528SMauro Carvalho Chehab API only allows for unsigned values, so just return 0 */ 2909a0bf528SMauro Carvalho Chehab return 0; 2919a0bf528SMauro Carvalho Chehab } 2929a0bf528SMauro Carvalho Chehab return 10*(c - mse); 2939a0bf528SMauro Carvalho Chehab } 2949a0bf528SMauro Carvalho Chehab 2959a0bf528SMauro Carvalho Chehab static int or51211_read_snr(struct dvb_frontend* fe, u16* snr) 2969a0bf528SMauro Carvalho Chehab { 2979a0bf528SMauro Carvalho Chehab struct or51211_state* state = fe->demodulator_priv; 2989a0bf528SMauro Carvalho Chehab u8 rec_buf[2]; 2999a0bf528SMauro Carvalho Chehab u8 snd_buf[3]; 3009a0bf528SMauro Carvalho Chehab 3019a0bf528SMauro Carvalho Chehab /* SNR after Equalizer */ 3029a0bf528SMauro Carvalho Chehab snd_buf[0] = 0x04; 3039a0bf528SMauro Carvalho Chehab snd_buf[1] = 0x00; 3049a0bf528SMauro Carvalho Chehab snd_buf[2] = 0x04; 3059a0bf528SMauro Carvalho Chehab 3069a0bf528SMauro Carvalho Chehab if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) { 307bb9e31f3SAndy Shevchenko pr_warn("error writing snr reg\n"); 3089a0bf528SMauro Carvalho Chehab return -1; 3099a0bf528SMauro Carvalho Chehab } 3109a0bf528SMauro Carvalho Chehab if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { 311bb9e31f3SAndy Shevchenko pr_warn("read_status read error\n"); 3129a0bf528SMauro Carvalho Chehab return -1; 3139a0bf528SMauro Carvalho Chehab } 3149a0bf528SMauro Carvalho Chehab 3159a0bf528SMauro Carvalho Chehab state->snr = calculate_snr(rec_buf[0], 89599047); 3169a0bf528SMauro Carvalho Chehab *snr = (state->snr) >> 16; 3179a0bf528SMauro Carvalho Chehab 318bb9e31f3SAndy Shevchenko dprintk("noise = 0x%02x, snr = %d.%02d dB\n", rec_buf[0], 3199a0bf528SMauro Carvalho Chehab state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16); 3209a0bf528SMauro Carvalho Chehab 3219a0bf528SMauro Carvalho Chehab return 0; 3229a0bf528SMauro Carvalho Chehab } 3239a0bf528SMauro Carvalho Chehab 3249a0bf528SMauro Carvalho Chehab static int or51211_read_signal_strength(struct dvb_frontend* fe, u16* strength) 3259a0bf528SMauro Carvalho Chehab { 3269a0bf528SMauro Carvalho Chehab /* Calculate Strength from SNR up to 35dB */ 3279a0bf528SMauro Carvalho Chehab /* Even though the SNR can go higher than 35dB, there is some comfort */ 3289a0bf528SMauro Carvalho Chehab /* factor in having a range of strong signals that can show at 100% */ 3299a0bf528SMauro Carvalho Chehab struct or51211_state* state = (struct or51211_state*)fe->demodulator_priv; 3309a0bf528SMauro Carvalho Chehab u16 snr; 3319a0bf528SMauro Carvalho Chehab int ret; 3329a0bf528SMauro Carvalho Chehab 3339a0bf528SMauro Carvalho Chehab ret = fe->ops.read_snr(fe, &snr); 3349a0bf528SMauro Carvalho Chehab if (ret != 0) 3359a0bf528SMauro Carvalho Chehab return ret; 3369a0bf528SMauro Carvalho Chehab /* Rather than use the 8.8 value snr, use state->snr which is 8.24 */ 3379a0bf528SMauro Carvalho Chehab /* scale the range 0 - 35*2^24 into 0 - 65535 */ 3389a0bf528SMauro Carvalho Chehab if (state->snr >= 8960 * 0x10000) 3399a0bf528SMauro Carvalho Chehab *strength = 0xffff; 3409a0bf528SMauro Carvalho Chehab else 3419a0bf528SMauro Carvalho Chehab *strength = state->snr / 8960; 3429a0bf528SMauro Carvalho Chehab 3439a0bf528SMauro Carvalho Chehab return 0; 3449a0bf528SMauro Carvalho Chehab } 3459a0bf528SMauro Carvalho Chehab 3469a0bf528SMauro Carvalho Chehab static int or51211_read_ber(struct dvb_frontend* fe, u32* ber) 3479a0bf528SMauro Carvalho Chehab { 3489a0bf528SMauro Carvalho Chehab *ber = -ENOSYS; 3499a0bf528SMauro Carvalho Chehab return 0; 3509a0bf528SMauro Carvalho Chehab } 3519a0bf528SMauro Carvalho Chehab 3529a0bf528SMauro Carvalho Chehab static int or51211_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) 3539a0bf528SMauro Carvalho Chehab { 3549a0bf528SMauro Carvalho Chehab *ucblocks = -ENOSYS; 3559a0bf528SMauro Carvalho Chehab return 0; 3569a0bf528SMauro Carvalho Chehab } 3579a0bf528SMauro Carvalho Chehab 3589a0bf528SMauro Carvalho Chehab static int or51211_sleep(struct dvb_frontend* fe) 3599a0bf528SMauro Carvalho Chehab { 3609a0bf528SMauro Carvalho Chehab return 0; 3619a0bf528SMauro Carvalho Chehab } 3629a0bf528SMauro Carvalho Chehab 3639a0bf528SMauro Carvalho Chehab static int or51211_init(struct dvb_frontend* fe) 3649a0bf528SMauro Carvalho Chehab { 3659a0bf528SMauro Carvalho Chehab struct or51211_state* state = fe->demodulator_priv; 3669a0bf528SMauro Carvalho Chehab const struct or51211_config* config = state->config; 3679a0bf528SMauro Carvalho Chehab const struct firmware* fw; 3689a0bf528SMauro Carvalho Chehab unsigned char get_ver_buf[] = {0x04,0x00,0x30,0x00,0x00}; 3699a0bf528SMauro Carvalho Chehab unsigned char rec_buf[14]; 3709a0bf528SMauro Carvalho Chehab int ret,i; 3719a0bf528SMauro Carvalho Chehab 3729a0bf528SMauro Carvalho Chehab if (!state->initialized) { 3739a0bf528SMauro Carvalho Chehab /* Request the firmware, this will block until it uploads */ 374bb9e31f3SAndy Shevchenko pr_info("Waiting for firmware upload (%s)...\n", 375bb9e31f3SAndy Shevchenko OR51211_DEFAULT_FIRMWARE); 3769a0bf528SMauro Carvalho Chehab ret = config->request_firmware(fe, &fw, 3779a0bf528SMauro Carvalho Chehab OR51211_DEFAULT_FIRMWARE); 378bb9e31f3SAndy Shevchenko pr_info("Got Hotplug firmware\n"); 3799a0bf528SMauro Carvalho Chehab if (ret) { 380*4bd69e7bSMauro Carvalho Chehab pr_warn("No firmware uploaded (timeout or file not found?)\n"); 3819a0bf528SMauro Carvalho Chehab return ret; 3829a0bf528SMauro Carvalho Chehab } 3839a0bf528SMauro Carvalho Chehab 3849a0bf528SMauro Carvalho Chehab ret = or51211_load_firmware(fe, fw); 3859a0bf528SMauro Carvalho Chehab release_firmware(fw); 3869a0bf528SMauro Carvalho Chehab if (ret) { 387bb9e31f3SAndy Shevchenko pr_warn("Writing firmware to device failed!\n"); 3889a0bf528SMauro Carvalho Chehab return ret; 3899a0bf528SMauro Carvalho Chehab } 390bb9e31f3SAndy Shevchenko pr_info("Firmware upload complete.\n"); 3919a0bf528SMauro Carvalho Chehab 3929a0bf528SMauro Carvalho Chehab /* Set operation mode in Receiver 1 register; 3939a0bf528SMauro Carvalho Chehab * type 1: 3949a0bf528SMauro Carvalho Chehab * data 0x50h Automatic sets receiver channel conditions 3959a0bf528SMauro Carvalho Chehab * Automatic NTSC rejection filter 3969a0bf528SMauro Carvalho Chehab * Enable MPEG serial data output 3979a0bf528SMauro Carvalho Chehab * MPEG2tr 3989a0bf528SMauro Carvalho Chehab * High tuner phase noise 3999a0bf528SMauro Carvalho Chehab * normal +/-150kHz Carrier acquisition range 4009a0bf528SMauro Carvalho Chehab */ 4019a0bf528SMauro Carvalho Chehab if (i2c_writebytes(state,state->config->demod_address, 4029a0bf528SMauro Carvalho Chehab cmd_buf,3)) { 403bb9e31f3SAndy Shevchenko pr_warn("Load DVR Error 5\n"); 4049a0bf528SMauro Carvalho Chehab return -1; 4059a0bf528SMauro Carvalho Chehab } 4069a0bf528SMauro Carvalho Chehab 4079a0bf528SMauro Carvalho Chehab /* Read back ucode version to besure we loaded correctly */ 4089a0bf528SMauro Carvalho Chehab /* and are really up and running */ 4099a0bf528SMauro Carvalho Chehab rec_buf[0] = 0x04; 4109a0bf528SMauro Carvalho Chehab rec_buf[1] = 0x00; 4119a0bf528SMauro Carvalho Chehab rec_buf[2] = 0x03; 4129a0bf528SMauro Carvalho Chehab rec_buf[3] = 0x00; 4139a0bf528SMauro Carvalho Chehab msleep(30); 4149a0bf528SMauro Carvalho Chehab if (i2c_writebytes(state,state->config->demod_address, 4159a0bf528SMauro Carvalho Chehab rec_buf,3)) { 416bb9e31f3SAndy Shevchenko pr_warn("Load DVR Error A\n"); 4179a0bf528SMauro Carvalho Chehab return -1; 4189a0bf528SMauro Carvalho Chehab } 4199a0bf528SMauro Carvalho Chehab msleep(3); 4209a0bf528SMauro Carvalho Chehab if (i2c_readbytes(state,state->config->demod_address, 4219a0bf528SMauro Carvalho Chehab &rec_buf[10],2)) { 422bb9e31f3SAndy Shevchenko pr_warn("Load DVR Error B\n"); 4239a0bf528SMauro Carvalho Chehab return -1; 4249a0bf528SMauro Carvalho Chehab } 4259a0bf528SMauro Carvalho Chehab 4269a0bf528SMauro Carvalho Chehab rec_buf[0] = 0x04; 4279a0bf528SMauro Carvalho Chehab rec_buf[1] = 0x00; 4289a0bf528SMauro Carvalho Chehab rec_buf[2] = 0x01; 4299a0bf528SMauro Carvalho Chehab rec_buf[3] = 0x00; 4309a0bf528SMauro Carvalho Chehab msleep(20); 4319a0bf528SMauro Carvalho Chehab if (i2c_writebytes(state,state->config->demod_address, 4329a0bf528SMauro Carvalho Chehab rec_buf,3)) { 433bb9e31f3SAndy Shevchenko pr_warn("Load DVR Error C\n"); 4349a0bf528SMauro Carvalho Chehab return -1; 4359a0bf528SMauro Carvalho Chehab } 4369a0bf528SMauro Carvalho Chehab msleep(3); 4379a0bf528SMauro Carvalho Chehab if (i2c_readbytes(state,state->config->demod_address, 4389a0bf528SMauro Carvalho Chehab &rec_buf[12],2)) { 439bb9e31f3SAndy Shevchenko pr_warn("Load DVR Error D\n"); 4409a0bf528SMauro Carvalho Chehab return -1; 4419a0bf528SMauro Carvalho Chehab } 4429a0bf528SMauro Carvalho Chehab 4439a0bf528SMauro Carvalho Chehab for (i = 0; i < 8; i++) 4449a0bf528SMauro Carvalho Chehab rec_buf[i]=0xed; 4459a0bf528SMauro Carvalho Chehab 4469a0bf528SMauro Carvalho Chehab for (i = 0; i < 5; i++) { 4479a0bf528SMauro Carvalho Chehab msleep(30); 4489a0bf528SMauro Carvalho Chehab get_ver_buf[4] = i+1; 4499a0bf528SMauro Carvalho Chehab if (i2c_writebytes(state,state->config->demod_address, 4509a0bf528SMauro Carvalho Chehab get_ver_buf,5)) { 451bb9e31f3SAndy Shevchenko pr_warn("Load DVR Error 6 - %d\n", i); 4529a0bf528SMauro Carvalho Chehab return -1; 4539a0bf528SMauro Carvalho Chehab } 4549a0bf528SMauro Carvalho Chehab msleep(3); 4559a0bf528SMauro Carvalho Chehab 4569a0bf528SMauro Carvalho Chehab if (i2c_readbytes(state,state->config->demod_address, 4579a0bf528SMauro Carvalho Chehab &rec_buf[i*2],2)) { 458bb9e31f3SAndy Shevchenko pr_warn("Load DVR Error 7 - %d\n", i); 4599a0bf528SMauro Carvalho Chehab return -1; 4609a0bf528SMauro Carvalho Chehab } 4619a0bf528SMauro Carvalho Chehab /* If we didn't receive the right index, try again */ 4629a0bf528SMauro Carvalho Chehab if ((int)rec_buf[i*2+1]!=i+1){ 4639a0bf528SMauro Carvalho Chehab i--; 4649a0bf528SMauro Carvalho Chehab } 4659a0bf528SMauro Carvalho Chehab } 466870f31cbSAndy Shevchenko dprintk("read_fwbits %10ph\n", rec_buf); 4679a0bf528SMauro Carvalho Chehab 468bb9e31f3SAndy Shevchenko pr_info("ver TU%02x%02x%02x VSB mode %02x Status %02x\n", 469bb9e31f3SAndy Shevchenko rec_buf[2], rec_buf[4], rec_buf[6], rec_buf[12], 470bb9e31f3SAndy Shevchenko rec_buf[10]); 4719a0bf528SMauro Carvalho Chehab 4729a0bf528SMauro Carvalho Chehab rec_buf[0] = 0x04; 4739a0bf528SMauro Carvalho Chehab rec_buf[1] = 0x00; 4749a0bf528SMauro Carvalho Chehab rec_buf[2] = 0x03; 4759a0bf528SMauro Carvalho Chehab rec_buf[3] = 0x00; 4769a0bf528SMauro Carvalho Chehab msleep(20); 4779a0bf528SMauro Carvalho Chehab if (i2c_writebytes(state,state->config->demod_address, 4789a0bf528SMauro Carvalho Chehab rec_buf,3)) { 479bb9e31f3SAndy Shevchenko pr_warn("Load DVR Error 8\n"); 4809a0bf528SMauro Carvalho Chehab return -1; 4819a0bf528SMauro Carvalho Chehab } 4829a0bf528SMauro Carvalho Chehab msleep(20); 4839a0bf528SMauro Carvalho Chehab if (i2c_readbytes(state,state->config->demod_address, 4849a0bf528SMauro Carvalho Chehab &rec_buf[8],2)) { 485bb9e31f3SAndy Shevchenko pr_warn("Load DVR Error 9\n"); 4869a0bf528SMauro Carvalho Chehab return -1; 4879a0bf528SMauro Carvalho Chehab } 4889a0bf528SMauro Carvalho Chehab state->initialized = 1; 4899a0bf528SMauro Carvalho Chehab } 4909a0bf528SMauro Carvalho Chehab 4919a0bf528SMauro Carvalho Chehab return 0; 4929a0bf528SMauro Carvalho Chehab } 4939a0bf528SMauro Carvalho Chehab 4949a0bf528SMauro Carvalho Chehab static int or51211_get_tune_settings(struct dvb_frontend* fe, 4959a0bf528SMauro Carvalho Chehab struct dvb_frontend_tune_settings* fesettings) 4969a0bf528SMauro Carvalho Chehab { 4979a0bf528SMauro Carvalho Chehab fesettings->min_delay_ms = 500; 4989a0bf528SMauro Carvalho Chehab fesettings->step_size = 0; 4999a0bf528SMauro Carvalho Chehab fesettings->max_drift = 0; 5009a0bf528SMauro Carvalho Chehab return 0; 5019a0bf528SMauro Carvalho Chehab } 5029a0bf528SMauro Carvalho Chehab 5039a0bf528SMauro Carvalho Chehab static void or51211_release(struct dvb_frontend* fe) 5049a0bf528SMauro Carvalho Chehab { 5059a0bf528SMauro Carvalho Chehab struct or51211_state* state = fe->demodulator_priv; 5069a0bf528SMauro Carvalho Chehab state->config->sleep(fe); 5079a0bf528SMauro Carvalho Chehab kfree(state); 5089a0bf528SMauro Carvalho Chehab } 5099a0bf528SMauro Carvalho Chehab 5109a0bf528SMauro Carvalho Chehab static struct dvb_frontend_ops or51211_ops; 5119a0bf528SMauro Carvalho Chehab 5129a0bf528SMauro Carvalho Chehab struct dvb_frontend* or51211_attach(const struct or51211_config* config, 5139a0bf528SMauro Carvalho Chehab struct i2c_adapter* i2c) 5149a0bf528SMauro Carvalho Chehab { 5159a0bf528SMauro Carvalho Chehab struct or51211_state* state = NULL; 5169a0bf528SMauro Carvalho Chehab 5179a0bf528SMauro Carvalho Chehab /* Allocate memory for the internal state */ 5189a0bf528SMauro Carvalho Chehab state = kzalloc(sizeof(struct or51211_state), GFP_KERNEL); 5199a0bf528SMauro Carvalho Chehab if (state == NULL) 5209a0bf528SMauro Carvalho Chehab return NULL; 5219a0bf528SMauro Carvalho Chehab 5229a0bf528SMauro Carvalho Chehab /* Setup the state */ 5239a0bf528SMauro Carvalho Chehab state->config = config; 5249a0bf528SMauro Carvalho Chehab state->i2c = i2c; 5259a0bf528SMauro Carvalho Chehab state->initialized = 0; 5269a0bf528SMauro Carvalho Chehab state->current_frequency = 0; 5279a0bf528SMauro Carvalho Chehab 5289a0bf528SMauro Carvalho Chehab /* Create dvb_frontend */ 5299a0bf528SMauro Carvalho Chehab memcpy(&state->frontend.ops, &or51211_ops, sizeof(struct dvb_frontend_ops)); 5309a0bf528SMauro Carvalho Chehab state->frontend.demodulator_priv = state; 5319a0bf528SMauro Carvalho Chehab return &state->frontend; 5329a0bf528SMauro Carvalho Chehab } 5339a0bf528SMauro Carvalho Chehab 5349a0bf528SMauro Carvalho Chehab static struct dvb_frontend_ops or51211_ops = { 5359a0bf528SMauro Carvalho Chehab .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, 5369a0bf528SMauro Carvalho Chehab .info = { 5379a0bf528SMauro Carvalho Chehab .name = "Oren OR51211 VSB Frontend", 5389a0bf528SMauro Carvalho Chehab .frequency_min = 44000000, 5399a0bf528SMauro Carvalho Chehab .frequency_max = 958000000, 5409a0bf528SMauro Carvalho Chehab .frequency_stepsize = 166666, 5419a0bf528SMauro Carvalho Chehab .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 5429a0bf528SMauro Carvalho Chehab FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | 5439a0bf528SMauro Carvalho Chehab FE_CAN_8VSB 5449a0bf528SMauro Carvalho Chehab }, 5459a0bf528SMauro Carvalho Chehab 5469a0bf528SMauro Carvalho Chehab .release = or51211_release, 5479a0bf528SMauro Carvalho Chehab 5489a0bf528SMauro Carvalho Chehab .init = or51211_init, 5499a0bf528SMauro Carvalho Chehab .sleep = or51211_sleep, 5509a0bf528SMauro Carvalho Chehab 5519a0bf528SMauro Carvalho Chehab .set_frontend = or51211_set_parameters, 5529a0bf528SMauro Carvalho Chehab .get_tune_settings = or51211_get_tune_settings, 5539a0bf528SMauro Carvalho Chehab 5549a0bf528SMauro Carvalho Chehab .read_status = or51211_read_status, 5559a0bf528SMauro Carvalho Chehab .read_ber = or51211_read_ber, 5569a0bf528SMauro Carvalho Chehab .read_signal_strength = or51211_read_signal_strength, 5579a0bf528SMauro Carvalho Chehab .read_snr = or51211_read_snr, 5589a0bf528SMauro Carvalho Chehab .read_ucblocks = or51211_read_ucblocks, 5599a0bf528SMauro Carvalho Chehab }; 5609a0bf528SMauro Carvalho Chehab 5619a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644); 5629a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); 5639a0bf528SMauro Carvalho Chehab 5649a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("Oren OR51211 VSB [pcHDTV HD-2000] Demodulator Driver"); 5659a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Kirk Lapray"); 5669a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL"); 5679a0bf528SMauro Carvalho Chehab 5689a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(or51211_attach); 5699a0bf528SMauro Carvalho Chehab 570