Path: blob/master/drivers/media/dvb/pt1/va1j5jf8007s.c
15112 views
/*1* ISDB-S 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 "va1j5jf8007s.h"2930enum va1j5jf8007s_tune_state {31VA1J5JF8007S_IDLE,32VA1J5JF8007S_SET_FREQUENCY_1,33VA1J5JF8007S_SET_FREQUENCY_2,34VA1J5JF8007S_SET_FREQUENCY_3,35VA1J5JF8007S_CHECK_FREQUENCY,36VA1J5JF8007S_SET_MODULATION,37VA1J5JF8007S_CHECK_MODULATION,38VA1J5JF8007S_SET_TS_ID,39VA1J5JF8007S_CHECK_TS_ID,40VA1J5JF8007S_TRACK,41};4243struct va1j5jf8007s_state {44const struct va1j5jf8007s_config *config;45struct i2c_adapter *adap;46struct dvb_frontend fe;47enum va1j5jf8007s_tune_state tune_state;48};4950static int va1j5jf8007s_read_snr(struct dvb_frontend *fe, u16 *snr)51{52struct va1j5jf8007s_state *state;53u8 addr;54int i;55u8 write_buf[1], read_buf[1];56struct i2c_msg msgs[2];57s32 word, x1, x2, x3, x4, x5, y;5859state = fe->demodulator_priv;60addr = state->config->demod_address;6162word = 0;63for (i = 0; i < 2; i++) {64write_buf[0] = 0xbc + i;6566msgs[0].addr = addr;67msgs[0].flags = 0;68msgs[0].len = sizeof(write_buf);69msgs[0].buf = write_buf;7071msgs[1].addr = addr;72msgs[1].flags = I2C_M_RD;73msgs[1].len = sizeof(read_buf);74msgs[1].buf = read_buf;7576if (i2c_transfer(state->adap, msgs, 2) != 2)77return -EREMOTEIO;7879word <<= 8;80word |= read_buf[0];81}8283word -= 3000;84if (word < 0)85word = 0;8687x1 = int_sqrt(word << 16) * ((15625ll << 21) / 1000000);88x2 = (s64)x1 * x1 >> 31;89x3 = (s64)x2 * x1 >> 31;90x4 = (s64)x2 * x2 >> 31;91x5 = (s64)x4 * x1 >> 31;9293y = (58857ll << 23) / 1000;94y -= (s64)x1 * ((89565ll << 24) / 1000) >> 30;95y += (s64)x2 * ((88977ll << 24) / 1000) >> 28;96y -= (s64)x3 * ((50259ll << 25) / 1000) >> 27;97y += (s64)x4 * ((14341ll << 27) / 1000) >> 27;98y -= (s64)x5 * ((16346ll << 30) / 10000) >> 28;99100*snr = y < 0 ? 0 : y >> 15;101return 0;102}103104static int va1j5jf8007s_get_frontend_algo(struct dvb_frontend *fe)105{106return DVBFE_ALGO_HW;107}108109static int110va1j5jf8007s_read_status(struct dvb_frontend *fe, fe_status_t *status)111{112struct va1j5jf8007s_state *state;113114state = fe->demodulator_priv;115116switch (state->tune_state) {117case VA1J5JF8007S_IDLE:118case VA1J5JF8007S_SET_FREQUENCY_1:119case VA1J5JF8007S_SET_FREQUENCY_2:120case VA1J5JF8007S_SET_FREQUENCY_3:121case VA1J5JF8007S_CHECK_FREQUENCY:122*status = 0;123return 0;124125126case VA1J5JF8007S_SET_MODULATION:127case VA1J5JF8007S_CHECK_MODULATION:128*status |= FE_HAS_SIGNAL;129return 0;130131case VA1J5JF8007S_SET_TS_ID:132case VA1J5JF8007S_CHECK_TS_ID:133*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;134return 0;135136case VA1J5JF8007S_TRACK:137*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK;138return 0;139}140141BUG();142}143144struct va1j5jf8007s_cb_map {145u32 frequency;146u8 cb;147};148149static const struct va1j5jf8007s_cb_map va1j5jf8007s_cb_maps[] = {150{ 986000, 0xb2 },151{ 1072000, 0xd2 },152{ 1154000, 0xe2 },153{ 1291000, 0x20 },154{ 1447000, 0x40 },155{ 1615000, 0x60 },156{ 1791000, 0x80 },157{ 1972000, 0xa0 },158};159160static u8 va1j5jf8007s_lookup_cb(u32 frequency)161{162int i;163const struct va1j5jf8007s_cb_map *map;164165for (i = 0; i < ARRAY_SIZE(va1j5jf8007s_cb_maps); i++) {166map = &va1j5jf8007s_cb_maps[i];167if (frequency < map->frequency)168return map->cb;169}170return 0xc0;171}172173static int va1j5jf8007s_set_frequency_1(struct va1j5jf8007s_state *state)174{175u32 frequency;176u16 word;177u8 buf[6];178struct i2c_msg msg;179180frequency = state->fe.dtv_property_cache.frequency;181182word = (frequency + 500) / 1000;183if (frequency < 1072000)184word = (word << 1 & ~0x1f) | (word & 0x0f);185186buf[0] = 0xfe;187buf[1] = 0xc0;188buf[2] = 0x40 | word >> 8;189buf[3] = word;190buf[4] = 0xe0;191buf[5] = va1j5jf8007s_lookup_cb(frequency);192193msg.addr = state->config->demod_address;194msg.flags = 0;195msg.len = sizeof(buf);196msg.buf = buf;197198if (i2c_transfer(state->adap, &msg, 1) != 1)199return -EREMOTEIO;200201return 0;202}203204static int va1j5jf8007s_set_frequency_2(struct va1j5jf8007s_state *state)205{206u8 buf[3];207struct i2c_msg msg;208209buf[0] = 0xfe;210buf[1] = 0xc0;211buf[2] = 0xe4;212213msg.addr = state->config->demod_address;214msg.flags = 0;215msg.len = sizeof(buf);216msg.buf = buf;217218if (i2c_transfer(state->adap, &msg, 1) != 1)219return -EREMOTEIO;220221return 0;222}223224static int va1j5jf8007s_set_frequency_3(struct va1j5jf8007s_state *state)225{226u32 frequency;227u8 buf[4];228struct i2c_msg msg;229230frequency = state->fe.dtv_property_cache.frequency;231232buf[0] = 0xfe;233buf[1] = 0xc0;234buf[2] = 0xf4;235buf[3] = va1j5jf8007s_lookup_cb(frequency) | 0x4;236237msg.addr = state->config->demod_address;238msg.flags = 0;239msg.len = sizeof(buf);240msg.buf = buf;241242if (i2c_transfer(state->adap, &msg, 1) != 1)243return -EREMOTEIO;244245return 0;246}247248static int249va1j5jf8007s_check_frequency(struct va1j5jf8007s_state *state, int *lock)250{251u8 addr;252u8 write_buf[2], read_buf[1];253struct i2c_msg msgs[2];254255addr = state->config->demod_address;256257write_buf[0] = 0xfe;258write_buf[1] = 0xc1;259260msgs[0].addr = addr;261msgs[0].flags = 0;262msgs[0].len = sizeof(write_buf);263msgs[0].buf = write_buf;264265msgs[1].addr = addr;266msgs[1].flags = I2C_M_RD;267msgs[1].len = sizeof(read_buf);268msgs[1].buf = read_buf;269270if (i2c_transfer(state->adap, msgs, 2) != 2)271return -EREMOTEIO;272273*lock = read_buf[0] & 0x40;274return 0;275}276277static int va1j5jf8007s_set_modulation(struct va1j5jf8007s_state *state)278{279u8 buf[2];280struct i2c_msg msg;281282buf[0] = 0x03;283buf[1] = 0x01;284285msg.addr = state->config->demod_address;286msg.flags = 0;287msg.len = sizeof(buf);288msg.buf = buf;289290if (i2c_transfer(state->adap, &msg, 1) != 1)291return -EREMOTEIO;292293return 0;294}295296static int297va1j5jf8007s_check_modulation(struct va1j5jf8007s_state *state, int *lock)298{299u8 addr;300u8 write_buf[1], read_buf[1];301struct i2c_msg msgs[2];302303addr = state->config->demod_address;304305write_buf[0] = 0xc3;306307msgs[0].addr = addr;308msgs[0].flags = 0;309msgs[0].len = sizeof(write_buf);310msgs[0].buf = write_buf;311312msgs[1].addr = addr;313msgs[1].flags = I2C_M_RD;314msgs[1].len = sizeof(read_buf);315msgs[1].buf = read_buf;316317if (i2c_transfer(state->adap, msgs, 2) != 2)318return -EREMOTEIO;319320*lock = !(read_buf[0] & 0x10);321return 0;322}323324static int325va1j5jf8007s_set_ts_id(struct va1j5jf8007s_state *state)326{327u32 ts_id;328u8 buf[3];329struct i2c_msg msg;330331ts_id = state->fe.dtv_property_cache.isdbs_ts_id;332if (!ts_id)333return 0;334335buf[0] = 0x8f;336buf[1] = ts_id >> 8;337buf[2] = ts_id;338339msg.addr = state->config->demod_address;340msg.flags = 0;341msg.len = sizeof(buf);342msg.buf = buf;343344if (i2c_transfer(state->adap, &msg, 1) != 1)345return -EREMOTEIO;346347return 0;348}349350static int351va1j5jf8007s_check_ts_id(struct va1j5jf8007s_state *state, int *lock)352{353u8 addr;354u8 write_buf[1], read_buf[2];355struct i2c_msg msgs[2];356u32 ts_id;357358ts_id = state->fe.dtv_property_cache.isdbs_ts_id;359if (!ts_id) {360*lock = 1;361return 0;362}363364addr = state->config->demod_address;365366write_buf[0] = 0xe6;367368msgs[0].addr = addr;369msgs[0].flags = 0;370msgs[0].len = sizeof(write_buf);371msgs[0].buf = write_buf;372373msgs[1].addr = addr;374msgs[1].flags = I2C_M_RD;375msgs[1].len = sizeof(read_buf);376msgs[1].buf = read_buf;377378if (i2c_transfer(state->adap, msgs, 2) != 2)379return -EREMOTEIO;380381*lock = (read_buf[0] << 8 | read_buf[1]) == ts_id;382return 0;383}384385static int386va1j5jf8007s_tune(struct dvb_frontend *fe,387struct dvb_frontend_parameters *params,388unsigned int mode_flags, unsigned int *delay,389fe_status_t *status)390{391struct va1j5jf8007s_state *state;392int ret;393int lock = 0;394395state = fe->demodulator_priv;396397if (params != NULL)398state->tune_state = VA1J5JF8007S_SET_FREQUENCY_1;399400switch (state->tune_state) {401case VA1J5JF8007S_IDLE:402*delay = 3 * HZ;403*status = 0;404return 0;405406case VA1J5JF8007S_SET_FREQUENCY_1:407ret = va1j5jf8007s_set_frequency_1(state);408if (ret < 0)409return ret;410411state->tune_state = VA1J5JF8007S_SET_FREQUENCY_2;412*delay = 0;413*status = 0;414return 0;415416case VA1J5JF8007S_SET_FREQUENCY_2:417ret = va1j5jf8007s_set_frequency_2(state);418if (ret < 0)419return ret;420421state->tune_state = VA1J5JF8007S_SET_FREQUENCY_3;422*delay = (HZ + 99) / 100;423*status = 0;424return 0;425426case VA1J5JF8007S_SET_FREQUENCY_3:427ret = va1j5jf8007s_set_frequency_3(state);428if (ret < 0)429return ret;430431state->tune_state = VA1J5JF8007S_CHECK_FREQUENCY;432*delay = 0;433*status = 0;434return 0;435436case VA1J5JF8007S_CHECK_FREQUENCY:437ret = va1j5jf8007s_check_frequency(state, &lock);438if (ret < 0)439return ret;440441if (!lock) {442*delay = (HZ + 999) / 1000;443*status = 0;444return 0;445}446447state->tune_state = VA1J5JF8007S_SET_MODULATION;448*delay = 0;449*status = FE_HAS_SIGNAL;450return 0;451452case VA1J5JF8007S_SET_MODULATION:453ret = va1j5jf8007s_set_modulation(state);454if (ret < 0)455return ret;456457state->tune_state = VA1J5JF8007S_CHECK_MODULATION;458*delay = 0;459*status = FE_HAS_SIGNAL;460return 0;461462case VA1J5JF8007S_CHECK_MODULATION:463ret = va1j5jf8007s_check_modulation(state, &lock);464if (ret < 0)465return ret;466467if (!lock) {468*delay = (HZ + 49) / 50;469*status = FE_HAS_SIGNAL;470return 0;471}472473state->tune_state = VA1J5JF8007S_SET_TS_ID;474*delay = 0;475*status = FE_HAS_SIGNAL | FE_HAS_CARRIER;476return 0;477478case VA1J5JF8007S_SET_TS_ID:479ret = va1j5jf8007s_set_ts_id(state);480if (ret < 0)481return ret;482483state->tune_state = VA1J5JF8007S_CHECK_TS_ID;484return 0;485486case VA1J5JF8007S_CHECK_TS_ID:487ret = va1j5jf8007s_check_ts_id(state, &lock);488if (ret < 0)489return ret;490491if (!lock) {492*delay = (HZ + 99) / 100;493*status = FE_HAS_SIGNAL | FE_HAS_CARRIER;494return 0;495}496497state->tune_state = VA1J5JF8007S_TRACK;498/* fall through */499500case VA1J5JF8007S_TRACK:501*delay = 3 * HZ;502*status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK;503return 0;504}505506BUG();507}508509static int va1j5jf8007s_init_frequency(struct va1j5jf8007s_state *state)510{511u8 buf[4];512struct i2c_msg msg;513514buf[0] = 0xfe;515buf[1] = 0xc0;516buf[2] = 0xf0;517buf[3] = 0x04;518519msg.addr = state->config->demod_address;520msg.flags = 0;521msg.len = sizeof(buf);522msg.buf = buf;523524if (i2c_transfer(state->adap, &msg, 1) != 1)525return -EREMOTEIO;526527return 0;528}529530static int va1j5jf8007s_set_sleep(struct va1j5jf8007s_state *state, int sleep)531{532u8 buf[2];533struct i2c_msg msg;534535buf[0] = 0x17;536buf[1] = sleep ? 0x01 : 0x00;537538msg.addr = state->config->demod_address;539msg.flags = 0;540msg.len = sizeof(buf);541msg.buf = buf;542543if (i2c_transfer(state->adap, &msg, 1) != 1)544return -EREMOTEIO;545546return 0;547}548549static int va1j5jf8007s_sleep(struct dvb_frontend *fe)550{551struct va1j5jf8007s_state *state;552int ret;553554state = fe->demodulator_priv;555556ret = va1j5jf8007s_init_frequency(state);557if (ret < 0)558return ret;559560return va1j5jf8007s_set_sleep(state, 1);561}562563static int va1j5jf8007s_init(struct dvb_frontend *fe)564{565struct va1j5jf8007s_state *state;566567state = fe->demodulator_priv;568state->tune_state = VA1J5JF8007S_IDLE;569570return va1j5jf8007s_set_sleep(state, 0);571}572573static void va1j5jf8007s_release(struct dvb_frontend *fe)574{575struct va1j5jf8007s_state *state;576state = fe->demodulator_priv;577kfree(state);578}579580static struct dvb_frontend_ops va1j5jf8007s_ops = {581.info = {582.name = "VA1J5JF8007/VA1J5JF8011 ISDB-S",583.type = FE_QPSK,584.frequency_min = 950000,585.frequency_max = 2150000,586.frequency_stepsize = 1000,587.caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO |588FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |589FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO,590},591592.read_snr = va1j5jf8007s_read_snr,593.get_frontend_algo = va1j5jf8007s_get_frontend_algo,594.read_status = va1j5jf8007s_read_status,595.tune = va1j5jf8007s_tune,596.sleep = va1j5jf8007s_sleep,597.init = va1j5jf8007s_init,598.release = va1j5jf8007s_release,599};600601static int va1j5jf8007s_prepare_1(struct va1j5jf8007s_state *state)602{603u8 addr;604u8 write_buf[1], read_buf[1];605struct i2c_msg msgs[2];606607addr = state->config->demod_address;608609write_buf[0] = 0x07;610611msgs[0].addr = addr;612msgs[0].flags = 0;613msgs[0].len = sizeof(write_buf);614msgs[0].buf = write_buf;615616msgs[1].addr = addr;617msgs[1].flags = I2C_M_RD;618msgs[1].len = sizeof(read_buf);619msgs[1].buf = read_buf;620621if (i2c_transfer(state->adap, msgs, 2) != 2)622return -EREMOTEIO;623624if (read_buf[0] != 0x41)625return -EIO;626627return 0;628}629630static const u8 va1j5jf8007s_20mhz_prepare_bufs[][2] = {631{0x04, 0x02}, {0x0d, 0x55}, {0x11, 0x40}, {0x13, 0x80}, {0x17, 0x01},632{0x1c, 0x0a}, {0x1d, 0xaa}, {0x1e, 0x20}, {0x1f, 0x88}, {0x51, 0xb0},633{0x52, 0x89}, {0x53, 0xb3}, {0x5a, 0x2d}, {0x5b, 0xd3}, {0x85, 0x69},634{0x87, 0x04}, {0x8e, 0x02}, {0xa3, 0xf7}, {0xa5, 0xc0},635};636637static const u8 va1j5jf8007s_25mhz_prepare_bufs[][2] = {638{0x04, 0x02}, {0x11, 0x40}, {0x13, 0x80}, {0x17, 0x01}, {0x1c, 0x0a},639{0x1d, 0xaa}, {0x1e, 0x20}, {0x1f, 0x88}, {0x51, 0xb0}, {0x52, 0x89},640{0x53, 0xb3}, {0x5a, 0x2d}, {0x5b, 0xd3}, {0x85, 0x69}, {0x87, 0x04},641{0x8e, 0x26}, {0xa3, 0xf7}, {0xa5, 0xc0},642};643644static int va1j5jf8007s_prepare_2(struct va1j5jf8007s_state *state)645{646const u8 (*bufs)[2];647int size;648u8 addr;649u8 buf[2];650struct i2c_msg msg;651int i;652653switch (state->config->frequency) {654case VA1J5JF8007S_20MHZ:655bufs = va1j5jf8007s_20mhz_prepare_bufs;656size = ARRAY_SIZE(va1j5jf8007s_20mhz_prepare_bufs);657break;658case VA1J5JF8007S_25MHZ:659bufs = va1j5jf8007s_25mhz_prepare_bufs;660size = ARRAY_SIZE(va1j5jf8007s_25mhz_prepare_bufs);661break;662default:663return -EINVAL;664}665666addr = state->config->demod_address;667668msg.addr = addr;669msg.flags = 0;670msg.len = 2;671msg.buf = buf;672for (i = 0; i < size; i++) {673memcpy(buf, bufs[i], sizeof(buf));674if (i2c_transfer(state->adap, &msg, 1) != 1)675return -EREMOTEIO;676}677678return 0;679}680681/* must be called after va1j5jf8007t_attach */682int va1j5jf8007s_prepare(struct dvb_frontend *fe)683{684struct va1j5jf8007s_state *state;685int ret;686687state = fe->demodulator_priv;688689ret = va1j5jf8007s_prepare_1(state);690if (ret < 0)691return ret;692693ret = va1j5jf8007s_prepare_2(state);694if (ret < 0)695return ret;696697return va1j5jf8007s_init_frequency(state);698}699700struct dvb_frontend *701va1j5jf8007s_attach(const struct va1j5jf8007s_config *config,702struct i2c_adapter *adap)703{704struct va1j5jf8007s_state *state;705struct dvb_frontend *fe;706u8 buf[2];707struct i2c_msg msg;708709state = kzalloc(sizeof(struct va1j5jf8007s_state), GFP_KERNEL);710if (!state)711return NULL;712713state->config = config;714state->adap = adap;715716fe = &state->fe;717memcpy(&fe->ops, &va1j5jf8007s_ops, sizeof(struct dvb_frontend_ops));718fe->demodulator_priv = state;719720buf[0] = 0x01;721buf[1] = 0x80;722723msg.addr = state->config->demod_address;724msg.flags = 0;725msg.len = sizeof(buf);726msg.buf = buf;727728if (i2c_transfer(state->adap, &msg, 1) != 1) {729kfree(state);730return NULL;731}732733return fe;734}735736737