From patchwork Mon Feb 15 06:08:46 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guest X-Patchwork-Id: 8310051 Return-Path: X-Original-To: patchwork-linux-media@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 04E63C02AA for ; Mon, 15 Feb 2016 06:11:46 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id B1AC92051C for ; Mon, 15 Feb 2016 06:11:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 5A274204D8 for ; Mon, 15 Feb 2016 06:11:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752336AbcBOGL3 (ORCPT ); Mon, 15 Feb 2016 01:11:29 -0500 Received: from mail-pa0-f50.google.com ([209.85.220.50]:35176 "EHLO mail-pa0-f50.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751745AbcBOGJF (ORCPT ); Mon, 15 Feb 2016 01:09:05 -0500 Received: by mail-pa0-f50.google.com with SMTP id ho8so81245300pac.2; Sun, 14 Feb 2016 22:09:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references :in-reply-to:references:mime-version:content-type :content-transfer-encoding; bh=ERdbedK4PZdDL391/IF+lCL1EQF/otE4C0uNl3cHQ5s=; b=EkgtdG+MsF4TL8tJkYkFrsstmSukHevRX8U3jrcCy4/xNfJYg3rdEPJybO1o6KVrv7 X+YPVq634YIAZE1bxqfe4Kg9AIbdxZB/8gtM+0Ba9LoKNP/KRhjjqyirbeGy4XhPoroM /6RumQ0UzB1OP7xkzRpl3/Te58FFEiWFH9QZZO0Aot4uQ1wQTZ5HC9X3Tp8EXcpy6uEb vmvNmeEE2L19rUPP2YrxHSl9Us1Ne9J9kBi4UPreM7OGhzgiVUoEA/M8+1CEpnDTnxap Aq3oe8xfPA4/8CARUYiOxqDmfVa5+12HFVHy5dwW5UvpZZ8EKxgQEsG3l5iwowJ5Ogiu rsFg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references:in-reply-to:references:mime-version :content-type:content-transfer-encoding; bh=ERdbedK4PZdDL391/IF+lCL1EQF/otE4C0uNl3cHQ5s=; b=bJE9ox94rTAniiUYNlWOQ/02n6tSRk5ZMQEpdJqBBdBRokgLWPxUjeMV5CcWX3nct/ 1YrK1umJ7ZdyWV/GmhDqWlV+0L5UJdFXKYSM6pZnDeuotjyYTwoI5JPw+Zmcx86cRZ1i 7E+OXGG2r4igzq9HrOmRDSuVEoux8KkheEPoUVdgVbCIxVov1pZ/nbg7SNEAit/86Ntt N7V63v97Oi5UGnFO9c8Md30q1gFiMBBmJ0TMio17VrBH5ZCHbBhGCuPN699ze2TNcpoa x7Vvo8w9bCD4nqdT/HFzy0WjYc/b0gYeoyTEQwfANI9pb8fO3u1u9gRvgsbdMnA5bpIc tcdA== X-Gm-Message-State: AG10YOSbcnlefUL+P+H18Hs7UCpOr84Vak1wLveVGZcczesPk/kveA1hQeXjJ+07rjVgHA== X-Received: by 10.67.1.129 with SMTP id bg1mr21153636pad.63.1455516544583; Sun, 14 Feb 2016 22:09:04 -0800 (PST) Received: from localhost (x154035.dynamic.ppp.asahi-net.or.jp. [122.249.154.35]) by smtp.gmail.com with ESMTPSA id t29sm35364906pfi.8.2016.02.14.22.09.03 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 14 Feb 2016 22:09:04 -0800 (PST) From: info@are.ma X-Google-Original-From: knightrider@are.ma To: linux-media@vger.kernel.org Cc: =?UTF-8?q?=D0=91=D1=83=D0=B4=D0=B8=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D1=82=D0=BE=2C=20AreMa=20Inc?= , linux-kernel@vger.kernel.org, crope@iki.fi, m.chehab@samsung.com, mchehab@osg.samsung.com, hdegoede@redhat.com, laurent.pinchart@ideasonboard.com, mkrufky@linuxtv.org, sylvester.nawrocki@gmail.com, g.liakhovetski@gmx.de, peter.senna@gmail.com Subject: [media 4/7] Toshiba TC90522XBG quad demodulator (2ch OFDM + 2ch 8PSK) used by both PT3 & PX-Q3PE Date: Mon, 15 Feb 2016 15:08:46 +0900 Message-Id: <1fa976cd9b42927575f3a3194915a50e1c4b18b1.1455513464.git.knightrider@are.ma> X-Mailer: git-send-email 2.3.10 In-Reply-To: References: In-Reply-To: References: MIME-Version: 1.0 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Spam-Status: No, score=-6.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,RP_MATCHES_RCVD,T_DKIM_INVALID,UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: ???? ???????, AreMa Inc Signed-off-by: ???? ???????, AreMa Inc --- drivers/media/dvb-frontends/tc90522.c | 283 ++++++++++++++++++++++++++++++++++ drivers/media/dvb-frontends/tc90522.h | 18 +++ 2 files changed, 301 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 0000000..97d18ba --- /dev/null +++ b/drivers/media/dvb-frontends/tc90522.c @@ -0,0 +1,283 @@ +/* + * 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; + fe_status_t 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; + bool ok = 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, fe_status_t *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, fe_status_t *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 */ + return 1613000 + 40000 * fno; + } + fno -= 24; + chno = 1 + 2 * fno; /* CS110 left */ + return 1593000 + 40000 * fno; + } + + void s_kHz(u32 *f) + { + *f = *f > 3000000 ? fno2kHz(14) : /* CNN etc. */ + *f >= 1049480 ? *f : + *f > 48 ? fno2kHz(4) : /* BS11 etc. */ + fno2kHz(*f - 1); + } + + u32 fno2Hz(u32 fno) + { + return (fno > 112 ? 557 : 93 + 6 * fno + (fno < 12 ? 0 : fno < 17 ? 2 : fno < 63 ? 0 : 2)) * 1000000 + 142857; + } + + void t_Hz(u32 *f) + { + *f = *f >= 90000000 ? *f : /* real_freq Hz */ + *f > 255 ? fno2Hz(77) : /* NHK */ + *f > 127 ? fno2Hz(*f - 128) : /* freqno (IO#) */ + *f > 63 ? (*f -= 64, /* CATV */ + *f > 22 ? fno2Hz(*f - 1) : /* C23-C62 */ + *f > 12 ? fno2Hz(*f - 10) : /* C13-C22 */ + fno2Hz(77)) : + *f > 62 ? fno2Hz(77) : + *f > 12 ? fno2Hz(*f + 50) : /* 13-62 */ + *f > 3 ? fno2Hz(*f + 9) : /* 4-12 */ + *f ? fno2Hz(*f - 1) : /* 1-3 */ + fno2Hz(77); + } + struct tc90522 *d = fe->demodulator_priv; + u16 stream_id = fe->dtv_property_cache.stream_id, + i = 0xFFFF; + u8 data[16]; + + if (!retune) /* once is enough */ + return 0; + d->stat = 0; + if (fe->dtv_property_cache.delivery_system == SYS_ISDBT) + goto ISDBT; + + s_kHz(&fe->dtv_property_cache.frequency); + if (fe->ops.tuner_ops.set_params(fe)) + return -EIO; + while (i--) { + if ((tc90522_r(fe, 0xC3, data, 1), !(data[0] & 0x10)) && /* locked */ + (tc90522_r(fe, 0xCE, data, 2), *(u16 *)data != 0) && /* valid TSID */ + tc90522_r(fe, 0xC3, data, 1) && + tc90522_r(fe, 0xCE, data, 16)) + break; + msleep_interruptible(1); + } + if (!i) + return -ETIMEDOUT; + for (i = 0; i < 8; i++) { + u16 tsid = tc90522_n2int(data + i*2, 2); + + if ((tsid == stream_id || stream_id == i) && + tc90522_w(fe, 0x8F, tsid >> 8) && + tc90522_w(fe, 0x90, tsid & 0xFF) && + tc90522_r(fe, 0xE6, data, 2) && + tc90522_n2int(data, 2) == tsid) + goto LOCK; + } + goto ERR; +ISDBT: + t_Hz(&fe->dtv_property_cache.frequency); + if (fe->ops.tuner_ops.set_params(fe)) + return -EIO; + while (i--) { + bool retryov, + lock0, + lock1; + if (!tc90522_r(fe, 0x80, data, 1) || !tc90522_r(fe, 0xB0, data + 1, 1)) + break; + retryov = data[0] & 0b10000000 ? true : false; + lock0 = data[0] & 0b00001000 ? false : true; + lock1 = data[1] & 0b00001000 ? true : false; + if (lock0 && lock1) { +LOCK: + d->stat = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK; + *stat = d->stat; + return 0; + } + if (retryov) + break; + msleep_interruptible(1); + } +ERR: + *stat = d->stat; + return -ETIMEDOUT; +} + +static struct dvb_frontend_ops tc90522_ops = { + .info = { + .name = TC90522_MODNAME, + .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_MULTISTREAM | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO, + .frequency_min = 1, + .frequency_max = 770000000, + }, + .get_frontend_algo = tc90522_get_frontend_algo, + .read_snr = tc90522_cn_raw, + .read_status = tc90522_status, + .tune = tc90522_tune, +}; + +int tc90522_probe(struct i2c_client *c, const struct i2c_device_id *id) +{ + struct tc90522 *d = kzalloc(sizeof(struct tc90522), GFP_KERNEL); + struct dvb_frontend *fe = c->dev.platform_data; + + if (!d) + return -ENOMEM; + d->i2c = c->adapter; + fe->demodulator_priv = d; + i2c_set_clientdata(c, d); + memcpy(&fe->ops, &tc90522_ops, sizeof(struct dvb_frontend_ops)); + fe->ops.delsys[0] = fe->dtv_property_cache.delivery_system; + return 0; +} + +int tc90522_remove(struct i2c_client *c) +{ + kfree(i2c_get_clientdata(c)); + return 0; +} + +static struct i2c_device_id tc90522_id[] = { + {TC90522_MODNAME, 0}, + {}, +}; +MODULE_DEVICE_TABLE(i2c, tc90522_id); + +static struct i2c_driver tc90522_driver = { + .driver = { + .owner = THIS_MODULE, + .name = tc90522_id->name, + }, + .probe = tc90522_probe, + .remove = tc90522_remove, + .id_table = tc90522_id, +}; +module_i2c_driver(tc90522_driver); + +MODULE_AUTHOR("Budi Rachmanto, AreMa Inc. "); +MODULE_DESCRIPTION("Toshiba TC90522 8PSK(ISDB-S)/OFDM(ISDB-T) quad demodulator"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/media/dvb-frontends/tc90522.h b/drivers/media/dvb-frontends/tc90522.h new file mode 100644 index 0000000..b6ee014 --- /dev/null +++ b/drivers/media/dvb-frontends/tc90522.h @@ -0,0 +1,18 @@ +/* + * Toshiba TC90522XBG 2ch OFDM(ISDB-T) + 2ch 8PSK(ISDB-S) demodulator + * + * Copyright (C) Budi Rachmanto, AreMa Inc. + * + * 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. + */ + +#ifndef TC90522_H +#define TC90522_H + +#define TC90522_MODNAME "tc90522" + +#endif +