Path: blob/master/drivers/media/dvb/pt1/va1j5jf8007t.c
15112 views
/*1* ISDB-T driver for VA1J5JF8007/VA1J5JF80112*3* Copyright (C) 2009 HIRANO Takahito <[email protected]>4*5* based on pt1dvr - http://pt1dvr.sourceforge.jp/6* by Tomoaki Ishikawa <[email protected]>7*8* This program is free software; you can redistribute it and/or modify9* it under the terms of the GNU General Public License as published by10* the Free Software Foundation; either version 2 of the License, or11* (at your option) any later version.12*13* This program is distributed in the hope that it will be useful,14* but WITHOUT ANY WARRANTY; without even the implied warranty of15* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the16* GNU General Public License for more details.17*18* You should have received a copy of the GNU General Public License19* along with this program; if not, write to the Free Software20* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.21*/2223#include <linux/kernel.h>24#include <linux/module.h>25#include <linux/slab.h>26#include <linux/i2c.h>27#include "dvb_frontend.h"28#include "dvb_math.h"29#include "va1j5jf8007t.h"3031enum va1j5jf8007t_tune_state {32VA1J5JF8007T_IDLE,33VA1J5JF8007T_SET_FREQUENCY,34VA1J5JF8007T_CHECK_FREQUENCY,35VA1J5JF8007T_SET_MODULATION,36VA1J5JF8007T_CHECK_MODULATION,37VA1J5JF8007T_TRACK,38VA1J5JF8007T_ABORT,39};4041struct va1j5jf8007t_state {42const struct va1j5jf8007t_config *config;43struct i2c_adapter *adap;44struct dvb_frontend fe;45enum va1j5jf8007t_tune_state tune_state;46};4748static int va1j5jf8007t_read_snr(struct dvb_frontend *fe, u16 *snr)49{50struct va1j5jf8007t_state *state;51u8 addr;52int i;53u8 write_buf[1], read_buf[1];54struct i2c_msg msgs[2];55s32 word, x, y;5657state = fe->demodulator_priv;58addr = state->config->demod_address;5960word = 0;61for (i = 0; i < 3; i++) {62write_buf[0] = 0x8b + i;6364msgs[0].addr = addr;65msgs[0].flags = 0;66msgs[0].len = sizeof(write_buf);67msgs[0].buf = write_buf;6869msgs[1].addr = addr;70msgs[1].flags = I2C_M_RD;71msgs[1].len = sizeof(read_buf);72msgs[1].buf = read_buf;7374if (i2c_transfer(state->adap, msgs, 2) != 2)75return -EREMOTEIO;7677word <<= 8;78word |= read_buf[0];79}8081if (!word)82return -EIO;8384x = 10 * (intlog10(0x540000 * 100 / word) - (2 << 24));85y = (24ll << 46) / 1000000;86y = ((s64)y * x >> 30) - (16ll << 40) / 10000;87y = ((s64)y * x >> 29) + (398ll << 35) / 10000;88y = ((s64)y * x >> 30) + (5491ll << 29) / 10000;89y = ((s64)y * x >> 30) + (30965ll << 23) / 10000;90*snr = y >> 15;91return 0;92}9394static int va1j5jf8007t_get_frontend_algo(struct dvb_frontend *fe)95{96return DVBFE_ALGO_HW;97}9899static int100va1j5jf8007t_read_status(struct dvb_frontend *fe, fe_status_t *status)101{102struct va1j5jf8007t_state *state;103104state = fe->demodulator_priv;105106switch (state->tune_state) {107case VA1J5JF8007T_IDLE:108case VA1J5JF8007T_SET_FREQUENCY:109case VA1J5JF8007T_CHECK_FREQUENCY:110*status = 0;111return 0;112113114case VA1J5JF8007T_SET_MODULATION:115case VA1J5JF8007T_CHECK_MODULATION:116case VA1J5JF8007T_ABORT:117*status |= FE_HAS_SIGNAL;118return 0;119120case VA1J5JF8007T_TRACK:121*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK;122return 0;123}124125BUG();126}127128struct va1j5jf8007t_cb_map {129u32 frequency;130u8 cb;131};132133static const struct va1j5jf8007t_cb_map va1j5jf8007t_cb_maps[] = {134{ 90000000, 0x80 },135{ 140000000, 0x81 },136{ 170000000, 0xa1 },137{ 220000000, 0x62 },138{ 330000000, 0xa2 },139{ 402000000, 0xe2 },140{ 450000000, 0x64 },141{ 550000000, 0x84 },142{ 600000000, 0xa4 },143{ 700000000, 0xc4 },144};145146static u8 va1j5jf8007t_lookup_cb(u32 frequency)147{148int i;149const struct va1j5jf8007t_cb_map *map;150151for (i = 0; i < ARRAY_SIZE(va1j5jf8007t_cb_maps); i++) {152map = &va1j5jf8007t_cb_maps[i];153if (frequency < map->frequency)154return map->cb;155}156return 0xe4;157}158159static int va1j5jf8007t_set_frequency(struct va1j5jf8007t_state *state)160{161u32 frequency;162u16 word;163u8 buf[6];164struct i2c_msg msg;165166frequency = state->fe.dtv_property_cache.frequency;167168word = (frequency + 71428) / 142857 + 399;169buf[0] = 0xfe;170buf[1] = 0xc2;171buf[2] = word >> 8;172buf[3] = word;173buf[4] = 0x80;174buf[5] = va1j5jf8007t_lookup_cb(frequency);175176msg.addr = state->config->demod_address;177msg.flags = 0;178msg.len = sizeof(buf);179msg.buf = buf;180181if (i2c_transfer(state->adap, &msg, 1) != 1)182return -EREMOTEIO;183184return 0;185}186187static int188va1j5jf8007t_check_frequency(struct va1j5jf8007t_state *state, int *lock)189{190u8 addr;191u8 write_buf[2], read_buf[1];192struct i2c_msg msgs[2];193194addr = state->config->demod_address;195196write_buf[0] = 0xfe;197write_buf[1] = 0xc3;198199msgs[0].addr = addr;200msgs[0].flags = 0;201msgs[0].len = sizeof(write_buf);202msgs[0].buf = write_buf;203204msgs[1].addr = addr;205msgs[1].flags = I2C_M_RD;206msgs[1].len = sizeof(read_buf);207msgs[1].buf = read_buf;208209if (i2c_transfer(state->adap, msgs, 2) != 2)210return -EREMOTEIO;211212*lock = read_buf[0] & 0x40;213return 0;214}215216static int va1j5jf8007t_set_modulation(struct va1j5jf8007t_state *state)217{218u8 buf[2];219struct i2c_msg msg;220221buf[0] = 0x01;222buf[1] = 0x40;223224msg.addr = state->config->demod_address;225msg.flags = 0;226msg.len = sizeof(buf);227msg.buf = buf;228229if (i2c_transfer(state->adap, &msg, 1) != 1)230return -EREMOTEIO;231232return 0;233}234235static int va1j5jf8007t_check_modulation(struct va1j5jf8007t_state *state,236int *lock, int *retry)237{238u8 addr;239u8 write_buf[1], read_buf[1];240struct i2c_msg msgs[2];241242addr = state->config->demod_address;243244write_buf[0] = 0x80;245246msgs[0].addr = addr;247msgs[0].flags = 0;248msgs[0].len = sizeof(write_buf);249msgs[0].buf = write_buf;250251msgs[1].addr = addr;252msgs[1].flags = I2C_M_RD;253msgs[1].len = sizeof(read_buf);254msgs[1].buf = read_buf;255256if (i2c_transfer(state->adap, msgs, 2) != 2)257return -EREMOTEIO;258259*lock = !(read_buf[0] & 0x10);260*retry = read_buf[0] & 0x80;261return 0;262}263264static int265va1j5jf8007t_tune(struct dvb_frontend *fe,266struct dvb_frontend_parameters *params,267unsigned int mode_flags, unsigned int *delay,268fe_status_t *status)269{270struct va1j5jf8007t_state *state;271int ret;272int lock = 0, retry = 0;273274state = fe->demodulator_priv;275276if (params != NULL)277state->tune_state = VA1J5JF8007T_SET_FREQUENCY;278279switch (state->tune_state) {280case VA1J5JF8007T_IDLE:281*delay = 3 * HZ;282*status = 0;283return 0;284285case VA1J5JF8007T_SET_FREQUENCY:286ret = va1j5jf8007t_set_frequency(state);287if (ret < 0)288return ret;289290state->tune_state = VA1J5JF8007T_CHECK_FREQUENCY;291*delay = 0;292*status = 0;293return 0;294295case VA1J5JF8007T_CHECK_FREQUENCY:296ret = va1j5jf8007t_check_frequency(state, &lock);297if (ret < 0)298return ret;299300if (!lock) {301*delay = (HZ + 999) / 1000;302*status = 0;303return 0;304}305306state->tune_state = VA1J5JF8007T_SET_MODULATION;307*delay = 0;308*status = FE_HAS_SIGNAL;309return 0;310311case VA1J5JF8007T_SET_MODULATION:312ret = va1j5jf8007t_set_modulation(state);313if (ret < 0)314return ret;315316state->tune_state = VA1J5JF8007T_CHECK_MODULATION;317*delay = 0;318*status = FE_HAS_SIGNAL;319return 0;320321case VA1J5JF8007T_CHECK_MODULATION:322ret = va1j5jf8007t_check_modulation(state, &lock, &retry);323if (ret < 0)324return ret;325326if (!lock) {327if (!retry) {328state->tune_state = VA1J5JF8007T_ABORT;329*delay = 3 * HZ;330*status = FE_HAS_SIGNAL;331return 0;332}333*delay = (HZ + 999) / 1000;334*status = FE_HAS_SIGNAL;335return 0;336}337338state->tune_state = VA1J5JF8007T_TRACK;339/* fall through */340341case VA1J5JF8007T_TRACK:342*delay = 3 * HZ;343*status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK;344return 0;345346case VA1J5JF8007T_ABORT:347*delay = 3 * HZ;348*status = FE_HAS_SIGNAL;349return 0;350}351352BUG();353}354355static int va1j5jf8007t_init_frequency(struct va1j5jf8007t_state *state)356{357u8 buf[7];358struct i2c_msg msg;359360buf[0] = 0xfe;361buf[1] = 0xc2;362buf[2] = 0x01;363buf[3] = 0x8f;364buf[4] = 0xc1;365buf[5] = 0x80;366buf[6] = 0x80;367368msg.addr = state->config->demod_address;369msg.flags = 0;370msg.len = sizeof(buf);371msg.buf = buf;372373if (i2c_transfer(state->adap, &msg, 1) != 1)374return -EREMOTEIO;375376return 0;377}378379static int va1j5jf8007t_set_sleep(struct va1j5jf8007t_state *state, int sleep)380{381u8 buf[2];382struct i2c_msg msg;383384buf[0] = 0x03;385buf[1] = sleep ? 0x90 : 0x80;386387msg.addr = state->config->demod_address;388msg.flags = 0;389msg.len = sizeof(buf);390msg.buf = buf;391392if (i2c_transfer(state->adap, &msg, 1) != 1)393return -EREMOTEIO;394395return 0;396}397398static int va1j5jf8007t_sleep(struct dvb_frontend *fe)399{400struct va1j5jf8007t_state *state;401int ret;402403state = fe->demodulator_priv;404405ret = va1j5jf8007t_init_frequency(state);406if (ret < 0)407return ret;408409return va1j5jf8007t_set_sleep(state, 1);410}411412static int va1j5jf8007t_init(struct dvb_frontend *fe)413{414struct va1j5jf8007t_state *state;415416state = fe->demodulator_priv;417state->tune_state = VA1J5JF8007T_IDLE;418419return va1j5jf8007t_set_sleep(state, 0);420}421422static void va1j5jf8007t_release(struct dvb_frontend *fe)423{424struct va1j5jf8007t_state *state;425state = fe->demodulator_priv;426kfree(state);427}428429static struct dvb_frontend_ops va1j5jf8007t_ops = {430.info = {431.name = "VA1J5JF8007/VA1J5JF8011 ISDB-T",432.type = FE_OFDM,433.frequency_min = 90000000,434.frequency_max = 770000000,435.frequency_stepsize = 142857,436.caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO |437FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |438FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO,439},440441.read_snr = va1j5jf8007t_read_snr,442.get_frontend_algo = va1j5jf8007t_get_frontend_algo,443.read_status = va1j5jf8007t_read_status,444.tune = va1j5jf8007t_tune,445.sleep = va1j5jf8007t_sleep,446.init = va1j5jf8007t_init,447.release = va1j5jf8007t_release,448};449450static const u8 va1j5jf8007t_20mhz_prepare_bufs[][2] = {451{0x03, 0x90}, {0x14, 0x8f}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2},452{0x22, 0x83}, {0x31, 0x0d}, {0x32, 0xe0}, {0x39, 0xd3}, {0x3a, 0x00},453{0x5c, 0x40}, {0x5f, 0x80}, {0x75, 0x02}, {0x76, 0x4e}, {0x77, 0x03},454{0xef, 0x01}455};456457static const u8 va1j5jf8007t_25mhz_prepare_bufs[][2] = {458{0x03, 0x90}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2}, {0x22, 0x83},459{0x3a, 0x00}, {0x5c, 0x40}, {0x5f, 0x80}, {0x75, 0x0a}, {0x76, 0x4c},460{0x77, 0x03}, {0xef, 0x01}461};462463int va1j5jf8007t_prepare(struct dvb_frontend *fe)464{465struct va1j5jf8007t_state *state;466const u8 (*bufs)[2];467int size;468u8 buf[2];469struct i2c_msg msg;470int i;471472state = fe->demodulator_priv;473474switch (state->config->frequency) {475case VA1J5JF8007T_20MHZ:476bufs = va1j5jf8007t_20mhz_prepare_bufs;477size = ARRAY_SIZE(va1j5jf8007t_20mhz_prepare_bufs);478break;479case VA1J5JF8007T_25MHZ:480bufs = va1j5jf8007t_25mhz_prepare_bufs;481size = ARRAY_SIZE(va1j5jf8007t_25mhz_prepare_bufs);482break;483default:484return -EINVAL;485}486487msg.addr = state->config->demod_address;488msg.flags = 0;489msg.len = sizeof(buf);490msg.buf = buf;491492for (i = 0; i < size; i++) {493memcpy(buf, bufs[i], sizeof(buf));494if (i2c_transfer(state->adap, &msg, 1) != 1)495return -EREMOTEIO;496}497498return va1j5jf8007t_init_frequency(state);499}500501struct dvb_frontend *502va1j5jf8007t_attach(const struct va1j5jf8007t_config *config,503struct i2c_adapter *adap)504{505struct va1j5jf8007t_state *state;506struct dvb_frontend *fe;507u8 buf[2];508struct i2c_msg msg;509510state = kzalloc(sizeof(struct va1j5jf8007t_state), GFP_KERNEL);511if (!state)512return NULL;513514state->config = config;515state->adap = adap;516517fe = &state->fe;518memcpy(&fe->ops, &va1j5jf8007t_ops, sizeof(struct dvb_frontend_ops));519fe->demodulator_priv = state;520521buf[0] = 0x01;522buf[1] = 0x80;523524msg.addr = state->config->demod_address;525msg.flags = 0;526msg.len = sizeof(buf);527msg.buf = buf;528529if (i2c_transfer(state->adap, &msg, 1) != 1) {530kfree(state);531return NULL;532}533534return fe;535}536537538