[media 4/7] Toshiba TC90522XBG quad demod (2ch OFDM + 2ch 8PSK) for PT3 & PXQ3PE
From: Буди Романто, AreMa Inc Signed-off-by: Буди Романто, AreMa Inc --- drivers/media/dvb-frontends/tc90522.c | 280 ++ drivers/media/dvb-frontends/tc90522.h | 18 +++ 2 files changed, 298 insertions(+) create mode 100644 drivers/media/dvb-frontends/tc90522.c create mode 100644 drivers/media/dvb-frontends/tc90522.h diff --git a/drivers/media/dvb-frontends/tc90522.c b/drivers/media/dvb-frontends/tc90522.c new file mode 100644 index 000..94cfbfc --- /dev/null +++ b/drivers/media/dvb-frontends/tc90522.c @@ -0,0 +1,280 @@ +/* + * Toshiba TC90522XBG 2ch OFDM(ISDB-T) + 2ch 8PSK(ISDB-S) demodulator + * + * Copyright (C) Budi Rachmanto, AreMa Inc. + * + * Supported cards: + * Earthsoft PT3 + * PLEX PX-Q3PE + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include "dvb_math.h" +#include "dvb_frontend.h" +#include "tc90522.h" + +struct tc90522 { + struct i2c_adapter *i2c; + enum fe_status stat; +}; + +bool tc90522_r(struct dvb_frontend *fe, u8 slvadr, u8 *buf, u8 len) +{ + struct tc90522 *d = fe->demodulator_priv; + struct i2c_msg msg[] = { + {.addr = fe->id,.flags = 0, .buf = &slvadr, .len = 1,}, + {.addr = fe->id,.flags = I2C_M_RD, .buf = buf, .len = len,}, + }; + return i2c_transfer(d->i2c, msg, 2) == 2; +} + +bool tc90522_w(struct dvb_frontend *fe, u8 slvadr, u8 dat) +{ + struct tc90522 *d = fe->demodulator_priv; + u8 buf[] = {slvadr, dat}; + struct i2c_msg msg[] = { + {.addr = fe->id,.flags = 0, .buf = buf, .len = 2,}, + }; + return i2c_transfer(d->i2c, msg, 1) == 1; +} + +u64 tc90522_n2int(const u8 *data, u8 n)/* convert n_bytes data from stream (network byte order) to integer */ +{ /* can't use 's ntoh*() as sometimes n = 3,5,... */ + u32 i, val = 0; + + for (i = 0; i < n; i++) { + val <<= 8; + val |= data[i]; + } + return val; +} + +int tc90522_cn_raw(struct dvb_frontend *fe, u16 *raw) /* for DVBv3 compatibility */ +{ + u8 buf[3], + len = fe->dtv_property_cache.delivery_system == SYS_ISDBS ? 2 : 3, + adr = fe->dtv_property_cache.delivery_system == SYS_ISDBS ? 0xbc : 0x8b; + boolok = tc90522_r(fe, adr, buf, len); + int cn = tc90522_n2int(buf, len); + + if (!ok) + return -EIO; + *raw = cn; + return cn; +} + +int tc90522_status(struct dvb_frontend *fe, enum fe_status *stat) +{ + struct tc90522 *d = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u16 v16; + s64 raw = tc90522_cn_raw(fe, &v16), + x, + y; + + s64 cn_s(void) /* @ .0001 dB */ + { + raw -= 3000; + if (raw < 0) + raw = 0; + x = int_sqrt(raw << 20); + y = 16346ll * x - (143410ll << 16); + y = ((x * y) >> 16) + (502590ll << 16); + y = ((x * y) >> 16) - (889770ll << 16); + y = ((x * y) >> 16) + (895650ll << 16); + y = (588570ll << 16) - ((x * y) >> 16); + return y < 0 ? 0 : y >> 16; + } + + s64 cn_t(void) /* @ .0001 dB */ + { + if (!raw) + return 0; + x = (1130911733ll - 10ll * intlog10(raw)) >> 2; + y = (x >> 2) - (x >> 6) + (x >> 8) + (x >> 9) - (x >> 10) + (x >> 11) + (x >> 12) - (16ll << 22); + y = ((x * y) >> 22) + (398ll << 22); + y = ((x * y) >> 22) + (5491ll << 22); + y = ((x * y) >> 22) + (30965ll << 22); + return y >> 22; + } + + c->cnr.len = 1; + c->cnr.stat[0].svalue = fe->dtv_property_cache.delivery_system == SYS_ISDBS ? cn_s() : cn_t(); + c->cnr.stat[0].scale= FE_SCALE_DECIBEL; + *stat = d->stat; + return d->stat; +} + +int tc90522_get_frontend_algo(struct dvb_frontend *fe) +{ + return DVBFE_ALGO_HW; +} + +int tc90522_tune(struct dvb_frontend *fe, bool retune, u32 mode_flags, u32 *delay, enum fe_status *stat) +{ + u32 fno2kHz(u32 fno) + { + u32 chno; + + if (fno < 12) { + chno = 1 + 2 * fno; /* BS */ + return 1049480 + 38360 * fno; + } else if (fno < 24) { + fno -= 12; + chno = 2 + 2 * fno; /* CS110 right */ +
[media 4/7] Toshiba TC90522XBG quad demod (2ch OFDM + 2ch 8PSK) for PT3 & PXQ3PE
From: Буди Романто, AreMa Inc Signed-off-by: Буди Романто, AreMa Inc --- drivers/media/dvb-frontends/tc90522.c | 280 ++ drivers/media/dvb-frontends/tc90522.h | 18 +++ 2 files changed, 298 insertions(+) create mode 100644 drivers/media/dvb-frontends/tc90522.c create mode 100644 drivers/media/dvb-frontends/tc90522.h diff --git a/drivers/media/dvb-frontends/tc90522.c b/drivers/media/dvb-frontends/tc90522.c new file mode 100644 index 000..94cfbfc --- /dev/null +++ b/drivers/media/dvb-frontends/tc90522.c @@ -0,0 +1,280 @@ +/* + * Toshiba TC90522XBG 2ch OFDM(ISDB-T) + 2ch 8PSK(ISDB-S) demodulator + * + * Copyright (C) Budi Rachmanto, AreMa Inc. + * + * Supported cards: + * Earthsoft PT3 + * PLEX PX-Q3PE + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include "dvb_math.h" +#include "dvb_frontend.h" +#include "tc90522.h" + +struct tc90522 { + struct i2c_adapter *i2c; + enum fe_status stat; +}; + +bool tc90522_r(struct dvb_frontend *fe, u8 slvadr, u8 *buf, u8 len) +{ + struct tc90522 *d = fe->demodulator_priv; + struct i2c_msg msg[] = { + {.addr = fe->id,.flags = 0, .buf = &slvadr, .len = 1,}, + {.addr = fe->id,.flags = I2C_M_RD, .buf = buf, .len = len,}, + }; + return i2c_transfer(d->i2c, msg, 2) == 2; +} + +bool tc90522_w(struct dvb_frontend *fe, u8 slvadr, u8 dat) +{ + struct tc90522 *d = fe->demodulator_priv; + u8 buf[] = {slvadr, dat}; + struct i2c_msg msg[] = { + {.addr = fe->id,.flags = 0, .buf = buf, .len = 2,}, + }; + return i2c_transfer(d->i2c, msg, 1) == 1; +} + +u64 tc90522_n2int(const u8 *data, u8 n)/* convert n_bytes data from stream (network byte order) to integer */ +{ /* can't use 's ntoh*() as sometimes n = 3,5,... */ + u32 i, val = 0; + + for (i = 0; i < n; i++) { + val <<= 8; + val |= data[i]; + } + return val; +} + +int tc90522_cn_raw(struct dvb_frontend *fe, u16 *raw) /* for DVBv3 compatibility */ +{ + u8 buf[3], + len = fe->dtv_property_cache.delivery_system == SYS_ISDBS ? 2 : 3, + adr = fe->dtv_property_cache.delivery_system == SYS_ISDBS ? 0xbc : 0x8b; + boolok = tc90522_r(fe, adr, buf, len); + int cn = tc90522_n2int(buf, len); + + if (!ok) + return -EIO; + *raw = cn; + return cn; +} + +int tc90522_status(struct dvb_frontend *fe, enum fe_status *stat) +{ + struct tc90522 *d = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u16 v16; + s64 raw = tc90522_cn_raw(fe, &v16), + x, + y; + + s64 cn_s(void) /* @ .0001 dB */ + { + raw -= 3000; + if (raw < 0) + raw = 0; + x = int_sqrt(raw << 20); + y = 16346ll * x - (143410ll << 16); + y = ((x * y) >> 16) + (502590ll << 16); + y = ((x * y) >> 16) - (889770ll << 16); + y = ((x * y) >> 16) + (895650ll << 16); + y = (588570ll << 16) - ((x * y) >> 16); + return y < 0 ? 0 : y >> 16; + } + + s64 cn_t(void) /* @ .0001 dB */ + { + if (!raw) + return 0; + x = (1130911733ll - 10ll * intlog10(raw)) >> 2; + y = (x >> 2) - (x >> 6) + (x >> 8) + (x >> 9) - (x >> 10) + (x >> 11) + (x >> 12) - (16ll << 22); + y = ((x * y) >> 22) + (398ll << 22); + y = ((x * y) >> 22) + (5491ll << 22); + y = ((x * y) >> 22) + (30965ll << 22); + return y >> 22; + } + + c->cnr.len = 1; + c->cnr.stat[0].svalue = fe->dtv_property_cache.delivery_system == SYS_ISDBS ? cn_s() : cn_t(); + c->cnr.stat[0].scale= FE_SCALE_DECIBEL; + *stat = d->stat; + return d->stat; +} + +int tc90522_get_frontend_algo(struct dvb_frontend *fe) +{ + return DVBFE_ALGO_HW; +} + +int tc90522_tune(struct dvb_frontend *fe, bool retune, u32 mode_flags, u32 *delay, enum fe_status *stat) +{ + u32 fno2kHz(u32 fno) + { + u32 chno; + + if (fno < 12) { + chno = 1 + 2 * fno; /* BS */ + return 1049480 + 38360 * fno; + } else if (fno < 24) { + fno -= 12; + chno = 2 + 2 * fno; /* CS110 right */ +