19a0bf528SMauro Carvalho Chehab /* 29a0bf528SMauro Carvalho Chehab * Support for LGDT3302 and LGDT3303 - VSB/QAM 39a0bf528SMauro Carvalho Chehab * 49a0bf528SMauro Carvalho Chehab * Copyright (C) 2005 Wilson Michaels <wilsonmichaels@earthlink.net> 59a0bf528SMauro Carvalho Chehab * 69a0bf528SMauro Carvalho Chehab * This program is free software; you can redistribute it and/or modify 79a0bf528SMauro Carvalho Chehab * it under the terms of the GNU General Public License as published by 89a0bf528SMauro Carvalho Chehab * the Free Software Foundation; either version 2 of the License, or 99a0bf528SMauro Carvalho Chehab * (at your option) any later version. 109a0bf528SMauro Carvalho Chehab * 119a0bf528SMauro Carvalho Chehab * This program is distributed in the hope that it will be useful, 129a0bf528SMauro Carvalho Chehab * but WITHOUT ANY WARRANTY; without even the implied warranty of 139a0bf528SMauro Carvalho Chehab * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 149a0bf528SMauro Carvalho Chehab * GNU General Public License for more details. 159a0bf528SMauro Carvalho Chehab * 169a0bf528SMauro Carvalho Chehab */ 179a0bf528SMauro Carvalho Chehab 189a0bf528SMauro Carvalho Chehab /* 199a0bf528SMauro Carvalho Chehab * NOTES ABOUT THIS DRIVER 209a0bf528SMauro Carvalho Chehab * 219a0bf528SMauro Carvalho Chehab * This Linux driver supports: 229a0bf528SMauro Carvalho Chehab * DViCO FusionHDTV 3 Gold-Q 239a0bf528SMauro Carvalho Chehab * DViCO FusionHDTV 3 Gold-T 249a0bf528SMauro Carvalho Chehab * DViCO FusionHDTV 5 Gold 259a0bf528SMauro Carvalho Chehab * DViCO FusionHDTV 5 Lite 269a0bf528SMauro Carvalho Chehab * DViCO FusionHDTV 5 USB Gold 279a0bf528SMauro Carvalho Chehab * Air2PC/AirStar 2 ATSC 3rd generation (HD5000) 289a0bf528SMauro Carvalho Chehab * pcHDTV HD5500 299a0bf528SMauro Carvalho Chehab * 309a0bf528SMauro Carvalho Chehab */ 319a0bf528SMauro Carvalho Chehab 329a0bf528SMauro Carvalho Chehab #include <linux/kernel.h> 339a0bf528SMauro Carvalho Chehab #include <linux/module.h> 349a0bf528SMauro Carvalho Chehab #include <linux/init.h> 359a0bf528SMauro Carvalho Chehab #include <linux/delay.h> 369a0bf528SMauro Carvalho Chehab #include <linux/string.h> 379a0bf528SMauro Carvalho Chehab #include <linux/slab.h> 389a0bf528SMauro Carvalho Chehab #include <asm/byteorder.h> 399a0bf528SMauro Carvalho Chehab 40fada1935SMauro Carvalho Chehab #include <media/dvb_frontend.h> 41fada1935SMauro Carvalho Chehab #include <media/dvb_math.h> 429a0bf528SMauro Carvalho Chehab #include "lgdt330x_priv.h" 439a0bf528SMauro Carvalho Chehab #include "lgdt330x.h" 449a0bf528SMauro Carvalho Chehab 459a0bf528SMauro Carvalho Chehab /* Use Equalizer Mean Squared Error instead of Phaser Tracker MSE */ 469a0bf528SMauro Carvalho Chehab /* #define USE_EQMSE */ 479a0bf528SMauro Carvalho Chehab 489a0bf528SMauro Carvalho Chehab static int debug; 499a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644); 509a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Turn on/off lgdt330x frontend debugging (default:off)."); 516752c797SMauro Carvalho Chehab 5223ba635dSMauro Carvalho Chehab #define dprintk(state, fmt, arg...) do { \ 53467845a1SMauro Carvalho Chehab if (debug) \ 5423ba635dSMauro Carvalho Chehab dev_printk(KERN_DEBUG, &state->client->dev, fmt, ##arg);\ 559a0bf528SMauro Carvalho Chehab } while (0) 569a0bf528SMauro Carvalho Chehab 57467845a1SMauro Carvalho Chehab struct lgdt330x_state { 5823ba635dSMauro Carvalho Chehab struct i2c_client *client; 599a0bf528SMauro Carvalho Chehab 609a0bf528SMauro Carvalho Chehab /* Configuration settings */ 6123ba635dSMauro Carvalho Chehab struct lgdt330x_config config; 629a0bf528SMauro Carvalho Chehab 639a0bf528SMauro Carvalho Chehab struct dvb_frontend frontend; 649a0bf528SMauro Carvalho Chehab 659a0bf528SMauro Carvalho Chehab /* Demodulator private data */ 660df289a2SMauro Carvalho Chehab enum fe_modulation current_modulation; 679a0bf528SMauro Carvalho Chehab u32 snr; /* Result of last SNR calculation */ 689a0bf528SMauro Carvalho Chehab 699a0bf528SMauro Carvalho Chehab /* Tuner private data */ 709a0bf528SMauro Carvalho Chehab u32 current_frequency; 719a0bf528SMauro Carvalho Chehab }; 729a0bf528SMauro Carvalho Chehab 739a0bf528SMauro Carvalho Chehab static int i2c_write_demod_bytes(struct lgdt330x_state *state, 7423ba635dSMauro Carvalho Chehab const u8 *buf, /* data bytes to send */ 759a0bf528SMauro Carvalho Chehab int len /* number of bytes to send */) 769a0bf528SMauro Carvalho Chehab { 779a0bf528SMauro Carvalho Chehab int i; 789a0bf528SMauro Carvalho Chehab int err; 799a0bf528SMauro Carvalho Chehab 809a0bf528SMauro Carvalho Chehab for (i = 0; i < len - 1; i += 2) { 8123ba635dSMauro Carvalho Chehab err = i2c_master_send(state->client, buf, 2); 8223ba635dSMauro Carvalho Chehab if (err != 2) { 8323ba635dSMauro Carvalho Chehab dev_warn(&state->client->dev, 8423ba635dSMauro Carvalho Chehab "%s: error (addr %02x <- %02x, err = %i)\n", 8523ba635dSMauro Carvalho Chehab __func__, buf[0], buf[1], err); 869a0bf528SMauro Carvalho Chehab if (err < 0) 879a0bf528SMauro Carvalho Chehab return err; 889a0bf528SMauro Carvalho Chehab else 899a0bf528SMauro Carvalho Chehab return -EREMOTEIO; 909a0bf528SMauro Carvalho Chehab } 9123ba635dSMauro Carvalho Chehab buf += 2; 929a0bf528SMauro Carvalho Chehab } 939a0bf528SMauro Carvalho Chehab return 0; 949a0bf528SMauro Carvalho Chehab } 959a0bf528SMauro Carvalho Chehab 969a0bf528SMauro Carvalho Chehab /* 979a0bf528SMauro Carvalho Chehab * This routine writes the register (reg) to the demod bus 989a0bf528SMauro Carvalho Chehab * then reads the data returned for (len) bytes. 999a0bf528SMauro Carvalho Chehab */ 1009a0bf528SMauro Carvalho Chehab static int i2c_read_demod_bytes(struct lgdt330x_state *state, 1019a0bf528SMauro Carvalho Chehab enum I2C_REG reg, u8 *buf, int len) 1029a0bf528SMauro Carvalho Chehab { 1039a0bf528SMauro Carvalho Chehab u8 wr[] = { reg }; 1049a0bf528SMauro Carvalho Chehab struct i2c_msg msg[] = { 105467845a1SMauro Carvalho Chehab { 10623ba635dSMauro Carvalho Chehab .addr = state->client->addr, 107467845a1SMauro Carvalho Chehab .flags = 0, 108467845a1SMauro Carvalho Chehab .buf = wr, 109467845a1SMauro Carvalho Chehab .len = 1 110467845a1SMauro Carvalho Chehab }, { 11123ba635dSMauro Carvalho Chehab .addr = state->client->addr, 112467845a1SMauro Carvalho Chehab .flags = I2C_M_RD, 113467845a1SMauro Carvalho Chehab .buf = buf, 114467845a1SMauro Carvalho Chehab .len = len 115467845a1SMauro Carvalho Chehab }, 1169a0bf528SMauro Carvalho Chehab }; 1179a0bf528SMauro Carvalho Chehab int ret; 118467845a1SMauro Carvalho Chehab 11923ba635dSMauro Carvalho Chehab ret = i2c_transfer(state->client->adapter, msg, 2); 1209a0bf528SMauro Carvalho Chehab if (ret != 2) { 12123ba635dSMauro Carvalho Chehab dev_warn(&state->client->dev, 12223ba635dSMauro Carvalho Chehab "%s: addr 0x%02x select 0x%02x error (ret == %i)\n", 12323ba635dSMauro Carvalho Chehab __func__, state->client->addr, reg, ret); 1249a0bf528SMauro Carvalho Chehab if (ret >= 0) 1259a0bf528SMauro Carvalho Chehab ret = -EIO; 1269a0bf528SMauro Carvalho Chehab } else { 1279a0bf528SMauro Carvalho Chehab ret = 0; 1289a0bf528SMauro Carvalho Chehab } 1299a0bf528SMauro Carvalho Chehab return ret; 1309a0bf528SMauro Carvalho Chehab } 1319a0bf528SMauro Carvalho Chehab 1329a0bf528SMauro Carvalho Chehab /* Software reset */ 133467845a1SMauro Carvalho Chehab static int lgdt3302_sw_reset(struct lgdt330x_state *state) 1349a0bf528SMauro Carvalho Chehab { 1359a0bf528SMauro Carvalho Chehab u8 ret; 1369a0bf528SMauro Carvalho Chehab u8 reset[] = { 1379a0bf528SMauro Carvalho Chehab IRQ_MASK, 138467845a1SMauro Carvalho Chehab /* 139467845a1SMauro Carvalho Chehab * bit 6 is active low software reset 140467845a1SMauro Carvalho Chehab * bits 5-0 are 1 to mask interrupts 141467845a1SMauro Carvalho Chehab */ 142467845a1SMauro Carvalho Chehab 0x00 1439a0bf528SMauro Carvalho Chehab }; 1449a0bf528SMauro Carvalho Chehab 1459a0bf528SMauro Carvalho Chehab ret = i2c_write_demod_bytes(state, 1469a0bf528SMauro Carvalho Chehab reset, sizeof(reset)); 1479a0bf528SMauro Carvalho Chehab if (ret == 0) { 1489a0bf528SMauro Carvalho Chehab /* force reset high (inactive) and unmask interrupts */ 1499a0bf528SMauro Carvalho Chehab reset[1] = 0x7f; 1509a0bf528SMauro Carvalho Chehab ret = i2c_write_demod_bytes(state, 1519a0bf528SMauro Carvalho Chehab reset, sizeof(reset)); 1529a0bf528SMauro Carvalho Chehab } 1539a0bf528SMauro Carvalho Chehab return ret; 1549a0bf528SMauro Carvalho Chehab } 1559a0bf528SMauro Carvalho Chehab 156467845a1SMauro Carvalho Chehab static int lgdt3303_sw_reset(struct lgdt330x_state *state) 1579a0bf528SMauro Carvalho Chehab { 1589a0bf528SMauro Carvalho Chehab u8 ret; 1599a0bf528SMauro Carvalho Chehab u8 reset[] = { 1609a0bf528SMauro Carvalho Chehab 0x02, 1619a0bf528SMauro Carvalho Chehab 0x00 /* bit 0 is active low software reset */ 1629a0bf528SMauro Carvalho Chehab }; 1639a0bf528SMauro Carvalho Chehab 1649a0bf528SMauro Carvalho Chehab ret = i2c_write_demod_bytes(state, 1659a0bf528SMauro Carvalho Chehab reset, sizeof(reset)); 1669a0bf528SMauro Carvalho Chehab if (ret == 0) { 1679a0bf528SMauro Carvalho Chehab /* force reset high (inactive) */ 1689a0bf528SMauro Carvalho Chehab reset[1] = 0x01; 1699a0bf528SMauro Carvalho Chehab ret = i2c_write_demod_bytes(state, 1709a0bf528SMauro Carvalho Chehab reset, sizeof(reset)); 1719a0bf528SMauro Carvalho Chehab } 1729a0bf528SMauro Carvalho Chehab return ret; 1739a0bf528SMauro Carvalho Chehab } 1749a0bf528SMauro Carvalho Chehab 175467845a1SMauro Carvalho Chehab static int lgdt330x_sw_reset(struct lgdt330x_state *state) 1769a0bf528SMauro Carvalho Chehab { 17723ba635dSMauro Carvalho Chehab switch (state->config.demod_chip) { 1789a0bf528SMauro Carvalho Chehab case LGDT3302: 179467845a1SMauro Carvalho Chehab return lgdt3302_sw_reset(state); 1809a0bf528SMauro Carvalho Chehab case LGDT3303: 181467845a1SMauro Carvalho Chehab return lgdt3303_sw_reset(state); 1829a0bf528SMauro Carvalho Chehab default: 1839a0bf528SMauro Carvalho Chehab return -ENODEV; 1849a0bf528SMauro Carvalho Chehab } 1859a0bf528SMauro Carvalho Chehab } 1869a0bf528SMauro Carvalho Chehab 1879a0bf528SMauro Carvalho Chehab static int lgdt330x_init(struct dvb_frontend *fe) 1889a0bf528SMauro Carvalho Chehab { 1891334a7dcSMauro Carvalho Chehab struct lgdt330x_state *state = fe->demodulator_priv; 1901334a7dcSMauro Carvalho Chehab char *chip_name; 1911334a7dcSMauro Carvalho Chehab int err; 1929a0bf528SMauro Carvalho Chehab /* 1939a0bf528SMauro Carvalho Chehab * Array of byte pairs <address, value> 1949a0bf528SMauro Carvalho Chehab * to initialize each different chip 1959a0bf528SMauro Carvalho Chehab */ 1961334a7dcSMauro Carvalho Chehab static const u8 lgdt3302_init_data[] = { 197467845a1SMauro Carvalho Chehab /* Use 50MHz param values from spec sheet since xtal is 50 */ 198467845a1SMauro Carvalho Chehab /* 199467845a1SMauro Carvalho Chehab * Change the value of NCOCTFV[25:0] of carrier 200467845a1SMauro Carvalho Chehab * recovery center frequency register 201467845a1SMauro Carvalho Chehab */ 2029a0bf528SMauro Carvalho Chehab VSB_CARRIER_FREQ0, 0x00, 2039a0bf528SMauro Carvalho Chehab VSB_CARRIER_FREQ1, 0x87, 2049a0bf528SMauro Carvalho Chehab VSB_CARRIER_FREQ2, 0x8e, 2059a0bf528SMauro Carvalho Chehab VSB_CARRIER_FREQ3, 0x01, 206467845a1SMauro Carvalho Chehab /* 207467845a1SMauro Carvalho Chehab * Change the TPCLK pin polarity 208467845a1SMauro Carvalho Chehab * data is valid on falling clock 209467845a1SMauro Carvalho Chehab */ 2109a0bf528SMauro Carvalho Chehab DEMUX_CONTROL, 0xfb, 211467845a1SMauro Carvalho Chehab /* 212467845a1SMauro Carvalho Chehab * Change the value of IFBW[11:0] of 213467845a1SMauro Carvalho Chehab * AGC IF/RF loop filter bandwidth register 214467845a1SMauro Carvalho Chehab */ 2159a0bf528SMauro Carvalho Chehab AGC_RF_BANDWIDTH0, 0x40, 2169a0bf528SMauro Carvalho Chehab AGC_RF_BANDWIDTH1, 0x93, 2179a0bf528SMauro Carvalho Chehab AGC_RF_BANDWIDTH2, 0x00, 218467845a1SMauro Carvalho Chehab /* 219467845a1SMauro Carvalho Chehab * Change the value of bit 6, 'nINAGCBY' and 220467845a1SMauro Carvalho Chehab * 'NSSEL[1:0] of ACG function control register 2 221467845a1SMauro Carvalho Chehab */ 2229a0bf528SMauro Carvalho Chehab AGC_FUNC_CTRL2, 0xc6, 223467845a1SMauro Carvalho Chehab /* 224467845a1SMauro Carvalho Chehab * Change the value of bit 6 'RFFIX' 225467845a1SMauro Carvalho Chehab * of AGC function control register 3 226467845a1SMauro Carvalho Chehab */ 2279a0bf528SMauro Carvalho Chehab AGC_FUNC_CTRL3, 0x40, 228467845a1SMauro Carvalho Chehab /* 229467845a1SMauro Carvalho Chehab * Set the value of 'INLVTHD' register 0x2a/0x2c 230467845a1SMauro Carvalho Chehab * to 0x7fe 231467845a1SMauro Carvalho Chehab */ 2329a0bf528SMauro Carvalho Chehab AGC_DELAY0, 0x07, 2339a0bf528SMauro Carvalho Chehab AGC_DELAY2, 0xfe, 234467845a1SMauro Carvalho Chehab /* 235467845a1SMauro Carvalho Chehab * Change the value of IAGCBW[15:8] 236467845a1SMauro Carvalho Chehab * of inner AGC loop filter bandwidth 237467845a1SMauro Carvalho Chehab */ 2389a0bf528SMauro Carvalho Chehab AGC_LOOP_BANDWIDTH0, 0x08, 2399a0bf528SMauro Carvalho Chehab AGC_LOOP_BANDWIDTH1, 0x9a 2409a0bf528SMauro Carvalho Chehab }; 2411334a7dcSMauro Carvalho Chehab static const u8 lgdt3303_init_data[] = { 2429a0bf528SMauro Carvalho Chehab 0x4c, 0x14 2439a0bf528SMauro Carvalho Chehab }; 2441334a7dcSMauro Carvalho Chehab static const u8 flip_1_lgdt3303_init_data[] = { 2459a0bf528SMauro Carvalho Chehab 0x4c, 0x14, 2469a0bf528SMauro Carvalho Chehab 0x87, 0xf3 2479a0bf528SMauro Carvalho Chehab }; 2481334a7dcSMauro Carvalho Chehab static const u8 flip_2_lgdt3303_init_data[] = { 2499a0bf528SMauro Carvalho Chehab 0x4c, 0x14, 2509a0bf528SMauro Carvalho Chehab 0x87, 0xda 2519a0bf528SMauro Carvalho Chehab }; 2529a0bf528SMauro Carvalho Chehab 2531334a7dcSMauro Carvalho Chehab /* 2541334a7dcSMauro Carvalho Chehab * Hardware reset is done using gpio[0] of cx23880x chip. 2551334a7dcSMauro Carvalho Chehab * I'd like to do it here, but don't know how to find chip address. 2561334a7dcSMauro Carvalho Chehab * cx88-cards.c arranges for the reset bit to be inactive (high). 2571334a7dcSMauro Carvalho Chehab * Maybe there needs to be a callable function in cx88-core or 2581334a7dcSMauro Carvalho Chehab * the caller of this function needs to do it. 2591334a7dcSMauro Carvalho Chehab */ 2609a0bf528SMauro Carvalho Chehab 26123ba635dSMauro Carvalho Chehab switch (state->config.demod_chip) { 2629a0bf528SMauro Carvalho Chehab case LGDT3302: 2639a0bf528SMauro Carvalho Chehab chip_name = "LGDT3302"; 2649a0bf528SMauro Carvalho Chehab err = i2c_write_demod_bytes(state, lgdt3302_init_data, 2659a0bf528SMauro Carvalho Chehab sizeof(lgdt3302_init_data)); 2669a0bf528SMauro Carvalho Chehab break; 2679a0bf528SMauro Carvalho Chehab case LGDT3303: 2689a0bf528SMauro Carvalho Chehab chip_name = "LGDT3303"; 26923ba635dSMauro Carvalho Chehab switch (state->config.clock_polarity_flip) { 2709a0bf528SMauro Carvalho Chehab case 2: 2719a0bf528SMauro Carvalho Chehab err = i2c_write_demod_bytes(state, 2729a0bf528SMauro Carvalho Chehab flip_2_lgdt3303_init_data, 2739a0bf528SMauro Carvalho Chehab sizeof(flip_2_lgdt3303_init_data)); 2749a0bf528SMauro Carvalho Chehab break; 2759a0bf528SMauro Carvalho Chehab case 1: 2769a0bf528SMauro Carvalho Chehab err = i2c_write_demod_bytes(state, 2779a0bf528SMauro Carvalho Chehab flip_1_lgdt3303_init_data, 2789a0bf528SMauro Carvalho Chehab sizeof(flip_1_lgdt3303_init_data)); 2799a0bf528SMauro Carvalho Chehab break; 2809a0bf528SMauro Carvalho Chehab case 0: 2819a0bf528SMauro Carvalho Chehab default: 2829a0bf528SMauro Carvalho Chehab err = i2c_write_demod_bytes(state, lgdt3303_init_data, 2839a0bf528SMauro Carvalho Chehab sizeof(lgdt3303_init_data)); 2849a0bf528SMauro Carvalho Chehab } 2859a0bf528SMauro Carvalho Chehab break; 2869a0bf528SMauro Carvalho Chehab default: 2879a0bf528SMauro Carvalho Chehab chip_name = "undefined"; 28823ba635dSMauro Carvalho Chehab dev_warn(&state->client->dev, 28923ba635dSMauro Carvalho Chehab "Only LGDT3302 and LGDT3303 are supported chips.\n"); 2909a0bf528SMauro Carvalho Chehab err = -ENODEV; 2919a0bf528SMauro Carvalho Chehab } 29223ba635dSMauro Carvalho Chehab dprintk(state, "Initialized the %s chip\n", chip_name); 2939a0bf528SMauro Carvalho Chehab if (err < 0) 2949a0bf528SMauro Carvalho Chehab return err; 295467845a1SMauro Carvalho Chehab return lgdt330x_sw_reset(state); 2969a0bf528SMauro Carvalho Chehab } 2979a0bf528SMauro Carvalho Chehab 2989a0bf528SMauro Carvalho Chehab static int lgdt330x_read_ber(struct dvb_frontend *fe, u32 *ber) 2999a0bf528SMauro Carvalho Chehab { 3009a0bf528SMauro Carvalho Chehab *ber = 0; /* Not supplied by the demod chips */ 3019a0bf528SMauro Carvalho Chehab return 0; 3029a0bf528SMauro Carvalho Chehab } 3039a0bf528SMauro Carvalho Chehab 3049a0bf528SMauro Carvalho Chehab static int lgdt330x_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) 3059a0bf528SMauro Carvalho Chehab { 3069a0bf528SMauro Carvalho Chehab struct lgdt330x_state *state = fe->demodulator_priv; 3079a0bf528SMauro Carvalho Chehab int err; 3089a0bf528SMauro Carvalho Chehab u8 buf[2]; 3099a0bf528SMauro Carvalho Chehab 3109a0bf528SMauro Carvalho Chehab *ucblocks = 0; 3119a0bf528SMauro Carvalho Chehab 31223ba635dSMauro Carvalho Chehab switch (state->config.demod_chip) { 3139a0bf528SMauro Carvalho Chehab case LGDT3302: 3149a0bf528SMauro Carvalho Chehab err = i2c_read_demod_bytes(state, LGDT3302_PACKET_ERR_COUNTER1, 3159a0bf528SMauro Carvalho Chehab buf, sizeof(buf)); 3169a0bf528SMauro Carvalho Chehab break; 3179a0bf528SMauro Carvalho Chehab case LGDT3303: 3189a0bf528SMauro Carvalho Chehab err = i2c_read_demod_bytes(state, LGDT3303_PACKET_ERR_COUNTER1, 3199a0bf528SMauro Carvalho Chehab buf, sizeof(buf)); 3209a0bf528SMauro Carvalho Chehab break; 3219a0bf528SMauro Carvalho Chehab default: 32223ba635dSMauro Carvalho Chehab dev_warn(&state->client->dev, 32323ba635dSMauro Carvalho Chehab "Only LGDT3302 and LGDT3303 are supported chips.\n"); 3249a0bf528SMauro Carvalho Chehab err = -ENODEV; 3259a0bf528SMauro Carvalho Chehab } 3269a0bf528SMauro Carvalho Chehab if (err < 0) 3279a0bf528SMauro Carvalho Chehab return err; 3289a0bf528SMauro Carvalho Chehab 3299a0bf528SMauro Carvalho Chehab *ucblocks = (buf[0] << 8) | buf[1]; 3309a0bf528SMauro Carvalho Chehab return 0; 3319a0bf528SMauro Carvalho Chehab } 3329a0bf528SMauro Carvalho Chehab 3339a0bf528SMauro Carvalho Chehab static int lgdt330x_set_parameters(struct dvb_frontend *fe) 3349a0bf528SMauro Carvalho Chehab { 3359a0bf528SMauro Carvalho Chehab struct dtv_frontend_properties *p = &fe->dtv_property_cache; 3361334a7dcSMauro Carvalho Chehab struct lgdt330x_state *state = fe->demodulator_priv; 3379a0bf528SMauro Carvalho Chehab /* 3389a0bf528SMauro Carvalho Chehab * Array of byte pairs <address, value> 3399a0bf528SMauro Carvalho Chehab * to initialize 8VSB for lgdt3303 chip 50 MHz IF 3409a0bf528SMauro Carvalho Chehab */ 3411334a7dcSMauro Carvalho Chehab static const u8 lgdt3303_8vsb_44_data[] = { 3429a0bf528SMauro Carvalho Chehab 0x04, 0x00, 3439a0bf528SMauro Carvalho Chehab 0x0d, 0x40, 3449a0bf528SMauro Carvalho Chehab 0x0e, 0x87, 3459a0bf528SMauro Carvalho Chehab 0x0f, 0x8e, 3469a0bf528SMauro Carvalho Chehab 0x10, 0x01, 347467845a1SMauro Carvalho Chehab 0x47, 0x8b 348467845a1SMauro Carvalho Chehab }; 3499a0bf528SMauro Carvalho Chehab /* 3509a0bf528SMauro Carvalho Chehab * Array of byte pairs <address, value> 3519a0bf528SMauro Carvalho Chehab * to initialize QAM for lgdt3303 chip 3529a0bf528SMauro Carvalho Chehab */ 3531334a7dcSMauro Carvalho Chehab static const u8 lgdt3303_qam_data[] = { 3549a0bf528SMauro Carvalho Chehab 0x04, 0x00, 3559a0bf528SMauro Carvalho Chehab 0x0d, 0x00, 3569a0bf528SMauro Carvalho Chehab 0x0e, 0x00, 3579a0bf528SMauro Carvalho Chehab 0x0f, 0x00, 3589a0bf528SMauro Carvalho Chehab 0x10, 0x00, 3599a0bf528SMauro Carvalho Chehab 0x51, 0x63, 3609a0bf528SMauro Carvalho Chehab 0x47, 0x66, 3619a0bf528SMauro Carvalho Chehab 0x48, 0x66, 3629a0bf528SMauro Carvalho Chehab 0x4d, 0x1a, 3639a0bf528SMauro Carvalho Chehab 0x49, 0x08, 364467845a1SMauro Carvalho Chehab 0x4a, 0x9b 365467845a1SMauro Carvalho Chehab }; 3661334a7dcSMauro Carvalho Chehab u8 top_ctrl_cfg[] = { TOP_CONTROL, 0x03 }; 3679a0bf528SMauro Carvalho Chehab 3689a0bf528SMauro Carvalho Chehab int err = 0; 3699a0bf528SMauro Carvalho Chehab /* Change only if we are actually changing the modulation */ 3709a0bf528SMauro Carvalho Chehab if (state->current_modulation != p->modulation) { 3719a0bf528SMauro Carvalho Chehab switch (p->modulation) { 3729a0bf528SMauro Carvalho Chehab case VSB_8: 37323ba635dSMauro Carvalho Chehab dprintk(state, "VSB_8 MODE\n"); 3749a0bf528SMauro Carvalho Chehab 3759a0bf528SMauro Carvalho Chehab /* Select VSB mode */ 3769a0bf528SMauro Carvalho Chehab top_ctrl_cfg[1] = 0x03; 3779a0bf528SMauro Carvalho Chehab 3789a0bf528SMauro Carvalho Chehab /* Select ANT connector if supported by card */ 37923ba635dSMauro Carvalho Chehab if (state->config.pll_rf_set) 38023ba635dSMauro Carvalho Chehab state->config.pll_rf_set(fe, 1); 3819a0bf528SMauro Carvalho Chehab 38223ba635dSMauro Carvalho Chehab if (state->config.demod_chip == LGDT3303) { 383467845a1SMauro Carvalho Chehab err = i2c_write_demod_bytes(state, 384467845a1SMauro Carvalho Chehab lgdt3303_8vsb_44_data, 3859a0bf528SMauro Carvalho Chehab sizeof(lgdt3303_8vsb_44_data)); 3869a0bf528SMauro Carvalho Chehab } 3879a0bf528SMauro Carvalho Chehab break; 3889a0bf528SMauro Carvalho Chehab 3899a0bf528SMauro Carvalho Chehab case QAM_64: 39023ba635dSMauro Carvalho Chehab dprintk(state, "QAM_64 MODE\n"); 3919a0bf528SMauro Carvalho Chehab 3929a0bf528SMauro Carvalho Chehab /* Select QAM_64 mode */ 3939a0bf528SMauro Carvalho Chehab top_ctrl_cfg[1] = 0x00; 3949a0bf528SMauro Carvalho Chehab 3959a0bf528SMauro Carvalho Chehab /* Select CABLE connector if supported by card */ 39623ba635dSMauro Carvalho Chehab if (state->config.pll_rf_set) 39723ba635dSMauro Carvalho Chehab state->config.pll_rf_set(fe, 0); 3989a0bf528SMauro Carvalho Chehab 39923ba635dSMauro Carvalho Chehab if (state->config.demod_chip == LGDT3303) { 400467845a1SMauro Carvalho Chehab err = i2c_write_demod_bytes(state, 401467845a1SMauro Carvalho Chehab lgdt3303_qam_data, 4029a0bf528SMauro Carvalho Chehab sizeof(lgdt3303_qam_data)); 4039a0bf528SMauro Carvalho Chehab } 4049a0bf528SMauro Carvalho Chehab break; 4059a0bf528SMauro Carvalho Chehab 4069a0bf528SMauro Carvalho Chehab case QAM_256: 40723ba635dSMauro Carvalho Chehab dprintk(state, "QAM_256 MODE\n"); 4089a0bf528SMauro Carvalho Chehab 4099a0bf528SMauro Carvalho Chehab /* Select QAM_256 mode */ 4109a0bf528SMauro Carvalho Chehab top_ctrl_cfg[1] = 0x01; 4119a0bf528SMauro Carvalho Chehab 4129a0bf528SMauro Carvalho Chehab /* Select CABLE connector if supported by card */ 41323ba635dSMauro Carvalho Chehab if (state->config.pll_rf_set) 41423ba635dSMauro Carvalho Chehab state->config.pll_rf_set(fe, 0); 4159a0bf528SMauro Carvalho Chehab 41623ba635dSMauro Carvalho Chehab if (state->config.demod_chip == LGDT3303) { 417467845a1SMauro Carvalho Chehab err = i2c_write_demod_bytes(state, 418467845a1SMauro Carvalho Chehab lgdt3303_qam_data, 4199a0bf528SMauro Carvalho Chehab sizeof(lgdt3303_qam_data)); 4209a0bf528SMauro Carvalho Chehab } 4219a0bf528SMauro Carvalho Chehab break; 4229a0bf528SMauro Carvalho Chehab default: 42323ba635dSMauro Carvalho Chehab dev_warn(&state->client->dev, 42423ba635dSMauro Carvalho Chehab "%s: Modulation type(%d) UNSUPPORTED\n", 425467845a1SMauro Carvalho Chehab __func__, p->modulation); 4269a0bf528SMauro Carvalho Chehab return -1; 4279a0bf528SMauro Carvalho Chehab } 4289a0bf528SMauro Carvalho Chehab if (err < 0) 42923ba635dSMauro Carvalho Chehab dev_warn(&state->client->dev, 43023ba635dSMauro Carvalho Chehab "%s: error blasting bytes to lgdt3303 for modulation type(%d)\n", 4319a0bf528SMauro Carvalho Chehab __func__, p->modulation); 4329a0bf528SMauro Carvalho Chehab 4339a0bf528SMauro Carvalho Chehab /* 434467845a1SMauro Carvalho Chehab * select serial or parallel MPEG hardware interface 4359a0bf528SMauro Carvalho Chehab * Serial: 0x04 for LGDT3302 or 0x40 for LGDT3303 4369a0bf528SMauro Carvalho Chehab * Parallel: 0x00 4379a0bf528SMauro Carvalho Chehab */ 43823ba635dSMauro Carvalho Chehab top_ctrl_cfg[1] |= state->config.serial_mpeg; 4399a0bf528SMauro Carvalho Chehab 4409a0bf528SMauro Carvalho Chehab /* Select the requested mode */ 4419a0bf528SMauro Carvalho Chehab i2c_write_demod_bytes(state, top_ctrl_cfg, 4429a0bf528SMauro Carvalho Chehab sizeof(top_ctrl_cfg)); 44323ba635dSMauro Carvalho Chehab if (state->config.set_ts_params) 44423ba635dSMauro Carvalho Chehab state->config.set_ts_params(fe, 0); 4459a0bf528SMauro Carvalho Chehab state->current_modulation = p->modulation; 4469a0bf528SMauro Carvalho Chehab } 4479a0bf528SMauro Carvalho Chehab 4489a0bf528SMauro Carvalho Chehab /* Tune to the specified frequency */ 4499a0bf528SMauro Carvalho Chehab if (fe->ops.tuner_ops.set_params) { 4509a0bf528SMauro Carvalho Chehab fe->ops.tuner_ops.set_params(fe); 451467845a1SMauro Carvalho Chehab if (fe->ops.i2c_gate_ctrl) 452467845a1SMauro Carvalho Chehab fe->ops.i2c_gate_ctrl(fe, 0); 4539a0bf528SMauro Carvalho Chehab } 4549a0bf528SMauro Carvalho Chehab 4559a0bf528SMauro Carvalho Chehab /* Keep track of the new frequency */ 456467845a1SMauro Carvalho Chehab /* 457467845a1SMauro Carvalho Chehab * FIXME this is the wrong way to do this... 458467845a1SMauro Carvalho Chehab * The tuner is shared with the video4linux analog API 459467845a1SMauro Carvalho Chehab */ 4609a0bf528SMauro Carvalho Chehab state->current_frequency = p->frequency; 4619a0bf528SMauro Carvalho Chehab 462467845a1SMauro Carvalho Chehab lgdt330x_sw_reset(state); 4639a0bf528SMauro Carvalho Chehab return 0; 4649a0bf528SMauro Carvalho Chehab } 4659a0bf528SMauro Carvalho Chehab 4667e3e68bcSMauro Carvalho Chehab static int lgdt330x_get_frontend(struct dvb_frontend *fe, 4677e3e68bcSMauro Carvalho Chehab struct dtv_frontend_properties *p) 4689a0bf528SMauro Carvalho Chehab { 4699a0bf528SMauro Carvalho Chehab struct lgdt330x_state *state = fe->demodulator_priv; 4707e3e68bcSMauro Carvalho Chehab 4719a0bf528SMauro Carvalho Chehab p->frequency = state->current_frequency; 4729a0bf528SMauro Carvalho Chehab return 0; 4739a0bf528SMauro Carvalho Chehab } 4749a0bf528SMauro Carvalho Chehab 4750df289a2SMauro Carvalho Chehab static int lgdt3302_read_status(struct dvb_frontend *fe, 4760df289a2SMauro Carvalho Chehab enum fe_status *status) 4779a0bf528SMauro Carvalho Chehab { 4789a0bf528SMauro Carvalho Chehab struct lgdt330x_state *state = fe->demodulator_priv; 4799a0bf528SMauro Carvalho Chehab u8 buf[3]; 4809a0bf528SMauro Carvalho Chehab 4819a0bf528SMauro Carvalho Chehab *status = 0; /* Reset status result */ 4829a0bf528SMauro Carvalho Chehab 4839a0bf528SMauro Carvalho Chehab /* AGC status register */ 4849a0bf528SMauro Carvalho Chehab i2c_read_demod_bytes(state, AGC_STATUS, buf, 1); 48523ba635dSMauro Carvalho Chehab dprintk(state, "AGC_STATUS = 0x%02x\n", buf[0]); 4869a0bf528SMauro Carvalho Chehab if ((buf[0] & 0x0c) == 0x8) { 487467845a1SMauro Carvalho Chehab /* 488467845a1SMauro Carvalho Chehab * Test signal does not exist flag 489467845a1SMauro Carvalho Chehab * as well as the AGC lock flag. 490467845a1SMauro Carvalho Chehab */ 4919a0bf528SMauro Carvalho Chehab *status |= FE_HAS_SIGNAL; 4929a0bf528SMauro Carvalho Chehab } 4939a0bf528SMauro Carvalho Chehab 4949a0bf528SMauro Carvalho Chehab /* 4959a0bf528SMauro Carvalho Chehab * You must set the Mask bits to 1 in the IRQ_MASK in order 4969a0bf528SMauro Carvalho Chehab * to see that status bit in the IRQ_STATUS register. 4979a0bf528SMauro Carvalho Chehab * This is done in SwReset(); 4989a0bf528SMauro Carvalho Chehab */ 499467845a1SMauro Carvalho Chehab 5009a0bf528SMauro Carvalho Chehab /* signal status */ 5019a0bf528SMauro Carvalho Chehab i2c_read_demod_bytes(state, TOP_CONTROL, buf, sizeof(buf)); 50223ba635dSMauro Carvalho Chehab dprintk(state, 50323ba635dSMauro Carvalho Chehab "TOP_CONTROL = 0x%02x, IRO_MASK = 0x%02x, IRQ_STATUS = 0x%02x\n", 5046752c797SMauro Carvalho Chehab buf[0], buf[1], buf[2]); 5059a0bf528SMauro Carvalho Chehab 5069a0bf528SMauro Carvalho Chehab /* sync status */ 507467845a1SMauro Carvalho Chehab if ((buf[2] & 0x03) == 0x01) 5089a0bf528SMauro Carvalho Chehab *status |= FE_HAS_SYNC; 5099a0bf528SMauro Carvalho Chehab 5109a0bf528SMauro Carvalho Chehab /* FEC error status */ 511db9c1007SMauro Carvalho Chehab if ((buf[2] & 0x0c) == 0x08) 512db9c1007SMauro Carvalho Chehab *status |= FE_HAS_LOCK | FE_HAS_VITERBI; 5139a0bf528SMauro Carvalho Chehab 5149a0bf528SMauro Carvalho Chehab /* Carrier Recovery Lock Status Register */ 5159a0bf528SMauro Carvalho Chehab i2c_read_demod_bytes(state, CARRIER_LOCK, buf, 1); 51623ba635dSMauro Carvalho Chehab dprintk(state, "CARRIER_LOCK = 0x%02x\n", buf[0]); 5179a0bf528SMauro Carvalho Chehab switch (state->current_modulation) { 5189a0bf528SMauro Carvalho Chehab case QAM_256: 5199a0bf528SMauro Carvalho Chehab case QAM_64: 5209a0bf528SMauro Carvalho Chehab /* Need to understand why there are 3 lock levels here */ 5219a0bf528SMauro Carvalho Chehab if ((buf[0] & 0x07) == 0x07) 5229a0bf528SMauro Carvalho Chehab *status |= FE_HAS_CARRIER; 5239a0bf528SMauro Carvalho Chehab break; 5249a0bf528SMauro Carvalho Chehab case VSB_8: 5259a0bf528SMauro Carvalho Chehab if ((buf[0] & 0x80) == 0x80) 5269a0bf528SMauro Carvalho Chehab *status |= FE_HAS_CARRIER; 5279a0bf528SMauro Carvalho Chehab break; 5289a0bf528SMauro Carvalho Chehab default: 52923ba635dSMauro Carvalho Chehab dev_warn(&state->client->dev, 53023ba635dSMauro Carvalho Chehab "%s: Modulation set to unsupported value\n", 531467845a1SMauro Carvalho Chehab __func__); 5329a0bf528SMauro Carvalho Chehab } 5339a0bf528SMauro Carvalho Chehab 5349a0bf528SMauro Carvalho Chehab return 0; 5359a0bf528SMauro Carvalho Chehab } 5369a0bf528SMauro Carvalho Chehab 5370df289a2SMauro Carvalho Chehab static int lgdt3303_read_status(struct dvb_frontend *fe, 5380df289a2SMauro Carvalho Chehab enum fe_status *status) 5399a0bf528SMauro Carvalho Chehab { 5409a0bf528SMauro Carvalho Chehab struct lgdt330x_state *state = fe->demodulator_priv; 5419a0bf528SMauro Carvalho Chehab int err; 5429a0bf528SMauro Carvalho Chehab u8 buf[3]; 5439a0bf528SMauro Carvalho Chehab 5449a0bf528SMauro Carvalho Chehab *status = 0; /* Reset status result */ 5459a0bf528SMauro Carvalho Chehab 5469a0bf528SMauro Carvalho Chehab /* lgdt3303 AGC status register */ 5479a0bf528SMauro Carvalho Chehab err = i2c_read_demod_bytes(state, 0x58, buf, 1); 5489a0bf528SMauro Carvalho Chehab if (err < 0) 5499a0bf528SMauro Carvalho Chehab return err; 5509a0bf528SMauro Carvalho Chehab 55123ba635dSMauro Carvalho Chehab dprintk(state, "AGC_STATUS = 0x%02x\n", buf[0]); 5529a0bf528SMauro Carvalho Chehab if ((buf[0] & 0x21) == 0x01) { 553467845a1SMauro Carvalho Chehab /* 554467845a1SMauro Carvalho Chehab * Test input signal does not exist flag 555467845a1SMauro Carvalho Chehab * as well as the AGC lock flag. 556467845a1SMauro Carvalho Chehab */ 5579a0bf528SMauro Carvalho Chehab *status |= FE_HAS_SIGNAL; 5589a0bf528SMauro Carvalho Chehab } 5599a0bf528SMauro Carvalho Chehab 5609a0bf528SMauro Carvalho Chehab /* Carrier Recovery Lock Status Register */ 5619a0bf528SMauro Carvalho Chehab i2c_read_demod_bytes(state, CARRIER_LOCK, buf, 1); 56223ba635dSMauro Carvalho Chehab dprintk(state, "CARRIER_LOCK = 0x%02x\n", buf[0]); 5639a0bf528SMauro Carvalho Chehab switch (state->current_modulation) { 5649a0bf528SMauro Carvalho Chehab case QAM_256: 5659a0bf528SMauro Carvalho Chehab case QAM_64: 5669a0bf528SMauro Carvalho Chehab /* Need to understand why there are 3 lock levels here */ 5679a0bf528SMauro Carvalho Chehab if ((buf[0] & 0x07) == 0x07) 5689a0bf528SMauro Carvalho Chehab *status |= FE_HAS_CARRIER; 5699a0bf528SMauro Carvalho Chehab else 5709a0bf528SMauro Carvalho Chehab break; 5719a0bf528SMauro Carvalho Chehab i2c_read_demod_bytes(state, 0x8a, buf, 1); 572db9c1007SMauro Carvalho Chehab dprintk(state, "QAM LOCK = 0x%02x\n", buf[0]); 573db9c1007SMauro Carvalho Chehab 5749a0bf528SMauro Carvalho Chehab if ((buf[0] & 0x04) == 0x04) 5759a0bf528SMauro Carvalho Chehab *status |= FE_HAS_SYNC; 5769a0bf528SMauro Carvalho Chehab if ((buf[0] & 0x01) == 0x01) 5779a0bf528SMauro Carvalho Chehab *status |= FE_HAS_LOCK; 5789a0bf528SMauro Carvalho Chehab if ((buf[0] & 0x08) == 0x08) 5799a0bf528SMauro Carvalho Chehab *status |= FE_HAS_VITERBI; 5809a0bf528SMauro Carvalho Chehab break; 5819a0bf528SMauro Carvalho Chehab case VSB_8: 5829a0bf528SMauro Carvalho Chehab if ((buf[0] & 0x80) == 0x80) 5839a0bf528SMauro Carvalho Chehab *status |= FE_HAS_CARRIER; 5849a0bf528SMauro Carvalho Chehab else 5859a0bf528SMauro Carvalho Chehab break; 5869a0bf528SMauro Carvalho Chehab i2c_read_demod_bytes(state, 0x38, buf, 1); 587db9c1007SMauro Carvalho Chehab dprintk(state, "8-VSB LOCK = 0x%02x\n", buf[0]); 588db9c1007SMauro Carvalho Chehab 5899a0bf528SMauro Carvalho Chehab if ((buf[0] & 0x02) == 0x00) 5909a0bf528SMauro Carvalho Chehab *status |= FE_HAS_SYNC; 591db9c1007SMauro Carvalho Chehab if ((buf[0] & 0xfd) == 0x01) 592db9c1007SMauro Carvalho Chehab *status |= FE_HAS_VITERBI | FE_HAS_LOCK; 5939a0bf528SMauro Carvalho Chehab break; 5949a0bf528SMauro Carvalho Chehab default: 59523ba635dSMauro Carvalho Chehab dev_warn(&state->client->dev, 59623ba635dSMauro Carvalho Chehab "%s: Modulation set to unsupported value\n", 597467845a1SMauro Carvalho Chehab __func__); 5989a0bf528SMauro Carvalho Chehab } 5999a0bf528SMauro Carvalho Chehab return 0; 6009a0bf528SMauro Carvalho Chehab } 6019a0bf528SMauro Carvalho Chehab 602467845a1SMauro Carvalho Chehab /* 603467845a1SMauro Carvalho Chehab * Calculate SNR estimation (scaled by 2^24) 604467845a1SMauro Carvalho Chehab * 605467845a1SMauro Carvalho Chehab * 8-VSB SNR equations from LGDT3302 and LGDT3303 datasheets, QAM 606467845a1SMauro Carvalho Chehab * equations from LGDT3303 datasheet. VSB is the same between the '02 607467845a1SMauro Carvalho Chehab * and '03, so maybe QAM is too? Perhaps someone with a newer datasheet 608467845a1SMauro Carvalho Chehab * that has QAM information could verify? 609467845a1SMauro Carvalho Chehab * 610467845a1SMauro Carvalho Chehab * For 8-VSB: (two ways, take your pick) 611467845a1SMauro Carvalho Chehab * LGDT3302: 612467845a1SMauro Carvalho Chehab * SNR_EQ = 10 * log10(25 * 24^2 / EQ_MSE) 613467845a1SMauro Carvalho Chehab * LGDT3303: 614467845a1SMauro Carvalho Chehab * SNR_EQ = 10 * log10(25 * 32^2 / EQ_MSE) 615467845a1SMauro Carvalho Chehab * LGDT3302 & LGDT3303: 616467845a1SMauro Carvalho Chehab * SNR_PT = 10 * log10(25 * 32^2 / PT_MSE) (we use this one) 617467845a1SMauro Carvalho Chehab * For 64-QAM: 618467845a1SMauro Carvalho Chehab * SNR = 10 * log10( 688128 / MSEQAM) 619467845a1SMauro Carvalho Chehab * For 256-QAM: 620467845a1SMauro Carvalho Chehab * SNR = 10 * log10( 696320 / MSEQAM) 621467845a1SMauro Carvalho Chehab * 622467845a1SMauro Carvalho Chehab * We re-write the snr equation as: 623467845a1SMauro Carvalho Chehab * SNR * 2^24 = 10*(c - intlog10(MSE)) 624467845a1SMauro Carvalho Chehab * Where for 256-QAM, c = log10(696320) * 2^24, and so on. 625467845a1SMauro Carvalho Chehab */ 6269a0bf528SMauro Carvalho Chehab static u32 calculate_snr(u32 mse, u32 c) 6279a0bf528SMauro Carvalho Chehab { 6289a0bf528SMauro Carvalho Chehab if (mse == 0) /* No signal */ 6299a0bf528SMauro Carvalho Chehab return 0; 6309a0bf528SMauro Carvalho Chehab 6319a0bf528SMauro Carvalho Chehab mse = intlog10(mse); 6329a0bf528SMauro Carvalho Chehab if (mse > c) { 633467845a1SMauro Carvalho Chehab /* 634467845a1SMauro Carvalho Chehab * Negative SNR, which is possible, but realisticly the 635467845a1SMauro Carvalho Chehab * demod will lose lock before the signal gets this bad. 636467845a1SMauro Carvalho Chehab * The API only allows for unsigned values, so just return 0 637467845a1SMauro Carvalho Chehab */ 6389a0bf528SMauro Carvalho Chehab return 0; 6399a0bf528SMauro Carvalho Chehab } 6409a0bf528SMauro Carvalho Chehab return 10 * (c - mse); 6419a0bf528SMauro Carvalho Chehab } 6429a0bf528SMauro Carvalho Chehab 6439a0bf528SMauro Carvalho Chehab static int lgdt3302_read_snr(struct dvb_frontend *fe, u16 *snr) 6449a0bf528SMauro Carvalho Chehab { 645467845a1SMauro Carvalho Chehab struct lgdt330x_state *state = fe->demodulator_priv; 6469a0bf528SMauro Carvalho Chehab u8 buf[5]; /* read data buffer */ 6479a0bf528SMauro Carvalho Chehab u32 noise; /* noise value */ 6489a0bf528SMauro Carvalho Chehab u32 c; /* per-modulation SNR calculation constant */ 6499a0bf528SMauro Carvalho Chehab 6509a0bf528SMauro Carvalho Chehab switch (state->current_modulation) { 6519a0bf528SMauro Carvalho Chehab case VSB_8: 6529a0bf528SMauro Carvalho Chehab i2c_read_demod_bytes(state, LGDT3302_EQPH_ERR0, buf, 5); 6539a0bf528SMauro Carvalho Chehab #ifdef USE_EQMSE 6549a0bf528SMauro Carvalho Chehab /* Use Equalizer Mean-Square Error Register */ 6559a0bf528SMauro Carvalho Chehab /* SNR for ranges from -15.61 to +41.58 */ 6569a0bf528SMauro Carvalho Chehab noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2]; 6579a0bf528SMauro Carvalho Chehab c = 69765745; /* log10(25*24^2)*2^24 */ 6589a0bf528SMauro Carvalho Chehab #else 6599a0bf528SMauro Carvalho Chehab /* Use Phase Tracker Mean-Square Error Register */ 6609a0bf528SMauro Carvalho Chehab /* SNR for ranges from -13.11 to +44.08 */ 6619a0bf528SMauro Carvalho Chehab noise = ((buf[0] & 7 << 3) << 13) | (buf[3] << 8) | buf[4]; 6629a0bf528SMauro Carvalho Chehab c = 73957994; /* log10(25*32^2)*2^24 */ 6639a0bf528SMauro Carvalho Chehab #endif 6649a0bf528SMauro Carvalho Chehab break; 6659a0bf528SMauro Carvalho Chehab case QAM_64: 6669a0bf528SMauro Carvalho Chehab case QAM_256: 6679a0bf528SMauro Carvalho Chehab i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2); 6689a0bf528SMauro Carvalho Chehab noise = ((buf[0] & 3) << 8) | buf[1]; 6699a0bf528SMauro Carvalho Chehab c = state->current_modulation == QAM_64 ? 97939837 : 98026066; 6709a0bf528SMauro Carvalho Chehab /* log10(688128)*2^24 and log10(696320)*2^24 */ 6719a0bf528SMauro Carvalho Chehab break; 6729a0bf528SMauro Carvalho Chehab default: 67323ba635dSMauro Carvalho Chehab dev_err(&state->client->dev, 67423ba635dSMauro Carvalho Chehab "%s: Modulation set to unsupported value\n", 6759a0bf528SMauro Carvalho Chehab __func__); 6769a0bf528SMauro Carvalho Chehab return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */ 6779a0bf528SMauro Carvalho Chehab } 6789a0bf528SMauro Carvalho Chehab 6799a0bf528SMauro Carvalho Chehab state->snr = calculate_snr(noise, c); 6809a0bf528SMauro Carvalho Chehab *snr = (state->snr) >> 16; /* Convert from 8.24 fixed-point to 8.8 */ 6819a0bf528SMauro Carvalho Chehab 68223ba635dSMauro Carvalho Chehab dprintk(state, "noise = 0x%08x, snr = %d.%02d dB\n", noise, 6839a0bf528SMauro Carvalho Chehab state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16); 6849a0bf528SMauro Carvalho Chehab 6859a0bf528SMauro Carvalho Chehab return 0; 6869a0bf528SMauro Carvalho Chehab } 6879a0bf528SMauro Carvalho Chehab 6889a0bf528SMauro Carvalho Chehab static int lgdt3303_read_snr(struct dvb_frontend *fe, u16 *snr) 6899a0bf528SMauro Carvalho Chehab { 690467845a1SMauro Carvalho Chehab struct lgdt330x_state *state = fe->demodulator_priv; 6919a0bf528SMauro Carvalho Chehab u8 buf[5]; /* read data buffer */ 6929a0bf528SMauro Carvalho Chehab u32 noise; /* noise value */ 6939a0bf528SMauro Carvalho Chehab u32 c; /* per-modulation SNR calculation constant */ 6949a0bf528SMauro Carvalho Chehab 6959a0bf528SMauro Carvalho Chehab switch (state->current_modulation) { 6969a0bf528SMauro Carvalho Chehab case VSB_8: 6979a0bf528SMauro Carvalho Chehab i2c_read_demod_bytes(state, LGDT3303_EQPH_ERR0, buf, 5); 6989a0bf528SMauro Carvalho Chehab #ifdef USE_EQMSE 6999a0bf528SMauro Carvalho Chehab /* Use Equalizer Mean-Square Error Register */ 7009a0bf528SMauro Carvalho Chehab /* SNR for ranges from -16.12 to +44.08 */ 7019a0bf528SMauro Carvalho Chehab noise = ((buf[0] & 0x78) << 13) | (buf[1] << 8) | buf[2]; 7029a0bf528SMauro Carvalho Chehab c = 73957994; /* log10(25*32^2)*2^24 */ 7039a0bf528SMauro Carvalho Chehab #else 7049a0bf528SMauro Carvalho Chehab /* Use Phase Tracker Mean-Square Error Register */ 7059a0bf528SMauro Carvalho Chehab /* SNR for ranges from -13.11 to +44.08 */ 7069a0bf528SMauro Carvalho Chehab noise = ((buf[0] & 7) << 16) | (buf[3] << 8) | buf[4]; 7079a0bf528SMauro Carvalho Chehab c = 73957994; /* log10(25*32^2)*2^24 */ 7089a0bf528SMauro Carvalho Chehab #endif 7099a0bf528SMauro Carvalho Chehab break; 7109a0bf528SMauro Carvalho Chehab case QAM_64: 7119a0bf528SMauro Carvalho Chehab case QAM_256: 7129a0bf528SMauro Carvalho Chehab i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2); 7139a0bf528SMauro Carvalho Chehab noise = (buf[0] << 8) | buf[1]; 7149a0bf528SMauro Carvalho Chehab c = state->current_modulation == QAM_64 ? 97939837 : 98026066; 7159a0bf528SMauro Carvalho Chehab /* log10(688128)*2^24 and log10(696320)*2^24 */ 7169a0bf528SMauro Carvalho Chehab break; 7179a0bf528SMauro Carvalho Chehab default: 71823ba635dSMauro Carvalho Chehab dev_err(&state->client->dev, 71923ba635dSMauro Carvalho Chehab "%s: Modulation set to unsupported value\n", 7209a0bf528SMauro Carvalho Chehab __func__); 7219a0bf528SMauro Carvalho Chehab return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */ 7229a0bf528SMauro Carvalho Chehab } 7239a0bf528SMauro Carvalho Chehab 7249a0bf528SMauro Carvalho Chehab state->snr = calculate_snr(noise, c); 7259a0bf528SMauro Carvalho Chehab *snr = (state->snr) >> 16; /* Convert from 8.24 fixed-point to 8.8 */ 7269a0bf528SMauro Carvalho Chehab 72723ba635dSMauro Carvalho Chehab dprintk(state, "noise = 0x%08x, snr = %d.%02d dB\n", noise, 7289a0bf528SMauro Carvalho Chehab state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16); 7299a0bf528SMauro Carvalho Chehab 7309a0bf528SMauro Carvalho Chehab return 0; 7319a0bf528SMauro Carvalho Chehab } 7329a0bf528SMauro Carvalho Chehab 7339a0bf528SMauro Carvalho Chehab static int lgdt330x_read_signal_strength(struct dvb_frontend *fe, u16 *strength) 7349a0bf528SMauro Carvalho Chehab { 7359a0bf528SMauro Carvalho Chehab /* Calculate Strength from SNR up to 35dB */ 736467845a1SMauro Carvalho Chehab /* 737467845a1SMauro Carvalho Chehab * Even though the SNR can go higher than 35dB, there is some comfort 738467845a1SMauro Carvalho Chehab * factor in having a range of strong signals that can show at 100% 739467845a1SMauro Carvalho Chehab */ 740467845a1SMauro Carvalho Chehab struct lgdt330x_state *state = fe->demodulator_priv; 7419a0bf528SMauro Carvalho Chehab u16 snr; 7429a0bf528SMauro Carvalho Chehab int ret; 7439a0bf528SMauro Carvalho Chehab 7449a0bf528SMauro Carvalho Chehab ret = fe->ops.read_snr(fe, &snr); 7459a0bf528SMauro Carvalho Chehab if (ret != 0) 7469a0bf528SMauro Carvalho Chehab return ret; 7479a0bf528SMauro Carvalho Chehab /* Rather than use the 8.8 value snr, use state->snr which is 8.24 */ 7489a0bf528SMauro Carvalho Chehab /* scale the range 0 - 35*2^24 into 0 - 65535 */ 7499a0bf528SMauro Carvalho Chehab if (state->snr >= 8960 * 0x10000) 7509a0bf528SMauro Carvalho Chehab *strength = 0xffff; 7519a0bf528SMauro Carvalho Chehab else 7529a0bf528SMauro Carvalho Chehab *strength = state->snr / 8960; 7539a0bf528SMauro Carvalho Chehab 7549a0bf528SMauro Carvalho Chehab return 0; 7559a0bf528SMauro Carvalho Chehab } 7569a0bf528SMauro Carvalho Chehab 757467845a1SMauro Carvalho Chehab static int 758467845a1SMauro Carvalho Chehab lgdt330x_get_tune_settings(struct dvb_frontend *fe, 759467845a1SMauro Carvalho Chehab struct dvb_frontend_tune_settings *fe_tune_settings) 7609a0bf528SMauro Carvalho Chehab { 7619a0bf528SMauro Carvalho Chehab /* I have no idea about this - it may not be needed */ 7629a0bf528SMauro Carvalho Chehab fe_tune_settings->min_delay_ms = 500; 7639a0bf528SMauro Carvalho Chehab fe_tune_settings->step_size = 0; 7649a0bf528SMauro Carvalho Chehab fe_tune_settings->max_drift = 0; 7659a0bf528SMauro Carvalho Chehab return 0; 7669a0bf528SMauro Carvalho Chehab } 7679a0bf528SMauro Carvalho Chehab 7689a0bf528SMauro Carvalho Chehab static void lgdt330x_release(struct dvb_frontend *fe) 7699a0bf528SMauro Carvalho Chehab { 770467845a1SMauro Carvalho Chehab struct lgdt330x_state *state = fe->demodulator_priv; 77123ba635dSMauro Carvalho Chehab struct i2c_client *client = state->client; 772467845a1SMauro Carvalho Chehab 77323ba635dSMauro Carvalho Chehab dev_dbg(&client->dev, "\n"); 77423ba635dSMauro Carvalho Chehab 77523ba635dSMauro Carvalho Chehab i2c_unregister_device(client); 77623ba635dSMauro Carvalho Chehab } 77723ba635dSMauro Carvalho Chehab 77823ba635dSMauro Carvalho Chehab static struct dvb_frontend *lgdt330x_get_dvb_frontend(struct i2c_client *client) 77923ba635dSMauro Carvalho Chehab { 78023ba635dSMauro Carvalho Chehab struct lgdt330x_state *state = i2c_get_clientdata(client); 78123ba635dSMauro Carvalho Chehab 78223ba635dSMauro Carvalho Chehab dev_dbg(&client->dev, "\n"); 78323ba635dSMauro Carvalho Chehab 78423ba635dSMauro Carvalho Chehab return &state->frontend; 7859a0bf528SMauro Carvalho Chehab } 7869a0bf528SMauro Carvalho Chehab 787bd336e63SMax Kellermann static const struct dvb_frontend_ops lgdt3302_ops; 788bd336e63SMax Kellermann static const struct dvb_frontend_ops lgdt3303_ops; 7899a0bf528SMauro Carvalho Chehab 79023ba635dSMauro Carvalho Chehab static int lgdt330x_probe(struct i2c_client *client, 79123ba635dSMauro Carvalho Chehab const struct i2c_device_id *id) 7929a0bf528SMauro Carvalho Chehab { 7939a0bf528SMauro Carvalho Chehab struct lgdt330x_state *state = NULL; 7949a0bf528SMauro Carvalho Chehab u8 buf[1]; 7959a0bf528SMauro Carvalho Chehab 7969a0bf528SMauro Carvalho Chehab /* Allocate memory for the internal state */ 797467845a1SMauro Carvalho Chehab state = kzalloc(sizeof(*state), GFP_KERNEL); 798467845a1SMauro Carvalho Chehab if (!state) 7999a0bf528SMauro Carvalho Chehab goto error; 8009a0bf528SMauro Carvalho Chehab 8019a0bf528SMauro Carvalho Chehab /* Setup the state */ 80223ba635dSMauro Carvalho Chehab memcpy(&state->config, client->dev.platform_data, 80323ba635dSMauro Carvalho Chehab sizeof(state->config)); 80423ba635dSMauro Carvalho Chehab i2c_set_clientdata(client, state); 80523ba635dSMauro Carvalho Chehab state->client = client; 8069a0bf528SMauro Carvalho Chehab 8079a0bf528SMauro Carvalho Chehab /* Create dvb_frontend */ 80823ba635dSMauro Carvalho Chehab switch (state->config.demod_chip) { 8099a0bf528SMauro Carvalho Chehab case LGDT3302: 810467845a1SMauro Carvalho Chehab memcpy(&state->frontend.ops, &lgdt3302_ops, 811467845a1SMauro Carvalho Chehab sizeof(struct dvb_frontend_ops)); 8129a0bf528SMauro Carvalho Chehab break; 8139a0bf528SMauro Carvalho Chehab case LGDT3303: 814467845a1SMauro Carvalho Chehab memcpy(&state->frontend.ops, &lgdt3303_ops, 815467845a1SMauro Carvalho Chehab sizeof(struct dvb_frontend_ops)); 8169a0bf528SMauro Carvalho Chehab break; 8179a0bf528SMauro Carvalho Chehab default: 8189a0bf528SMauro Carvalho Chehab goto error; 8199a0bf528SMauro Carvalho Chehab } 8209a0bf528SMauro Carvalho Chehab state->frontend.demodulator_priv = state; 8219a0bf528SMauro Carvalho Chehab 82223ba635dSMauro Carvalho Chehab /* Setup get frontend callback */ 82323ba635dSMauro Carvalho Chehab state->config.get_dvb_frontend = lgdt330x_get_dvb_frontend; 82423ba635dSMauro Carvalho Chehab 8259a0bf528SMauro Carvalho Chehab /* Verify communication with demod chip */ 8269a0bf528SMauro Carvalho Chehab if (i2c_read_demod_bytes(state, 2, buf, 1)) 8279a0bf528SMauro Carvalho Chehab goto error; 8289a0bf528SMauro Carvalho Chehab 8299a0bf528SMauro Carvalho Chehab state->current_frequency = -1; 8309a0bf528SMauro Carvalho Chehab state->current_modulation = -1; 8319a0bf528SMauro Carvalho Chehab 83223ba635dSMauro Carvalho Chehab dev_info(&state->client->dev, 83323ba635dSMauro Carvalho Chehab "Demod loaded for LGDT330%s chip\n", 83423ba635dSMauro Carvalho Chehab state->config.demod_chip == LGDT3302 ? "2" : "3"); 835ff093612SMauro Carvalho Chehab 83623ba635dSMauro Carvalho Chehab return 0; 8379a0bf528SMauro Carvalho Chehab 8389a0bf528SMauro Carvalho Chehab error: 8399a0bf528SMauro Carvalho Chehab kfree(state); 84023ba635dSMauro Carvalho Chehab dprintk(state, "ERROR\n"); 84123ba635dSMauro Carvalho Chehab return -ENODEV; 84223ba635dSMauro Carvalho Chehab } 84323ba635dSMauro Carvalho Chehab struct dvb_frontend *lgdt330x_attach(const struct lgdt330x_config *_config, 84423ba635dSMauro Carvalho Chehab u8 demod_address, 84523ba635dSMauro Carvalho Chehab struct i2c_adapter *i2c) 84623ba635dSMauro Carvalho Chehab { 84723ba635dSMauro Carvalho Chehab struct i2c_client *client; 84823ba635dSMauro Carvalho Chehab struct i2c_board_info board_info = {}; 84923ba635dSMauro Carvalho Chehab struct lgdt330x_config config = *_config; 85023ba635dSMauro Carvalho Chehab 85123ba635dSMauro Carvalho Chehab strlcpy(board_info.type, "lgdt330x", sizeof(board_info.type)); 85223ba635dSMauro Carvalho Chehab board_info.addr = demod_address; 85323ba635dSMauro Carvalho Chehab board_info.platform_data = &config; 85423ba635dSMauro Carvalho Chehab client = i2c_new_device(i2c, &board_info); 85523ba635dSMauro Carvalho Chehab if (!client || !client->dev.driver) 8569a0bf528SMauro Carvalho Chehab return NULL; 85723ba635dSMauro Carvalho Chehab 85823ba635dSMauro Carvalho Chehab return lgdt330x_get_dvb_frontend(client); 8599a0bf528SMauro Carvalho Chehab } 860467845a1SMauro Carvalho Chehab EXPORT_SYMBOL(lgdt330x_attach); 8619a0bf528SMauro Carvalho Chehab 862bd336e63SMax Kellermann static const struct dvb_frontend_ops lgdt3302_ops = { 8639a0bf528SMauro Carvalho Chehab .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, 8649a0bf528SMauro Carvalho Chehab .info = { 8659a0bf528SMauro Carvalho Chehab .name = "LG Electronics LGDT3302 VSB/QAM Frontend", 8669a0bf528SMauro Carvalho Chehab .frequency_min = 54000000, 8679a0bf528SMauro Carvalho Chehab .frequency_max = 858000000, 8689a0bf528SMauro Carvalho Chehab .frequency_stepsize = 62500, 8699a0bf528SMauro Carvalho Chehab .symbol_rate_min = 5056941, /* QAM 64 */ 8709a0bf528SMauro Carvalho Chehab .symbol_rate_max = 10762000, /* VSB 8 */ 8719a0bf528SMauro Carvalho Chehab .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB 8729a0bf528SMauro Carvalho Chehab }, 8739a0bf528SMauro Carvalho Chehab .init = lgdt330x_init, 8749a0bf528SMauro Carvalho Chehab .set_frontend = lgdt330x_set_parameters, 8759a0bf528SMauro Carvalho Chehab .get_frontend = lgdt330x_get_frontend, 8769a0bf528SMauro Carvalho Chehab .get_tune_settings = lgdt330x_get_tune_settings, 8779a0bf528SMauro Carvalho Chehab .read_status = lgdt3302_read_status, 8789a0bf528SMauro Carvalho Chehab .read_ber = lgdt330x_read_ber, 8799a0bf528SMauro Carvalho Chehab .read_signal_strength = lgdt330x_read_signal_strength, 8809a0bf528SMauro Carvalho Chehab .read_snr = lgdt3302_read_snr, 8819a0bf528SMauro Carvalho Chehab .read_ucblocks = lgdt330x_read_ucblocks, 8829a0bf528SMauro Carvalho Chehab .release = lgdt330x_release, 8839a0bf528SMauro Carvalho Chehab }; 8849a0bf528SMauro Carvalho Chehab 885bd336e63SMax Kellermann static const struct dvb_frontend_ops lgdt3303_ops = { 8869a0bf528SMauro Carvalho Chehab .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, 8879a0bf528SMauro Carvalho Chehab .info = { 8889a0bf528SMauro Carvalho Chehab .name = "LG Electronics LGDT3303 VSB/QAM Frontend", 8899a0bf528SMauro Carvalho Chehab .frequency_min = 54000000, 8909a0bf528SMauro Carvalho Chehab .frequency_max = 858000000, 8919a0bf528SMauro Carvalho Chehab .frequency_stepsize = 62500, 8929a0bf528SMauro Carvalho Chehab .symbol_rate_min = 5056941, /* QAM 64 */ 8939a0bf528SMauro Carvalho Chehab .symbol_rate_max = 10762000, /* VSB 8 */ 8949a0bf528SMauro Carvalho Chehab .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB 8959a0bf528SMauro Carvalho Chehab }, 8969a0bf528SMauro Carvalho Chehab .init = lgdt330x_init, 8979a0bf528SMauro Carvalho Chehab .set_frontend = lgdt330x_set_parameters, 8989a0bf528SMauro Carvalho Chehab .get_frontend = lgdt330x_get_frontend, 8999a0bf528SMauro Carvalho Chehab .get_tune_settings = lgdt330x_get_tune_settings, 9009a0bf528SMauro Carvalho Chehab .read_status = lgdt3303_read_status, 9019a0bf528SMauro Carvalho Chehab .read_ber = lgdt330x_read_ber, 9029a0bf528SMauro Carvalho Chehab .read_signal_strength = lgdt330x_read_signal_strength, 9039a0bf528SMauro Carvalho Chehab .read_snr = lgdt3303_read_snr, 9049a0bf528SMauro Carvalho Chehab .read_ucblocks = lgdt330x_read_ucblocks, 9059a0bf528SMauro Carvalho Chehab .release = lgdt330x_release, 9069a0bf528SMauro Carvalho Chehab }; 9079a0bf528SMauro Carvalho Chehab 90823ba635dSMauro Carvalho Chehab static int lgdt330x_remove(struct i2c_client *client) 90923ba635dSMauro Carvalho Chehab { 91023ba635dSMauro Carvalho Chehab struct lgdt330x_state *state = i2c_get_clientdata(client); 91123ba635dSMauro Carvalho Chehab 91223ba635dSMauro Carvalho Chehab dev_dbg(&client->dev, "\n"); 91323ba635dSMauro Carvalho Chehab 91423ba635dSMauro Carvalho Chehab kfree(state); 91523ba635dSMauro Carvalho Chehab 91623ba635dSMauro Carvalho Chehab return 0; 91723ba635dSMauro Carvalho Chehab } 91823ba635dSMauro Carvalho Chehab 91923ba635dSMauro Carvalho Chehab static const struct i2c_device_id lgdt330x_id_table[] = { 92023ba635dSMauro Carvalho Chehab {"lgdt330x", 0}, 92123ba635dSMauro Carvalho Chehab {} 92223ba635dSMauro Carvalho Chehab }; 92323ba635dSMauro Carvalho Chehab MODULE_DEVICE_TABLE(i2c, lgdt330x_id_table); 92423ba635dSMauro Carvalho Chehab 92523ba635dSMauro Carvalho Chehab static struct i2c_driver lgdt330x_driver = { 92623ba635dSMauro Carvalho Chehab .driver = { 92723ba635dSMauro Carvalho Chehab .name = "lgdt330x", 92823ba635dSMauro Carvalho Chehab .suppress_bind_attrs = true, 92923ba635dSMauro Carvalho Chehab }, 93023ba635dSMauro Carvalho Chehab .probe = lgdt330x_probe, 93123ba635dSMauro Carvalho Chehab .remove = lgdt330x_remove, 93223ba635dSMauro Carvalho Chehab .id_table = lgdt330x_id_table, 93323ba635dSMauro Carvalho Chehab }; 93423ba635dSMauro Carvalho Chehab 93523ba635dSMauro Carvalho Chehab module_i2c_driver(lgdt330x_driver); 93623ba635dSMauro Carvalho Chehab 93723ba635dSMauro Carvalho Chehab 9389a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("LGDT330X (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver"); 9399a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Wilson Michaels"); 9409a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL"); 941