[media 4/7] Toshiba TC90522XBG quad demod (2ch OFDM + 2ch 8PSK) for PT3 & PXQ3PE

2016-02-15 Thread info
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

2016-02-15 Thread info
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  */
+