Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1368563 > unrolled thread

[media 0/8] DVB driver for Earthsoft PT3, PLEX PX-Q3PE ISDB-S/T PCIE cards & PX-BCUD ISDB-S USB dongle

Started byinfo@are.ma
First post2016-03-31 21:20 +0200
Last post2016-03-31 21:50 +0200
Articles 9 — 2 participants

Back to article view | Back to linux.kernel


Contents

  [media 0/8] DVB driver for Earthsoft PT3, PLEX PX-Q3PE ISDB-S/T PCIE cards & PX-BCUD ISDB-S USB dongle info@are.ma - 2016-03-31 21:20 +0200
    [media 1/8] raise adapter number limit info@are.ma - 2016-03-31 21:50 +0200
    [media 2/8] NXP tda2014x & Newport Media nm120/130/131 tuner (PXQ3PE) info@are.ma - 2016-03-31 21:50 +0200
      Re: [media 2/8] NXP tda2014x & Newport Media nm120/130/131 tuner  (PXQ3PE) kbuild test robot <lkp@intel.com> - 2016-04-01 06:10 +0200
      Re: [media 2/8] NXP tda2014x & Newport Media nm120/130/131 tuner  (PXQ3PE) kbuild test robot <lkp@intel.com> - 2016-04-01 06:30 +0200
    [media 8/8] Support for PLEX PX-BCUD (ISDB-S usb dongle) info@are.ma - 2016-03-31 21:50 +0200
    [media 5/8] MaxLinear MxL301RF ISDB-T tuner info@are.ma - 2016-03-31 21:50 +0200
    [media 6/8] Sharp QM1D1C004x ISDB-S tuner driver for PT3 and PX-BCUD info@are.ma - 2016-03-31 21:50 +0200
    [media 4/8] Toshiba TC905xx demodulator for PT3/PX-Q3PE/PX-BCUD info@are.ma - 2016-03-31 21:50 +0200

#1368563 — [media 0/8] DVB driver for Earthsoft PT3, PLEX PX-Q3PE ISDB-S/T PCIE cards & PX-BCUD ISDB-S USB dongle

Frominfo@are.ma
Date2016-03-31 21:20 +0200
Subject[media 0/8] DVB driver for Earthsoft PT3, PLEX PX-Q3PE ISDB-S/T PCIE cards & PX-BCUD ISDB-S USB dongle
Message-ID<riQim-1co-7@gated-at.bofh.it>
From: Буди Романто, AreMa Inc <knightrider@are.ma>

MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
To: linux-media@vger.kernel.org
Cc: 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

DVB driver for Earthsoft PT3, PLEX PX-Q3PE ISDB-S/T PCIE cards & PX-BCUD ISDB-S USB dongle
==========================================================================================

Status: stable

Features:
1. in addition to the real frequency:
	ISDB-S : freq. channel ID
	ISDB-T : freq# (I/O# +128), ch#, ch# +64 for CATV
2. in addition to TSID:
	ISDB-S : slot#

Supported Cards & Main components:
A. EarthSoft PT3:
1. Altera	EP4CGX15BF14C8N	: customized FPGA PCI bridge
2. Toshiba	TC90522XBG	: quad demodulator (2ch OFDM + 2ch 8PSK)
3. Sharp	VA4M6JC2103	: contains 2 ISDB-S + 2 ISDB-T tuners
	ISDB-S : Sharp QM1D1C0042 RF-IC, chip ver. 0x48
	ISDB-T : MaxLinear CMOS Hybrid TV MxL301RF

B. PLEX PX-Q3PE:
1. ASICEN	ASV5220		: PCI-E bridge
2. Toshiba	TC90522XBG	: quad demodulator (2ch OFDM + 2ch 8PSK)
3. NXP Semiconductors TDA20142	: ISDB-S tuner
4. Newport Media NM120		: ISDB-T tuner
5. ASICEN	ASIE5606X8	: crypting controller

C. PLEX PX-BCUD (ISDB-S USB dongle)
1. Empia	EM28178		: USB I/F (courtesy of Nagahama Satoshi)
2. Toshiba	TC90532		: demodulator (using TC90522 driver)
3. Sharp	QM1D1C0045_2	: ISDB-S RF-IC, chip ver. 0x68

Notes:
This is a complex but smartly polished driver package containing 2 (dual head)
PCI-E bridge I/F drivers, single demodulator frontend, and 4 (quad tail) tuner drivers,
plus, simplified Nagahama's patch for PLEX PX-BCUD (ISDB-S USB dongle).
Generic registration related procedures (subdevices, frontend, etc.) summarized in
ptx_common.c are very useful also for other DVB drivers, and would be very handy if
inserted into the core (e.g. dvb_frontend.c & dvb_frontend.h).

For example, currently, the entity of struct dvb_frontend is created sometimes in
demodulators, some in tuners, or even in the parent (bridge) drivers. IMHO, this entity
should be provided by dvb_core. ptx_register_fe() included in ptx_common.c simplifies
the tasks and in fact, significantly reduces coding & kernel size.

Also, currently dvb_frontend's .demodulator_priv & .tuner_priv are of type (void *).
These should be changed to (struct i2c_client *), IMHO. Private data for demodulator
or tuner should be attached under i2c_client, using i2c_set_clientdata() for instance.

FILENAME	SUPPORTED CHIPS
========	===============
tc90522.c	TC90522XBG, TC90532XBG,...
tda2014x.c	TDA20142
qm1d1c004x.c	QM1D1C0042, QM1D1C0045, QM1D1C0045_2
nm131.c		NM131, NM130, NM120
mxl301rf.c	MxL301RF
pt3_pci.c	EP4CGX15BF14C8N
pxq3pe_pci.c	ASV5220

Full package:
- URL:	https://github.com/knight-rider/ptx

Буди Романто, AreMa Inc (8):
  The current limit is too low for latest cards with 8+ tuners on a
    single slot, change to 64.
  NXP tda2014x & Newport Media nm120/130/131 tuner drivers for PLEX
    PX-Q3PE
  Obsoleted & superseded, please read cover letter for details.
  Toshiba TC905xx demodulator driver for PT3, PX-Q3PE & PX-BCUD
  MaxLinear MxL301RF ISDB-T tuner
  Sharp QM1D1C004x ISDB-S tuner driver for PT3 and PX-BCUD
  PCIE bridge driver for PT3 & PX-Q3PE     Please read cover letter for
    details.
  Support for PLEX PX-BCUD (ISDB-S usb dongle)     Nagahama's patch
    simplified...

 drivers/media/dvb-core/dvbdev.h         |   2 +-
 drivers/media/dvb-frontends/tc90522.c   | 965 +++++++-------------------------
 drivers/media/dvb-frontends/tc90522.h   |  36 +-
 drivers/media/pci/Kconfig               |   2 +-
 drivers/media/pci/Makefile              |   2 +-
 drivers/media/pci/pt3/Kconfig           |  10 -
 drivers/media/pci/pt3/Makefile          |   8 -
 drivers/media/pci/pt3/pt3.c             | 874 -----------------------------
 drivers/media/pci/pt3/pt3.h             | 186 ------
 drivers/media/pci/pt3/pt3_dma.c         | 225 --------
 drivers/media/pci/pt3/pt3_i2c.c         | 240 --------
 drivers/media/pci/ptx/Kconfig           |  21 +
 drivers/media/pci/ptx/Makefile          |   8 +
 drivers/media/pci/ptx/pt3_pci.c         | 425 ++++++++++++++
 drivers/media/pci/ptx/ptx_common.c      | 252 +++++++++
 drivers/media/pci/ptx/ptx_common.h      |  74 +++
 drivers/media/pci/ptx/pxq3pe_pci.c      | 585 +++++++++++++++++++
 drivers/media/tuners/Kconfig            |  21 +-
 drivers/media/tuners/Makefile           |   4 +-
 drivers/media/tuners/mxl301rf.c         | 471 ++++++----------
 drivers/media/tuners/mxl301rf.h         |  19 +-
 drivers/media/tuners/nm131.c            | 248 ++++++++
 drivers/media/tuners/nm131.h            |  13 +
 drivers/media/tuners/qm1d1c0042.c       | 448 ---------------
 drivers/media/tuners/qm1d1c0042.h       |  37 --
 drivers/media/tuners/qm1d1c004x.c       | 242 ++++++++
 drivers/media/tuners/qm1d1c004x.h       |  23 +
 drivers/media/tuners/tda2014x.c         | 342 +++++++++++
 drivers/media/tuners/tda2014x.h         |  13 +
 drivers/media/usb/em28xx/Kconfig        |   2 +
 drivers/media/usb/em28xx/em28xx-cards.c |  27 +
 drivers/media/usb/em28xx/em28xx-dvb.c   |  79 ++-
 drivers/media/usb/em28xx/em28xx.h       |   1 +
 33 files changed, 2752 insertions(+), 3153 deletions(-)
 delete mode 100644 drivers/media/pci/pt3/Kconfig
 delete mode 100644 drivers/media/pci/pt3/Makefile
 delete mode 100644 drivers/media/pci/pt3/pt3.c
 delete mode 100644 drivers/media/pci/pt3/pt3.h
 delete mode 100644 drivers/media/pci/pt3/pt3_dma.c
 delete mode 100644 drivers/media/pci/pt3/pt3_i2c.c
 create mode 100644 drivers/media/pci/ptx/Kconfig
 create mode 100644 drivers/media/pci/ptx/Makefile
 create mode 100644 drivers/media/pci/ptx/pt3_pci.c
 create mode 100644 drivers/media/pci/ptx/ptx_common.c
 create mode 100644 drivers/media/pci/ptx/ptx_common.h
 create mode 100644 drivers/media/pci/ptx/pxq3pe_pci.c
 create mode 100644 drivers/media/tuners/nm131.c
 create mode 100644 drivers/media/tuners/nm131.h
 delete mode 100644 drivers/media/tuners/qm1d1c0042.c
 delete mode 100644 drivers/media/tuners/qm1d1c0042.h
 create mode 100644 drivers/media/tuners/qm1d1c004x.c
 create mode 100644 drivers/media/tuners/qm1d1c004x.h
 create mode 100644 drivers/media/tuners/tda2014x.c
 create mode 100644 drivers/media/tuners/tda2014x.h

-- 
2.7.4

[toc] | [next] | [standalone]


#1368576 — [media 1/8] raise adapter number limit

Frominfo@are.ma
Date2016-03-31 21:50 +0200
Subject[media 1/8] raise adapter number limit
Message-ID<riQLo-1p2-3@gated-at.bofh.it>
In reply to#1368563
From: Буди Романто, AreMa Inc <knightrider@are.ma>

The current limit is too low for latest cards with 8+ tuners on a single slot, change to 64.

Signed-off-by: Буди Романто, AreMa Inc <knightrider@are.ma>
---
 drivers/media/dvb-core/dvbdev.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/dvb-core/dvbdev.h b/drivers/media/dvb-core/dvbdev.h
index 4aff7bd..950decd 100644
--- a/drivers/media/dvb-core/dvbdev.h
+++ b/drivers/media/dvb-core/dvbdev.h
@@ -34,7 +34,7 @@
 #if defined(CONFIG_DVB_MAX_ADAPTERS) && CONFIG_DVB_MAX_ADAPTERS > 0
   #define DVB_MAX_ADAPTERS CONFIG_DVB_MAX_ADAPTERS
 #else
-  #define DVB_MAX_ADAPTERS 8
+  #define DVB_MAX_ADAPTERS 64
 #endif
 
 #define DVB_UNSET (-1)
-- 
2.7.4

[toc] | [prev] | [next] | [standalone]


#1368577 — [media 2/8] NXP tda2014x & Newport Media nm120/130/131 tuner (PXQ3PE)

Frominfo@are.ma
Date2016-03-31 21:50 +0200
Subject[media 2/8] NXP tda2014x & Newport Media nm120/130/131 tuner (PXQ3PE)
Message-ID<riQLo-1p2-7@gated-at.bofh.it>
In reply to#1368563
From: Буди Романто, AreMa Inc <knightrider@are.ma>

NXP tda2014x & Newport Media nm120/130/131 tuner drivers for PLEX PX-Q3PE

Signed-off-by: Буди Романто, AreMa Inc <knightrider@are.ma>
---
 drivers/media/tuners/Kconfig    |  21 ++-
 drivers/media/tuners/Makefile   |   4 +-
 drivers/media/tuners/nm131.c    | 248 +++++++++++++++++++++++++++++
 drivers/media/tuners/nm131.h    |  13 ++
 drivers/media/tuners/tda2014x.c | 342 ++++++++++++++++++++++++++++++++++++++++
 drivers/media/tuners/tda2014x.h |  13 ++
 6 files changed, 637 insertions(+), 4 deletions(-)
 create mode 100644 drivers/media/tuners/nm131.c
 create mode 100644 drivers/media/tuners/nm131.h
 create mode 100644 drivers/media/tuners/tda2014x.c
 create mode 100644 drivers/media/tuners/tda2014x.h

diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig
index 05998f0..a7f044b 100644
--- a/drivers/media/tuners/Kconfig
+++ b/drivers/media/tuners/Kconfig
@@ -271,10 +271,25 @@ config MEDIA_TUNER_MXL301RF
 	help
 	  MaxLinear MxL301RF OFDM tuner driver.
 
-config MEDIA_TUNER_QM1D1C0042
-	tristate "Sharp QM1D1C0042 tuner"
+config MEDIA_TUNER_QM1D1C004X
+	tristate "Sharp QM1D1C004x tuner"
 	depends on MEDIA_SUPPORT && I2C
 	default m if !MEDIA_SUBDRV_AUTOSELECT
 	help
-	  Sharp QM1D1C0042 trellis coded 8PSK tuner driver.
+	  Sharp trellis coded 8PSK tuner driver.
+	  Supported chips: QM1D1C0042, QM1D1C0045
+
+config MEDIA_TUNER_NM131
+	tristate "Newport Media tuners NM131, NM130 and NM120"
+	depends on MEDIA_SUPPORT && I2C
+	default m if !MEDIA_SUBDRV_AUTOSELECT
+	help
+	  Newport Media NM131, NM130 and NM120 tuner driver.
+
+config MEDIA_TUNER_TDA2014X
+	tristate "NXP Semiconductors TDA2014x tuner"
+	depends on MEDIA_SUPPORT && I2C
+	default m if !MEDIA_SUBDRV_AUTOSELECT
+	help
+	  NXP Semiconductor TDA2014x tuner driver.
 endmenu
diff --git a/drivers/media/tuners/Makefile b/drivers/media/tuners/Makefile
index 06a9ab6..6a2b52a 100644
--- a/drivers/media/tuners/Makefile
+++ b/drivers/media/tuners/Makefile
@@ -39,8 +39,10 @@ obj-$(CONFIG_MEDIA_TUNER_FC0013) += fc0013.o
 obj-$(CONFIG_MEDIA_TUNER_IT913X) += it913x.o
 obj-$(CONFIG_MEDIA_TUNER_R820T) += r820t.o
 obj-$(CONFIG_MEDIA_TUNER_MXL301RF) += mxl301rf.o
-obj-$(CONFIG_MEDIA_TUNER_QM1D1C0042) += qm1d1c0042.o
+obj-$(CONFIG_MEDIA_TUNER_QM1D1C004X) += qm1d1c004x.o
 obj-$(CONFIG_MEDIA_TUNER_M88RS6000T) += m88rs6000t.o
+obj-$(CONFIG_MEDIA_TUNER_NM131) += nm131.o
+obj-$(CONFIG_MEDIA_TUNER_TDA2014X) += tda2014x.o
 
 ccflags-y += -I$(srctree)/drivers/media/dvb-core
 ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
diff --git a/drivers/media/tuners/nm131.c b/drivers/media/tuners/nm131.c
new file mode 100644
index 0000000..817cf96
--- /dev/null
+++ b/drivers/media/tuners/nm131.c
@@ -0,0 +1,248 @@
+/*
+	Driver for Newport Media tuners NMI131, NMI130 and NMI120
+
+	Copyright (C) Budi Rachmanto, AreMa Inc. <info@are.ma>
+*/
+
+#include "dvb_frontend.h"
+#include "nm131.h"
+
+bool nm131_w(struct dvb_frontend *fe, u16 slvadr, u32 val, u32 sz)
+{
+	struct i2c_client	*d	= fe->demodulator_priv;
+	u8		buf[]	= {0xFE, 0xCE, slvadr >> 8, slvadr & 0xFF, 0, 0, 0, 0};
+	struct i2c_msg	msg[]	= {
+		{.addr = d->addr,	.flags = 0,	.buf = buf,	.len = sz + 4,},
+	};
+
+	*(u32 *)(buf + 4) = slvadr == 0x36 ? val & 0x7F : val;
+	return i2c_transfer(d->adapter, msg, 1) == 1;
+}
+
+bool nm131_w8(struct dvb_frontend *fe, u8 slvadr, u8 dat)
+{
+	struct i2c_client	*d	= fe->demodulator_priv;
+	u8		buf[]	= {slvadr, dat};
+	struct i2c_msg	msg[]	= {
+		{.addr = d->addr,	.flags = 0,	.buf = buf,	.len = 2,},
+	};
+	return i2c_transfer(d->adapter, msg, 1) == 1;
+}
+
+bool nm131_r(struct dvb_frontend *fe, u16 slvadr, u8 *dat, u32 sz)
+{
+	struct i2c_client	*d	= fe->demodulator_priv;
+	u8		rcmd[]	= {0xFE, 0xCF},
+			buf[sz];
+	struct i2c_msg	msg[]	= {
+		{.addr = d->addr,	.flags = 0,		.buf = rcmd,	.len = 2,},
+		{.addr = d->addr,	.flags = I2C_M_RD,	.buf = buf,	.len = sz,},
+	};
+	bool	ret = nm131_w(fe, slvadr, 0, 0) && i2c_transfer(d->adapter, msg, 2) == 2;
+
+	memcpy(dat, buf, sz);
+	return ret;
+}
+
+int nm131_tune(struct dvb_frontend *fe)
+{
+	struct vhf_filter_cutoff_codes_t {
+		u32	Hz;
+		u8	val8_0x08,
+			val8_0x09;
+	} const vhf_filter_cutoff_codes[] = {
+		{45000000, 167, 58},	{55000000, 151, 57},	{65000000, 100, 54},	{75000000, 83, 53},	{85000000, 82, 53},
+		{95000000, 65, 52},	{105000000, 64, 52},	{115000000, 64, 52},	{125000000, 0, 0}
+	};
+	const u8	v45[]		= {0, 1, 2, 3, 4, 6, 9, 12},
+			ACI_audio_lut	= 0,
+			aci_lut		= 1;
+	const u32	lo_freq_lut[]	= {0, 0, 434000000, 237000000, 214000000, 118000000, 79000000, 53000000},
+			*v11,
+			adec_ddfs_fq	= 126217,
+			ddfs_lut	= 0;
+	u8		rf_reg_0x05	= 0x87,
+			v15,
+			val;
+	int		i;
+	u32		tune_rf		= fe->dtv_property_cache.frequency,
+			clk_off_f	= tune_rf,
+			xo		= 24000,
+			lofreq,
+			rf,
+			v14,
+			v32;
+	bool		done		= false;
+
+	if (!(nm131_w8(fe, 1, 0x50)		&&
+		nm131_w8(fe, 0x47, 0x30)	&&
+		nm131_w8(fe, 0x25, 0)		&&
+		nm131_w8(fe, 0x20, 0)		&&
+		nm131_w8(fe, 0x23, 0x4D)))
+		return -EIO;
+	while (1) {
+		rf = clk_off_f;
+		val = rf > 120400000 ? 0x85 : 5;
+		if (rf_reg_0x05 != val) {
+			nm131_w(fe, 0x05, val, 1);
+			rf_reg_0x05 = val;
+		}
+		lofreq = rf;
+		v11 = &lo_freq_lut[6];
+		val = 6;
+		if (lofreq > 53000000) {
+			do {
+				if (*v11 >= lofreq)
+					break;
+				--val;
+				--v11;
+			} while (val != 1);
+		} else
+			val = 7;
+		i = 0;
+		do {
+			if (lofreq > vhf_filter_cutoff_codes[i].Hz && lofreq <= vhf_filter_cutoff_codes[i + 1].Hz)
+				break;
+			++i;
+		} while (i != 8);
+		nm131_w(fe, 8, vhf_filter_cutoff_codes[i].val8_0x08, 1);
+		nm131_w(fe, 9, vhf_filter_cutoff_codes[i].val8_0x09, 1);
+		v14 = lofreq / 1000 * 8 * v45[val];
+		nm131_r(fe, 0x21, &v15, 1);
+		v15 &= 3;
+		xo = v15 == 2 ? xo * 2 : v15 == 3 ? xo >> 1 : xo;
+		v32 = v14 / xo;
+		if (!((v14 % xo * (0x80000000 / xo) >> 12) & 0x7FFFF) || done)
+			break;
+		clk_off_f += 1000;
+		done = true;
+	}
+	xo = (v14 % xo * (0x80000000 / xo) >> 12) & 0x7FFFF;
+	clk_off_f = v14;
+	v14 /= 216000;
+	if (v14 > 31)
+		v14 = 31;
+	if (v14 < 16)
+		v14 = 16;
+	nm131_w(fe, 1, (u16)v32 >> 1, 1);
+	nm131_w(fe, 2, (v32 & 1) | 2 * xo, 1);
+	nm131_w(fe, 3, xo >> 7, 1);
+	nm131_w(fe, 4, (xo >> 15) | 16 * v14, 1);
+	nm131_r(fe, 0x1D, &v15, 1);
+	nm131_w(fe, 0x1D, 32 * val | (v15 & 0x1F), 1);
+	if (lofreq < 300000000) {
+		nm131_w(fe, 0x25, 0x78, 1);
+		nm131_w(fe, 0x27, 0x7F, 1);
+		nm131_w(fe, 0x29, 0x7F, 1);
+		nm131_w(fe, 0x2E, 0x12, 1);
+	} else {
+		nm131_w(fe, 0x25, 0xF4, 1);
+		nm131_w(fe, 0x27, 0xEF, 1);
+		nm131_w(fe, 0x29, 0x4F, 1);
+		nm131_w(fe, 0x2E, 0x34, 1);
+	}
+	nm131_w(fe, 0x36, lofreq < 150000000 ? 0x54 : 0x7C, 1);
+	nm131_w(fe, 0x37, lofreq < 155000000 ? 0x84 : lofreq < 300000000 ? 0x9C : 0x84, 1);
+	clk_off_f = (clk_off_f << 9) / v14 - 110592000;
+
+	nm131_w(fe, 0x164, tune_rf < 300000000 ? 0x600 : 0x500, 4);
+	rf = clk_off_f / 6750 + 16384;
+	nm131_w(fe, 0x230, (adec_ddfs_fq << 15) / rf | 0x80000, 4);
+	nm131_w(fe, 0x250, ACI_audio_lut, 4);
+	nm131_w(fe, 0x27C, 0x1010, 4);
+	nm131_w(fe, 0x1BC, (ddfs_lut << 14) / rf, 4);
+	nm131_r(fe, 0x21C, (u8 *)(&v32), 4);
+	nm131_w(fe, 0x21C, (((v32 & 0xFFC00000) | 524288000 / ((clk_off_f >> 14) + 6750)) & 0xC7BFFFFE) | 0x8000000, 4);
+	nm131_r(fe, 0x234, (u8 *)(&v32), 4);
+	nm131_w(fe, 0x234, v32 & 0xCFC00000, 4);
+	nm131_w(fe, 0x210, ((864 * (clk_off_f >> 5) - 1308983296) / 216000 & 0xFFFFFFF0) | 3, 4);
+	nm131_r(fe, 0x104, (u8 *)(&v32), 4);
+	v32 = ((((clk_off_f > 3686396 ? 2 : clk_off_f >= 1843193 ? 1 : 0) << 16) | (((((((v32 & 0x87FFFFC0) | 0x10000011)
+		& 0xFFFF87FF) | (aci_lut << 11)) & 0xFFFF7FFF) | 0x8000) & 0xFFF0FFFF)) & 0xFC0FFFFF) | 0xA00000;
+	nm131_w(fe, 0x104, v32, 4);
+	v32 = (v32 & 0xFFFFFFEF) | 0x20000020;
+	nm131_w(fe, 0x104, v32, 4);
+	nm131_r(fe, 0x328, (u8 *)(&v14), 4);
+	if (v14) {
+		v32 &= 0xFFFFFFDF;
+		nm131_w(fe, 0x104, v32, 4);
+		nm131_w(fe, 0x104, v32 | 0x20, 4);
+	}
+	return	nm131_w8(fe, 0x23, 0x4C)	&&
+		nm131_w8(fe, 1, 0x50)		&&
+		nm131_w8(fe, 0x71, 1)		&&
+		nm131_w8(fe, 0x72, 0x24)	?
+		0 : -EIO;
+}
+
+int nm131_probe(struct i2c_client *t, const struct i2c_device_id *id)
+{
+	struct tnr_rf_reg_t {
+		u8 slvadr;
+		u8 val;
+	} const
+	tnr_rf_defaults_lut[] = {
+		{6, 72},	{7, 64},	{10, 235},	{11, 17},	{12, 16},	{13, 136},
+		{16, 4},	{17, 48},	{18, 48},	{21, 170},	{22, 3},	{23, 128},
+		{24, 103},	{25, 212},	{26, 68},	{28, 16},	{29, 238},	{30, 153},
+		{33, 197},	{34, 145},	{36, 1},	{43, 145},	{45, 1},	{47, 128},
+		{49, 0},	{51, 0},	{56, 0},	{57, 47},	{58, 0},	{59, 0}
+	},
+	nm120_rf_defaults_lut[] = {
+		{14, 69},	{27, 14},	{35, 255},	{38, 130},	{40, 0},
+		{48, 223},	{50, 223},	{52, 104},	{53, 24}
+	};
+	struct tnr_bb_reg_t {
+		u16 slvadr;
+		u32 val;
+	} const
+	tnr_bb_defaults_lut[2] = {
+		{356, 2048},	{448, 764156359}
+	};
+	u8			i;
+	struct dvb_frontend	*fe	= t->dev.platform_data;
+
+	fe->ops.tuner_ops.set_params	= nm131_tune;
+	if (nm131_w8(fe, 0xB0, 0xA0)		&&
+		nm131_w8(fe, 0xB2, 0x3D)	&&
+		nm131_w8(fe, 0xB3, 0x25)	&&
+		nm131_w8(fe, 0xB4, 0x8B)	&&
+		nm131_w8(fe, 0xB5, 0x4B)	&&
+		nm131_w8(fe, 0xB6, 0x3F)	&&
+		nm131_w8(fe, 0xB7, 0xFF)	&&
+		nm131_w8(fe, 0xB8, 0xC0)	&&
+		nm131_w8(fe, 3, 0)		&&
+		nm131_w8(fe, 0x1D, 0)		&&
+		nm131_w8(fe, 0x1F, 0)) {
+		nm131_w8(fe, 0xE, 0x77);
+		nm131_w8(fe, 0xF, 0x13);
+		nm131_w8(fe, 0x75, 2);
+	}
+	for (i = 0; i < ARRAY_SIZE(tnr_rf_defaults_lut); i++)
+		nm131_w(fe, tnr_rf_defaults_lut[i].slvadr, tnr_rf_defaults_lut[i].val, 1);
+	nm131_r(fe, 0x36, &i, 1);
+	nm131_w(fe, 0x36, i & 0x7F, 1);	/* no LDO bypass */
+	nm131_w(fe, tnr_bb_defaults_lut[0].slvadr, tnr_bb_defaults_lut[0].val, 4);
+	nm131_w(fe, tnr_bb_defaults_lut[1].slvadr, tnr_bb_defaults_lut[1].val, 4);
+	for (i = 0; i < ARRAY_SIZE(nm120_rf_defaults_lut); i++)
+		nm131_w(fe, nm120_rf_defaults_lut[i].slvadr, nm120_rf_defaults_lut[i].val, 1);
+	nm131_w(fe, 0xA, 0xFB, 1);	/* ltgain */
+	return 0;
+}
+
+static struct i2c_device_id nm131_id[] = {
+	{NM131_MODNAME, 0},
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, nm131_id);
+
+static struct i2c_driver nm131_driver = {
+	.driver.name	= nm131_id->name,
+	.probe		= nm131_probe,
+	.id_table	= nm131_id,
+};
+module_i2c_driver(nm131_driver);
+
+MODULE_AUTHOR("Budi Rachmanto, AreMa Inc. <info@are.ma>");
+MODULE_DESCRIPTION("Driver for Newport Media tuners NMI131, NMI130 and NMI120");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/nm131.h b/drivers/media/tuners/nm131.h
new file mode 100644
index 0000000..21f3627
--- /dev/null
+++ b/drivers/media/tuners/nm131.h
@@ -0,0 +1,13 @@
+/*
+ * Driver for Newport Media tuners NMI131, NMI130 and NMI120
+ *
+ * Copyright (C) Budi Rachmanto, AreMa Inc. <info@are.ma>
+ */
+
+#ifndef	NM131_H
+#define	NM131_H
+
+#define NM131_MODNAME "nm131"
+
+#endif
+
diff --git a/drivers/media/tuners/tda2014x.c b/drivers/media/tuners/tda2014x.c
new file mode 100644
index 0000000..bd54efc
--- /dev/null
+++ b/drivers/media/tuners/tda2014x.c
@@ -0,0 +1,342 @@
+/*
+	Driver for NXP Semiconductors tuner TDA2014x
+
+	Copyright (C) Budi Rachmanto, AreMa Inc. <info@are.ma>
+*/
+
+#include "dvb_frontend.h"
+#include "tda2014x.h"
+
+int tda2014x_r(struct dvb_frontend *fe, u8 slvadr)
+{
+	struct i2c_client	*d	= fe->demodulator_priv;
+	u8		buf[]	= {0xFE, 0xA8, slvadr},
+			rcmd[]	= {0xFE, 0xA9},
+			ret	= 0;
+	struct i2c_msg	msg[]	= {
+		{.addr = d->addr,	.flags = 0,		.buf = buf,	.len = 3,},
+		{.addr = d->addr,	.flags = 0,		.buf = rcmd,	.len = 2,},
+		{.addr = d->addr,	.flags = I2C_M_RD,	.buf = &ret,	.len = 1,},
+	};
+	return i2c_transfer(d->adapter, msg, 3) == 3 ? ret : -EIO;
+}
+
+bool tda2014x_r8(struct dvb_frontend *fe, u16 slvadr, u8 start_bit, u8 nbits, u8 *rdat)
+{
+	u8	mask	= nbits > 7 ? 0xFF : ((1 << nbits) - 1) << start_bit;
+	int	val	= tda2014x_r(fe, slvadr);
+
+	if (val < 0)
+		return false;
+	*rdat = (val & mask) >> start_bit;
+	return true;
+}
+
+bool tda2014x_w8(struct dvb_frontend *fe, u8 slvadr, u8 dat)
+{
+	struct i2c_client	*d	= fe->demodulator_priv;
+	u8		buf[]	= {slvadr, dat};
+	struct i2c_msg	msg[]	= {
+		{.addr = d->addr,	.flags = 0,	.buf = buf,	.len = 2,},
+	};
+	return i2c_transfer(d->adapter, msg, 1) == 1;
+}
+
+bool tda2014x_w16(struct dvb_frontend *fe, u16 slvadr, u8 start_bit, u8 nbits, u8 nbytes, bool rmw, u8 access, u16 wdat)
+{
+	struct i2c_client	*d	= fe->demodulator_priv;
+	u16	mask	= nbits > 15 ? 0xFFFF : ((1 << nbits) - 1) << start_bit,
+		val	= mask & (wdat << start_bit);
+	u8	*wval	= (u8 *)&val,
+		i;
+
+	for (i = 0, nbytes = !nbytes ? 1 : nbytes > 2 ? 2 : nbytes; access & 2 && nbytes; i++, nbytes--) {
+		u8	buf[]	= {0xFE, 0xA8, slvadr + i, 0};
+		int	ret	= tda2014x_r(fe, slvadr + i);
+		struct i2c_msg msg[] = {
+			{.addr = d->addr,	.flags = 0,	.buf = buf,	.len = 4,},
+		};
+
+		if (ret < 0)
+			return false;
+		if (rmw)
+			wval[nbytes - 1] |= ~(mask >> 8 * i) & ret;
+		buf[3] = wval[nbytes - 1];
+		if (i2c_transfer(d->adapter, msg, 1) != 1)
+			return false;
+	}
+	return true;
+}
+
+int tda2014x_tune(struct dvb_frontend *fe)
+{
+	enum {
+		TDA2014X_LNA_GAIN_7dB	= 0x0,
+		TDA2014X_LNA_GAIN_10dB	= 0x1,
+		TDA2014X_LNA_GAIN_13dB	= 0x2,		/* default */
+		TDA2014X_LNA_GAIN_18dB	= 0x3,
+		TDA2014X_LNA_GAIN_NEGATIVE_11dB = 0x4,
+
+		TDA2014X_LPT_GAIN_NEGATIVE_8dB	= 0x0,
+		TDA2014X_LPT_GAIN_NEGATIVE_10dB	= 0x1,	/* default */
+		TDA2014X_LPT_GAIN_NEGATIVE_14dB	= 0x2,
+		TDA2014X_LPT_GAIN_NEGATIVE_16dB	= 0x3,
+
+		TDA2014X_AMPOUT_15DB	= 0x0,
+		TDA2014X_AMPOUT_18DB	= 0x1,
+		TDA2014X_AMPOUT_18DB_b	= 0x2,
+		TDA2014X_AMPOUT_21DB	= 0x3,		/* default */
+		TDA2014X_AMPOUT_24DB	= 0x6,		/* ok too */
+		TDA2014X_AMPOUT_27DB	= 0x7,
+		TDA2014X_AMPOUT_30DB	= 0xE,
+		TDA2014X_AMPOUT_33DB	= 0xF,
+	};
+	bool	bDoublerEnable[]		= {false, true, true, true, true},
+		bDcc1Enable[]			= {false, true, true, true, true},
+		bDcc2Enable[]			= {false, true, true, true, true},
+		bPpfEnable[]			= {false, true, true, true, true},
+		bDiv1ConfigInDivideBy3[]	= {false, true, false, true, false},
+		bDiv2ConfigInDivideBy3[]	= {false, true, true, false, false},
+		bSelectDivideBy4Or5Or6Or7Path[]	= {false, true, true, true, true},
+		bSelectDivideBy8Path[]		= {true, false, false, false, false},
+		bInputMuxEnable;
+	u8	PredividerRatio,
+		val;
+	u64	kHz = fe->dtv_property_cache.frequency,
+		ResLsb,
+		Premain,
+		CalcPrecision = 1000000,
+		kint,
+		Nint,
+		R,
+		DsmFracInReg,
+		DsmIntInReg,
+		v15;
+	int	ePllRefClkRatio,
+		i = kHz <= 1075000 ? 0 : kHz <= 1228000 ? 1 : kHz <= 1433000 ? 2 : kHz <= 1720000 ? 3 : 4,
+		lna	= TDA2014X_LNA_GAIN_13dB,
+		gain	= (lna == TDA2014X_LNA_GAIN_18dB) | ((lna & 3) << 4) | (TDA2014X_LPT_GAIN_NEGATIVE_10dB << 1),
+		ampout	= TDA2014X_AMPOUT_21DB;
+
+	/* GetLoConfig */
+	if (!tda2014x_r8(fe, 0x25, 3, 1, &val))
+		return -EIO;
+	bInputMuxEnable = val;
+
+	/* SetLoConfig */
+	if (tda2014x_w16(fe, 0x22, 0, 8, 0, 0, 6,
+		(bDoublerEnable[i] << 7) | (bDcc1Enable[i] << 6) | (bDcc2Enable[i] << 5) | 0b11110 | bPpfEnable[i]) &&
+		tda2014x_r8(fe, 0x23, 0, 8, &val) &&
+		tda2014x_w16(fe, 0x23, 0, 8, 0, 0, 6, (bDiv1ConfigInDivideBy3[i] << 7) | (bDiv2ConfigInDivideBy3[i] << 5) |
+			(bSelectDivideBy4Or5Or6Or7Path[i] << 3) | (bSelectDivideBy8Path[i] << 2) | (val & 0b1010011)))
+		tda2014x_w16(fe, 0x25, 3, 1, 0, 1, 6, bInputMuxEnable);
+
+	ResLsb = (8 - i) * kHz * 1000 / 27;	/* Xtal 27 MHz */
+	kint = ResLsb;
+	v15 = ResLsb / 1000000;
+	R = 1;
+	Premain = 2;
+	Nint = v15 * R / Premain;
+	if (Nint < 131) {
+		Premain = 1;
+		Nint = v15 * R / Premain;
+		if (Nint > 251) {
+			R = 3;
+			Premain = 4;
+			goto LABEL_36;
+		}
+		if (Nint < 131) {
+			R = 3;
+			Premain = 2;
+			goto LABEL_36;
+		}
+	} else if (Nint > 251) {
+		Premain = 4;
+		Nint = v15 * R / Premain;
+		if (Nint > 251) {
+			R = 3;
+			Premain = 4;
+		}
+LABEL_36:
+		Nint = v15 * R / Premain;
+		if (Nint < 131 || Nint > 251)
+			return -ERANGE;
+	}
+	switch (100 * R / Premain) {
+	case 25:
+		kint = ResLsb / 4;
+		break;
+	case 50:
+		kint = ResLsb / 2;
+		break;
+	case 75:
+		kint = ResLsb / 2 + ResLsb / 4;
+		break;
+	case 100:
+		break;
+	case 150:
+		kint = ResLsb / 2 + ResLsb;
+		break;
+	default:
+		return -ERANGE;
+	}
+	kint		= (kint / 10) * 10;
+	ePllRefClkRatio	= R == 2 ? 1 : R == 3 ? 2 : 0;
+	PredividerRatio	= Premain == 2 ? 0 : 1;
+	DsmIntInReg	= kint / 1000000;
+	DsmFracInReg	= kint - 1000000 * DsmIntInReg;
+	for (i = 0; i < 16; i++) {
+		DsmFracInReg *= 2;
+		if (DsmFracInReg > 0xFFFFFFF && i != 15) {
+			DsmFracInReg /= 10;
+			CalcPrecision /= 10;
+		}
+	}
+	return	!(tda2014x_w16(fe, 3, 6, 2, 0, 1, 6, ePllRefClkRatio)	&&
+
+		/* SetPllDividerConfig */
+		tda2014x_w16(fe, 0x1A, 5, 1, 0, 1, 6, PredividerRatio)			&&
+		tda2014x_w16(fe, 0x1E, 0, 8, 0, 0, 6, DsmIntInReg - 128)		&&
+		tda2014x_w16(fe, 0x1F, 0, 0x10, 2, 0, 6, DsmFracInReg / CalcPrecision)	&&
+
+		/* ProgramVcoChannelChange */
+		tda2014x_r8(fe, 0x12, 0, 8, &val)				&&
+		tda2014x_w16(fe, 0x12, 0, 8, 0, 0, 6, (val & 0x7F) | 0x40)	&&
+		tda2014x_w16(fe, 0x13, 0, 2, 0, 1, 6, 2)			&&
+		tda2014x_w16(fe, 0x13, 7, 1, 0, 1, 6, 0)			&&
+		tda2014x_w16(fe, 0x13, 5, 1, 0, 1, 6, 1)			&&
+		tda2014x_w16(fe, 0x13, 5, 1, 0, 1, 6, 1)			&&
+		tda2014x_w16(fe, 0x13, 7, 1, 0, 1, 6, 0)			&&
+		tda2014x_w16(fe, 0x13, 4, 1, 0, 1, 6, 1)			&&
+		((tda2014x_r8(fe, 0x15, 4, 1, &val) && val == 1)		||
+		(tda2014x_r8(fe, 0x15, 4, 1, &val) && val == 1))		&&
+		tda2014x_w16(fe, 0x13, 4, 1, 0, 1, 6, 0)			&&
+		tda2014x_r8(fe, 0x12, 0, 8, &val)				&&
+		tda2014x_w16(fe, 0x12, 0, 8, 0, 0, 6, val & 0x7F)		&&
+
+		/* SetFilterBandwidth */
+		tda2014x_w16(fe, 0xA, 0, 4, 0, 1, 6, 0xA)	&&
+		tda2014x_w16(fe, 0xB, 1, 7, 0, 1, 6, 0x7C)	&&
+
+		/* SetGainConfig */
+		tda2014x_r8(fe, 6, 0, 8, &val)					&&
+		tda2014x_w16(fe, 6, 0, 8, 0, 0, 6, (val & 0x48) | 0x80 | gain)	&&
+		tda2014x_r8(fe, 9, 0, 8, &val)					&&
+		tda2014x_w16(fe, 9, 0, 8, 0, 0, 6, 0b10110000 | (val & 3))	&&
+		tda2014x_w16(fe, 0xA, 5, 3, 0, 1, 6, 3)				&&
+		tda2014x_w16(fe, 0xC, 4, 4, 0, 1, 6, ampout)			&&
+
+		tda2014x_w8(fe, 0xA, 0xFF)	&&
+		tda2014x_w8(fe, 0x10, 0xB2)	&&
+		tda2014x_w8(fe, 0x11, 0)	&&
+		tda2014x_w8(fe, 3, 1)) * -EIO;
+}
+
+int tda2014x_probe(struct i2c_client *c, const struct i2c_device_id *id)
+{
+	u8			val	= 0;
+	struct dvb_frontend	*fe	= c->dev.platform_data;
+
+	fe->ops.tuner_ops.set_params	= tda2014x_tune;
+	fe->dtv_property_cache.frequency = 1318000;
+	return	!(tda2014x_w8(fe, 0x13, 0)	&&
+		tda2014x_w8(fe, 0x15, 0)	&&
+		tda2014x_w8(fe, 0x17, 0)	&&
+		tda2014x_w8(fe, 0x1C, 0)	&&
+		tda2014x_w8(fe, 0x1D, 0)	&&
+		tda2014x_w8(fe, 0x1F, 0)	&&
+		(tda2014x_w8(fe, 7, 0x31), tda2014x_w8(fe, 8, 0x77), tda2014x_w8(fe, 4, 2))	&&
+
+		/* SetPowerMode */
+		tda2014x_r8(fe, 2, 0, 8, &val)					&&
+		tda2014x_w16(fe, 2, 0, 8, 0, 0, 6, val | 0x81)			&&
+		tda2014x_r8(fe, 6, 0, 8, &val)					&&
+		tda2014x_w16(fe, 6, 0, 8, 0, 0, 6, (val | 0x39) & 0x7F)		&&
+		tda2014x_r8(fe, 7, 0, 8, &val)					&&
+		tda2014x_w16(fe, 7, 0, 8, 0, 0, 6, val | 0xAE)			&&
+		tda2014x_r8(fe, 0xF, 0, 8, &val)				&&
+		tda2014x_w16(fe, 0xF, 0, 8, 0, 0, 6, val | 0x80)		&&
+		tda2014x_r8(fe, 0x18, 0, 8, &val)				&&
+		tda2014x_w16(fe, 0x18, 0, 8, 0, 0, 6, val & 0x7F)		&&
+		tda2014x_r8(fe, 0x1A, 0, 8, &val)				&&
+		tda2014x_w16(fe, 0x1A, 0, 8, 0, 0, 6, val | 0xC0)		&&
+		tda2014x_w16(fe, 0x22, 0, 8, 0, 0, 6, 0xFF)			&&
+		tda2014x_r8(fe, 0x23, 0, 8, &val)				&&
+		tda2014x_w16(fe, 0x23, 0, 8, 0, 0, 6, val & 0xFE)		&&
+		tda2014x_r8(fe, 0x25, 0, 8, &val)				&&
+		tda2014x_w16(fe, 0x25, 0, 8, 0, 0, 6, val | 8)			&&
+		tda2014x_r8(fe, 0x27, 0, 8, &val)				&&
+		tda2014x_w16(fe, 0x27, 0, 8, 0, 0, 6, (val | 0xC0) & 0xDF)	&&
+		tda2014x_r8(fe, 0x24, 0, 8, &val)				&&
+		tda2014x_w16(fe, 0x24, 0, 8, 0, 0, 6, (val | 4) & 0xCF)		&&
+		tda2014x_r8(fe, 0xD, 0, 8, &val)				&&
+		tda2014x_w16(fe, 0xD, 0, 8, 0, 0, 6, val & 0xDF)		&&
+		tda2014x_r8(fe, 9, 0, 8, &val)					&&
+		tda2014x_w16(fe, 9, 0, 8, 0, 0, 6, (val | 0xB0) & 0xB1)		&&
+		tda2014x_r8(fe, 0xA, 0, 8, &val)				&&
+		tda2014x_w16(fe, 0xA, 0, 8, 0, 0, 6, (val | 0x6F) & 0x7F)	&&
+		tda2014x_r8(fe, 0xB, 0, 8, &val)				&&
+		tda2014x_w16(fe, 0xB, 0, 8, 0, 0, 6, (val | 0x7A) & 0x7B)	&&
+		tda2014x_w16(fe, 0xC, 0, 8, 0, 0, 6, 0)				&&
+		tda2014x_w16(fe, 0x19, 0, 8, 0, 0, 6, 0xFA)			&&
+		tda2014x_r8(fe, 0x1B, 0, 8, &val)				&&
+		tda2014x_w16(fe, 0x1B, 0, 8, 0, 0, 6, val & 0x7F)		&&
+		tda2014x_r8(fe, 0x21, 0, 8, &val)				&&
+		tda2014x_w16(fe, 0x21, 0, 8, 0, 0, 6, val | 0x40)		&&
+		tda2014x_r8(fe, 0x10, 0, 8, &val)				&&
+		tda2014x_w16(fe, 0x10, 0, 8, 0, 0, 6, (val | 0x90) & 0xBF)	&&
+		tda2014x_r8(fe, 0x14, 0, 8, &val)				&&
+		tda2014x_w16(fe, 0x14, 0, 8, 0, 0, 6, (val | 0x20) & 0xEF)	&&
+
+		/* ProgramPllPor */
+		tda2014x_w16(fe, 0x1A, 6, 1, 0, 1, 6, 1)	&&
+		tda2014x_w16(fe, 0x18, 0, 1, 0, 1, 6, 1)	&&
+		tda2014x_w16(fe, 0x18, 7, 1, 0, 1, 6, 1)	&&
+		tda2014x_w16(fe, 0x1B, 7, 1, 0, 1, 6, 1)	&&
+		tda2014x_w16(fe, 0x18, 0, 1, 0, 1, 6, 0)	&&
+
+		/* ProgramVcoPor */
+		tda2014x_r8(fe, 0xF, 0, 8, &val)						&&
+		(val = (val & 0x1F) | 0x80, tda2014x_w16(fe, 0xF, 0, 8, 0, 0, 6, val))		&&
+		tda2014x_r8(fe, 0x13, 0, 8, &val)						&&
+		(val = (val & 0xFFFFFFCF) | 0x20, tda2014x_w16(fe, 0x13, 0, 8, 0, 0, 6, val))	&&
+		tda2014x_r8(fe, 0x12, 0, 8, &val)				&&
+		(val |= 0xC0, tda2014x_w16(fe, 0x12, 0, 8, 0, 0, 6, val))	&&
+		tda2014x_w16(fe, 0x10, 5, 1, 0, 1, 6, 1)			&&
+		tda2014x_w16(fe, 0x10, 5, 1, 0, 1, 6, 1)			&&
+		tda2014x_w16(fe, 0xF, 5, 1, 0, 1, 6, 1)				&&
+		tda2014x_r8(fe, 0x11, 4, 1, &val)				&&
+		(val || tda2014x_r8(fe, 0x11, 4, 1, &val))			&&
+		(val || tda2014x_r8(fe, 0x11, 4, 1, &val))			&&
+		val								&&
+		tda2014x_r8(fe, 0x10, 0, 4, &val)				&&
+		tda2014x_w16(fe, 0xF, 0, 4, 0, 1, 6, val)			&&
+		tda2014x_w16(fe, 0xF, 6, 1, 0, 1, 6, 1)				&&
+		tda2014x_w16(fe, 0xF, 5, 1, 0, 1, 6, 0)				&&
+		tda2014x_r8(fe, 0x12, 0, 8, &val)				&&
+		(val &= 0x7F, tda2014x_w16(fe, 0x12, 0, 8, 0, 0, 6, val))	&&
+		tda2014x_w16(fe, 0xD, 5, 2, 0, 1, 6, 1)				&&
+
+		/* EnableLoopThrough */
+		tda2014x_r8(fe, 6, 0, 8, &val)					&&
+		tda2014x_w16(fe, 6, 0, 8, 0, 0, 6, (val & 0xF7) | 8)) * -EIO	||
+
+		tda2014x_tune(fe);
+}
+
+static struct i2c_device_id tda2014x_id[] = {
+	{TDA2014X_MODNAME, 0},
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, tda2014x_id);
+
+static struct i2c_driver tda2014x_driver = {
+	.driver.name	= tda2014x_id->name,
+	.probe		= tda2014x_probe,
+	.id_table	= tda2014x_id,
+};
+module_i2c_driver(tda2014x_driver);
+
+MODULE_AUTHOR("Budi Rachmanto, AreMa Inc. <info@are.ma>");
+MODULE_DESCRIPTION("Driver for NXP Semiconductors tuner TDA2014x");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/tda2014x.h b/drivers/media/tuners/tda2014x.h
new file mode 100644
index 0000000..36f8198
--- /dev/null
+++ b/drivers/media/tuners/tda2014x.h
@@ -0,0 +1,13 @@
+/*
+ * Driver for NXP Semiconductors tuner TDA2014x
+ *
+ * Copyright (C) Budi Rachmanto, AreMa Inc. <info@are.ma>
+ */
+
+#ifndef	TDA2014X_H
+#define	TDA2014X_H
+
+#define TDA2014X_MODNAME "tda2014x"
+
+#endif
+
-- 
2.7.4

[toc] | [prev] | [next] | [standalone]


#1368996 — Re: [media 2/8] NXP tda2014x & Newport Media nm120/130/131 tuner (PXQ3PE)

Fromkbuild test robot <lkp@intel.com>
Date2016-04-01 06:10 +0200
SubjectRe: [media 2/8] NXP tda2014x & Newport Media nm120/130/131 tuner (PXQ3PE)
Message-ID<riYzf-7lh-7@gated-at.bofh.it>
In reply to#1368577

[Multipart message — attachments visible in raw view] — view raw

Hi Буди,

[auto build test ERROR on linuxtv-media/master]
[also build test ERROR on v4.6-rc1 next-20160331]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url:    https://github.com/0day-ci/linux/commits/info-are-ma/DVB-driver-for-Earthsoft-PT3-PLEX-PX-Q3PE-ISDB-S-T-PCIE-cards-PX-BCUD-ISDB-S-USB-dongle/20160401-034740
base:   git://linuxtv.org/media_tree.git master
config: x86_64-randconfig-s0-04011126 (attached as .config)
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

Note: the linux-review/info-are-ma/DVB-driver-for-Earthsoft-PT3-PLEX-PX-Q3PE-ISDB-S-T-PCIE-cards-PX-BCUD-ISDB-S-USB-dongle/20160401-034740 HEAD a28878c9675f849df56f4623c33ca431f03e240a builds fine.
      It only hurts bisectibility.

All errors (new ones prefixed by >>):

>> make[4]: *** No rule to make target 'drivers/media/tuners/qm1d1c004x.o', needed by 'drivers/media/tuners/built-in.o'.
   make[4]: Target '__build' not remade because of errors.

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[toc] | [prev] | [next] | [standalone]


#1368998 — Re: [media 2/8] NXP tda2014x & Newport Media nm120/130/131 tuner (PXQ3PE)

Fromkbuild test robot <lkp@intel.com>
Date2016-04-01 06:30 +0200
SubjectRe: [media 2/8] NXP tda2014x & Newport Media nm120/130/131 tuner (PXQ3PE)
Message-ID<riYSB-7wu-3@gated-at.bofh.it>
In reply to#1368577

[Multipart message — attachments visible in raw view] — view raw

Hi Буди,

[auto build test ERROR on linuxtv-media/master]
[also build test ERROR on v4.6-rc1 next-20160331]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url:    https://github.com/0day-ci/linux/commits/info-are-ma/DVB-driver-for-Earthsoft-PT3-PLEX-PX-Q3PE-ISDB-S-T-PCIE-cards-PX-BCUD-ISDB-S-USB-dongle/20160401-034740
base:   git://linuxtv.org/media_tree.git master
config: x86_64-randconfig-s5-04011138 (attached as .config)
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

Note: the linux-review/info-are-ma/DVB-driver-for-Earthsoft-PT3-PLEX-PX-Q3PE-ISDB-S-T-PCIE-cards-PX-BCUD-ISDB-S-USB-dongle/20160401-034740 HEAD a28878c9675f849df56f4623c33ca431f03e240a builds fine.
      It only hurts bisectibility.

All errors (new ones prefixed by >>):

>> make[4]: *** No rule to make target 'drivers/media/tuners/qm1d1c004x.c', needed by 'drivers/media/tuners/qm1d1c004x.o'.
   make[4]: Target '__build' not remade because of errors.

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[toc] | [prev] | [next] | [standalone]


#1368578 — [media 8/8] Support for PLEX PX-BCUD (ISDB-S usb dongle)

Frominfo@are.ma
Date2016-03-31 21:50 +0200
Subject[media 8/8] Support for PLEX PX-BCUD (ISDB-S usb dongle)
Message-ID<riQLo-1p2-11@gated-at.bofh.it>
In reply to#1368563
From: Буди Романто, AreMa Inc <knightrider@are.ma>

Support for PLEX PX-BCUD (ISDB-S usb dongle)
Nagahama's patch simplified...

Signed-off-by: Буди Романто, AreMa Inc <knightrider@are.ma>
---
 drivers/media/usb/em28xx/Kconfig        |  2 +
 drivers/media/usb/em28xx/em28xx-cards.c | 27 +++++++++++
 drivers/media/usb/em28xx/em28xx-dvb.c   | 79 ++++++++++++++++++++++++++++++++-
 drivers/media/usb/em28xx/em28xx.h       |  1 +
 4 files changed, 107 insertions(+), 2 deletions(-)

diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig
index e382210..b138939 100644
--- a/drivers/media/usb/em28xx/Kconfig
+++ b/drivers/media/usb/em28xx/Kconfig
@@ -59,6 +59,8 @@ config VIDEO_EM28XX_DVB
 	select DVB_DRX39XYJ if MEDIA_SUBDRV_AUTOSELECT
 	select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT
 	select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT
+	select DVB_TC90522 if MEDIA_SUBDRV_AUTOSELECT
+	select MEDIA_TUNER_QM1D1C004X if MEDIA_SUBDRV_AUTOSELECT
 	---help---
 	  This adds support for DVB cards based on the
 	  Empiatech em28xx chips.
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 930e3e3..772a8f8 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -492,6 +492,20 @@ static struct em28xx_reg_seq terratec_t2_stick_hd[] = {
 	{-1,                             -1,   -1,     -1},
 };
 
+static struct em28xx_reg_seq plex_px_bcud[] = {
+	{EM2874_R80_GPIO_P0_CTRL,	0xff,	0xff,	0},
+	{0x0d,				0xff,	0xff,	0},
+	{EM2874_R50_IR_CONFIG,		0x01,	0xff,	0},
+	{EM28XX_R06_I2C_CLK,		0x40,	0xff,	0},
+	{EM2874_R80_GPIO_P0_CTRL,	0xfd,	0xff,	100},
+	{EM28XX_R12_VINENABLE,		0x20,	0x20,	0},
+	{0x0d,				0x42,	0xff,	1000},
+	{EM2874_R80_GPIO_P0_CTRL,	0xfc,	0xff,	10},
+	{EM2874_R80_GPIO_P0_CTRL,	0xfd,	0xff,	10},
+	{0x73,				0xfd,	0xff,	100},
+	{-1,				-1,	-1,	-1},
+};
+
 /*
  *  Button definitions
  */
@@ -2306,6 +2320,17 @@ struct em28xx_board em28xx_boards[] = {
 		.has_dvb       = 1,
 		.ir_codes      = RC_MAP_TERRATEC_SLIM_2,
 	},
+	/* 3275:0085 PLEX PX-BCUD.
+	 * Empia EM28178, TOSHIBA TC90532XBG, Sharp QM1D1C0042 */
+	[EM28178_BOARD_PLEX_PX_BCUD] = {
+		.name          = "PLEX PX-BCUD",
+		.xclk          = EM28XX_XCLK_FREQUENCY_4_3MHZ,
+		.def_i2c_bus   = 1,
+		.i2c_speed     = EM28XX_I2C_CLK_WAIT_ENABLE,
+		.tuner_type    = TUNER_ABSENT,
+		.tuner_gpio    = plex_px_bcud,
+		.has_dvb       = 1,
+	},
 };
 EXPORT_SYMBOL_GPL(em28xx_boards);
 
@@ -2495,6 +2520,8 @@ struct usb_device_id em28xx_id_table[] = {
 			.driver_info = EM2861_BOARD_LEADTEK_VC100 },
 	{ USB_DEVICE(0xeb1a, 0x8179),
 			.driver_info = EM28178_BOARD_TERRATEC_T2_STICK_HD },
+	{ USB_DEVICE(0x3275, 0x0085),
+			.driver_info = EM28178_BOARD_PLEX_PX_BCUD },
 	{ },
 };
 MODULE_DEVICE_TABLE(usb, em28xx_id_table);
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index 5d209c7..e6c5a97 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -12,6 +12,10 @@
 
  (c) 2012 Frank Schäfer <fschaefer.oss@googlemail.com>
 
+ (c) 2016 Nagahama Satoshi <sattnag@aim.com>
+	   Budi Rachmanto, AreMa Inc. <info@are.ma>
+	- PLEX PX-BCUD support
+
  Based on cx88-dvb, saa7134-dvb and videobuf-dvb originally written by:
 	(c) 2004, 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
 	(c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
@@ -25,11 +29,10 @@
 #include <linux/slab.h>
 #include <linux/usb.h>
 
+#include "ptx_common.h"
 #include "em28xx.h"
 #include <media/v4l2-common.h>
-#include <dvb_demux.h>
 #include <dvb_net.h>
-#include <dmxdev.h>
 #include <media/tuner.h>
 #include "tuner-simple.h"
 #include <linux/gpio.h>
@@ -787,6 +790,65 @@ static int em28xx_mt352_terratec_xs_init(struct dvb_frontend *fe)
 	return 0;
 }
 
+static void px_bcud_init(struct em28xx *dev)
+{
+	int i;
+	struct {
+		unsigned char r[4];
+		int len;
+	} regs1[] = {
+		{{ 0x0e, 0x77 }, 2},
+		{{ 0x0f, 0x77 }, 2},
+		{{ 0x03, 0x90 }, 2},
+	}, regs2[] = {
+		{{ 0x07, 0x01 }, 2},
+		{{ 0x08, 0x10 }, 2},
+		{{ 0x13, 0x00 }, 2},
+		{{ 0x17, 0x00 }, 2},
+		{{ 0x03, 0x01 }, 2},
+		{{ 0x10, 0xb1 }, 2},
+		{{ 0x11, 0x40 }, 2},
+		{{ 0x85, 0x7a }, 2},
+		{{ 0x87, 0x04 }, 2},
+	};
+	static struct em28xx_reg_seq gpio[] = {
+		{EM28XX_R06_I2C_CLK,		0x40,	0xff,	300},
+		{EM2874_R80_GPIO_P0_CTRL,	0xfd,	0xff,	60},
+		{EM28XX_R15_RGAIN,		0x20,	0xff,	0},
+		{EM28XX_R16_GGAIN,		0x20,	0xff,	0},
+		{EM28XX_R17_BGAIN,		0x20,	0xff,	0},
+		{EM28XX_R18_ROFFSET,		0x00,	0xff,	0},
+		{EM28XX_R19_GOFFSET,		0x00,	0xff,	0},
+		{EM28XX_R1A_BOFFSET,		0x00,	0xff,	0},
+		{EM28XX_R23_UOFFSET,		0x00,	0xff,	0},
+		{EM28XX_R24_VOFFSET,		0x00,	0xff,	0},
+		{EM28XX_R26_COMPR,		0x00,	0xff,	0},
+		{0x13,				0x08,	0xff,	0},
+		{EM28XX_R12_VINENABLE,		0x27,	0xff,	0},
+		{EM28XX_R0C_USBSUSP,		0x10,	0xff,	0},
+		{EM28XX_R27_OUTFMT,		0x00,	0xff,	0},
+		{EM28XX_R10_VINMODE,		0x00,	0xff,	0},
+		{EM28XX_R11_VINCTRL,		0x11,	0xff,	0},
+		{EM2874_R50_IR_CONFIG,		0x01,	0xff,	0},
+		{EM2874_R5F_TS_ENABLE,		0x80,	0xff,	0},
+		{EM28XX_R06_I2C_CLK,		0x46,	0xff,	0},
+	};
+	em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x46);
+	/* sleeping ISDB-T */
+	dev->dvb->i2c_client_demod->addr = 0x14;
+	for (i = 0; i < ARRAY_SIZE(regs1); i++)
+		i2c_master_send(dev->dvb->i2c_client_demod, regs1[i].r, regs1[i].len);
+	/* sleeping ISDB-S */
+	dev->dvb->i2c_client_demod->addr = 0x15;
+	for (i = 0; i < ARRAY_SIZE(regs2); i++)
+		i2c_master_send(dev->dvb->i2c_client_demod, regs2[i].r, regs2[i].len);
+	for (i = 0; i < ARRAY_SIZE(gpio); i++) {
+		em28xx_write_reg_bits(dev, gpio[i].reg, gpio[i].val, gpio[i].mask);
+		if (gpio[i].sleep > 0)
+			msleep(gpio[i].sleep);
+	}
+};
+
 static struct mt352_config terratec_xs_mt352_cfg = {
 	.demod_address = (0x1e >> 1),
 	.no_tuner = 1,
@@ -1762,6 +1824,19 @@ static int em28xx_dvb_init(struct em28xx *dev)
 			dvb->i2c_client_tuner = client;
 		}
 		break;
+	case EM28178_BOARD_PLEX_PX_BCUD:
+		{
+			struct ptx_subdev_info	pxbcud_subdev_info =
+				{SYS_ISDBS, 0x15, TC90522_MODNAME, 0x61, QM1D1C004X_MODNAME};
+
+			dvb->fe[0] = ptx_register_fe(&dev->i2c_adap[dev->def_i2c_bus], NULL, &pxbcud_subdev_info);
+			if (!dvb->fe[0])
+                                goto out_free;
+			dvb->i2c_client_demod = dvb->fe[0]->demodulator_priv;
+                        dvb->i2c_client_tuner = dvb->fe[0]->tuner_priv;
+			px_bcud_init(dev);
+		}
+		break;
 	default:
 		em28xx_errdev("/2: The frontend of your DVB/ATSC card"
 				" isn't supported yet\n");
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 2674449..9ad1240 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -145,6 +145,7 @@
 #define EM2861_BOARD_LEADTEK_VC100                95
 #define EM28178_BOARD_TERRATEC_T2_STICK_HD        96
 #define EM2884_BOARD_ELGATO_EYETV_HYBRID_2008     97
+#define EM28178_BOARD_PLEX_PX_BCUD                98
 
 /* Limits minimum and default number of buffers */
 #define EM28XX_MIN_BUF 4
-- 
2.7.4

[toc] | [prev] | [next] | [standalone]


#1368579 — [media 5/8] MaxLinear MxL301RF ISDB-T tuner

Frominfo@are.ma
Date2016-03-31 21:50 +0200
Subject[media 5/8] MaxLinear MxL301RF ISDB-T tuner
Message-ID<riQLo-1p2-17@gated-at.bofh.it>
In reply to#1368563
From: Буди Романто, AreMa Inc <knightrider@are.ma>

Signed-off-by: Буди Романто, AreMa Inc <knightrider@are.ma>
---
 drivers/media/tuners/mxl301rf.c | 220 ++++++++++++++++++++++++++++++++++++++++
 drivers/media/tuners/mxl301rf.h |  23 +++++
 2 files changed, 243 insertions(+)
 create mode 100644 drivers/media/tuners/mxl301rf.c
 create mode 100644 drivers/media/tuners/mxl301rf.h

diff --git a/drivers/media/tuners/mxl301rf.c b/drivers/media/tuners/mxl301rf.c
new file mode 100644
index 0000000..916b06f
--- /dev/null
+++ b/drivers/media/tuners/mxl301rf.c
@@ -0,0 +1,220 @@
+/*
+	Sharp VA4M6JC2103 - Earthsoft PT3 ISDB-T tuner MaxLinear CMOS Hybrid TV MxL301RF
+
+	Copyright (C) Budi Rachmanto, AreMa Inc. <info@are.ma>
+
+	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 "dvb_frontend.h"
+#include "mxl301rf.h"
+
+int mxl301rf_w(struct dvb_frontend *fe, u8 slvadr, const u8 *dat, int len)
+{
+	struct i2c_client	*d	= fe->demodulator_priv;
+	u8			buf[len + 1];
+	struct i2c_msg		msg[] = {
+		{.addr = d->addr,	.flags = 0,	.buf = buf,	.len = len + 1,},
+	};
+
+	buf[0] = slvadr;
+	memcpy(buf + 1, dat, len);
+	return i2c_transfer(d->adapter, msg, 1) == 1 ? 0 : -EIO;
+}
+
+int mxl301rf_w_tuner(struct dvb_frontend *fe, const u8 *dat, int len)
+{
+	u8 buf[len + 1];
+
+	buf[0] = ((struct i2c_client *)fe->tuner_priv)->addr << 1;
+	memcpy(buf + 1, dat, len);
+	return mxl301rf_w(fe, 0xFE, buf, len + 1);
+}
+
+u8 mxl301rf_r(struct dvb_frontend *fe, u8 regadr)
+{
+	struct i2c_client	*d	= fe->demodulator_priv,
+				*t	= fe->tuner_priv;
+	u8	wbuf[]	= {0xFB, regadr},
+		rbuf[]	= {0xFE, (t->addr << 1) | 1, 0};
+	struct i2c_msg msg[] = {
+		{.addr	= d->addr,	.flags	= 0,		.buf	= rbuf,		.len	= 2,},
+		{.addr	= d->addr,	.flags	= I2C_M_RD,	.buf	= rbuf + 2,	.len	= 1,},
+	};
+	mxl301rf_w_tuner(fe, wbuf, sizeof(wbuf));
+	return t->addr && (i2c_transfer(d->adapter, msg, 2) == 2) ? rbuf[2] : 0;
+}
+
+enum mxl301rf_agc {
+	MXL301RF_AGC_AUTO,
+	MXL301RF_AGC_MANUAL,
+};
+
+int mxl301rf_set_agc(struct dvb_frontend *fe, enum mxl301rf_agc agc)
+{
+	u8	dat	= agc == MXL301RF_AGC_AUTO ? 0x40 : 0x00,
+		imsrst	= 0x01 << 6;
+	int	err	= mxl301rf_w(fe, 0x25, &dat, 1);
+
+	dat = 0x4c | (agc == MXL301RF_AGC_AUTO ? 0 : 1);
+	return	err				||
+		mxl301rf_w(fe, 0x23, &dat, 1)	||
+		mxl301rf_w(fe, 0x01, &imsrst, 1);
+}
+
+int mxl301rf_sleep(struct dvb_frontend *fe)
+{
+	u8	buf	= (1 << 7) | (1 << 4),
+		dat[]	= {0x01, 0x00, 0x13, 0x00};
+	int	err	= mxl301rf_set_agc(fe, MXL301RF_AGC_MANUAL);
+
+	if (err)
+		return err;
+	mxl301rf_w_tuner(fe, dat, sizeof(dat));
+	return mxl301rf_w(fe, 0x03, &buf, 1);
+}
+
+int mxl301rf_tune(struct dvb_frontend *fe)
+{
+	struct shf_dvbt {
+		u32	freq,		/* Channel center frequency @ kHz	*/
+			freq_th;	/* Offset frequency threshold @ kHz	*/
+		u8	shf_val,	/* Spur shift value			*/
+			shf_dir;	/* Spur shift direction			*/
+	} shf_dvbt_tab[] = {
+		{ 64500, 500, 0x92, 0x07},
+		{191500, 300, 0xe2, 0x07},
+		{205500, 500, 0x2c, 0x04},
+		{212500, 500, 0x1e, 0x04},
+		{226500, 500, 0xd4, 0x07},
+		{ 99143, 500, 0x9c, 0x07},
+		{173143, 500, 0xd4, 0x07},
+		{191143, 300, 0xd4, 0x07},
+		{207143, 500, 0xce, 0x07},
+		{225143, 500, 0xce, 0x07},
+		{243143, 500, 0xd4, 0x07},
+		{261143, 500, 0xd4, 0x07},
+		{291143, 500, 0xd4, 0x07},
+		{339143, 500, 0x2c, 0x04},
+		{117143, 500, 0x7a, 0x07},
+		{135143, 300, 0x7a, 0x07},
+		{153143, 500, 0x01, 0x07}
+	};
+	u8 rf_dat[] = {
+		0x13, 0x00,	/* abort tune		*/
+		0x3b, 0xc0,
+		0x3b, 0x80,
+		0x10, 0x95,	/* BW			*/
+		0x1a, 0x05,
+		0x61, 0x00,
+		0x62, 0xa0,
+		0x11, 0x40,	/* 2 bytes to store RF	*/
+		0x12, 0x0e,	/* 2 bytes to store RF	*/
+		0x13, 0x01	/* start tune		*/
+	};
+	const u8 idac[] = {
+		0x0d, 0x00,
+		0x0c, 0x67,
+		0x6f, 0x89,
+		0x70, 0x0c,
+		0x6f, 0x8a,
+		0x70, 0x0e,
+		0x6f, 0x8b,
+		0x70, 0x10+12,
+	};
+	u8	dat[20];
+	int	err	= mxl301rf_set_agc(fe, MXL301RF_AGC_MANUAL);
+	u32	freq	= fe->dtv_property_cache.frequency,
+		kHz	= 1000,
+		MHz	= 1000000,
+		dig_rf	= freq / MHz,
+		tmp	= freq % MHz,
+		i,
+		fdiv	= 1000000;
+	unsigned long timeout;
+
+	if (err)
+		return err;
+	for (i = 0; i < 6; i++) {
+		dig_rf <<= 1;
+		fdiv /= 2;
+		if (tmp > fdiv) {
+			tmp -= fdiv;
+			dig_rf++;
+		}
+	}
+	if (tmp > 7812)
+		dig_rf++;
+	rf_dat[2 * 7 + 1]	= (u8)(dig_rf);
+	rf_dat[2 * 8 + 1]	= (u8)(dig_rf >> 8);
+	for (i = 0; i < ARRAY_SIZE(shf_dvbt_tab); i++) {
+		if ((freq >= (shf_dvbt_tab[i].freq - shf_dvbt_tab[i].freq_th) * kHz) &&
+				(freq <= (shf_dvbt_tab[i].freq + shf_dvbt_tab[i].freq_th) * kHz)) {
+			rf_dat[2 * 5 + 1] = shf_dvbt_tab[i].shf_val;
+			rf_dat[2 * 6 + 1] = 0xa0 | shf_dvbt_tab[i].shf_dir;
+			break;
+		}
+	}
+	memcpy(dat, rf_dat, sizeof(rf_dat));
+
+	mxl301rf_w_tuner(fe, dat, 14);
+	msleep_interruptible(1);
+	mxl301rf_w_tuner(fe, dat + 14, 6);
+	msleep_interruptible(1);
+	dat[0] = 0x1a;
+	dat[1] = 0x0d;
+	mxl301rf_w_tuner(fe, dat, 2);
+	mxl301rf_w_tuner(fe, idac, sizeof(idac));
+	timeout = jiffies + msecs_to_jiffies(100);
+	while (time_before(jiffies, timeout)) {
+		if ((mxl301rf_r(fe, 0x16) & 0x0c) == 0x0c && (mxl301rf_r(fe, 0x16) & 0x03) == 0x03)
+			return mxl301rf_set_agc(fe, MXL301RF_AGC_AUTO);
+		msleep_interruptible(1);
+	}
+	return -ETIMEDOUT;
+}
+
+int mxl301rf_wakeup(struct dvb_frontend *fe)
+{
+	u8	buf	= (1 << 7) | (0 << 4),
+		dat[2]	= {0x01, 0x01};
+	int	err	= mxl301rf_w(fe, 0x03, &buf, 1);
+
+	if (err)
+		return err;
+	mxl301rf_w_tuner(fe, dat, sizeof(dat));
+	return 0;
+}
+
+int mxl301rf_probe(struct i2c_client *t, const struct i2c_device_id *id)
+{
+	struct dvb_frontend	*fe	= t->dev.platform_data;
+	u8			d[]	= {0x10, 0x01};
+
+	fe->ops.tuner_ops.set_params	= mxl301rf_tune;
+	fe->ops.tuner_ops.sleep		= mxl301rf_sleep;
+	fe->ops.tuner_ops.init		= mxl301rf_wakeup;
+	return	mxl301rf_w(fe, 0x1c, d, 1)	||
+		mxl301rf_w(fe, 0x1d, d+1, 1);
+}
+
+static struct i2c_device_id mxl301rf_id[] = {
+	{MXL301RF_MODNAME, 0},
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, mxl301rf_id);
+
+static struct i2c_driver mxl301rf_driver = {
+	.driver.name	= mxl301rf_id->name,
+	.probe		= mxl301rf_probe,
+	.id_table	= mxl301rf_id,
+};
+module_i2c_driver(mxl301rf_driver);
+
+MODULE_AUTHOR("Budi Rachmanto, AreMa Inc. <knightrider(@)are.ma>");
+MODULE_DESCRIPTION("Earthsoft PT3 MxL301RF MaxLinear CMOS Hybrid TV ISDB-T tuner driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/media/tuners/mxl301rf.h b/drivers/media/tuners/mxl301rf.h
new file mode 100644
index 0000000..32a31b0
--- /dev/null
+++ b/drivers/media/tuners/mxl301rf.h
@@ -0,0 +1,23 @@
+/*
+ * Sharp VA4M6JC2103 - Earthsoft PT3 ISDB-T tuner MaxLinear CMOS Hybrid TV MxL301RF
+ *
+ * Copyright (C) 2014 Budi Rachmanto, AreMa Inc. <info@are.ma>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 MXL301RF_H
+#define MXL301RF_H
+
+#define MXL301RF_MODNAME "mxl301rf"
+
+#endif
+
-- 
2.7.4

[toc] | [prev] | [next] | [standalone]


#1368581 — [media 6/8] Sharp QM1D1C004x ISDB-S tuner driver for PT3 and PX-BCUD

Frominfo@are.ma
Date2016-03-31 21:50 +0200
Subject[media 6/8] Sharp QM1D1C004x ISDB-S tuner driver for PT3 and PX-BCUD
Message-ID<riQLp-1p2-25@gated-at.bofh.it>
In reply to#1368563
From: Буди Романто, AreMa Inc <knightrider@are.ma>

Signed-off-by: Буди Романто, AreMa Inc <knightrider@are.ma>
---
 drivers/media/tuners/qm1d1c004x.c | 242 ++++++++++++++++++++++++++++++++++++++
 drivers/media/tuners/qm1d1c004x.h |  23 ++++
 2 files changed, 265 insertions(+)
 create mode 100644 drivers/media/tuners/qm1d1c004x.c
 create mode 100644 drivers/media/tuners/qm1d1c004x.h

diff --git a/drivers/media/tuners/qm1d1c004x.c b/drivers/media/tuners/qm1d1c004x.c
new file mode 100644
index 0000000..843cfb2
--- /dev/null
+++ b/drivers/media/tuners/qm1d1c004x.c
@@ -0,0 +1,242 @@
+/*
+	Sharp VA4M6JC2103 QM1D1C004x ISDB-S tuner driver
+
+	Copyright (C) Budi Rachmanto, AreMa Inc. <info@are.ma>
+
+	CHIP		VER.	CARD
+	QM1D1C0042	0x48	Earthsoft PT3
+	QM1D1C0045	0x58
+	QM1D1C0045_2	0x68	PLEX PX-BCUD
+
+	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 "dvb_frontend.h"
+#include "qm1d1c004x.h"
+
+struct qm1d1c004x {
+	u8 reg[32];
+};
+
+bool qm1d1c004x_r(struct dvb_frontend *fe, u8 slvadr, u8 *dat)
+{
+	struct i2c_client	*d	= fe->demodulator_priv,
+				*t	= fe->tuner_priv;
+	u8		buf[]	= {0xFE, t->addr << 1, slvadr, 0xFE, (t->addr << 1) | 1, 0};
+	struct i2c_msg	msg[]	= {
+		{.addr = d->addr,	.flags = 0,		.buf = buf,	.len = 3,},
+		{.addr = d->addr,	.flags = 0,		.buf = buf + 3,	.len = 2,},
+		{.addr = d->addr,	.flags = I2C_M_RD,	.buf = buf + 5,	.len = 1,},
+	};
+	bool	ret = i2c_transfer(d->adapter, msg, 3) == 3;
+
+	*dat = buf[5];
+	return ret;
+}
+
+int qm1d1c004x_w(struct dvb_frontend *fe, u8 slvadr, u8 *dat, int len)
+{
+	struct i2c_client	*d	= fe->demodulator_priv;
+	u8		buf[len + 1];
+	struct i2c_msg	msg[] = {
+		{.addr = d->addr,	.flags = 0,	.buf = buf,	.len = len + 1,},
+	};
+
+	buf[0] = slvadr;
+	memcpy(buf + 1, dat, len);
+	return i2c_transfer(d->adapter, msg, 1) == 1 ? 0 : -EIO;
+}
+
+int qm1d1c004x_w_tuner(struct dvb_frontend *fe, u8 adr, u8 dat)
+{
+	struct i2c_client	*t	= fe->tuner_priv;
+	struct qm1d1c004x	*q	= i2c_get_clientdata(t);
+	u8			buf[]	= {t->addr << 1, adr, dat};
+	int			err	= qm1d1c004x_w(fe, 0xFE, buf, 3);
+
+	q->reg[adr] = dat;
+	return err;
+}
+
+enum qm1d1c004x_agc {
+	QM1D1C004X_AGC_AUTO,
+	QM1D1C004X_AGC_MANUAL,
+};
+
+int qm1d1c004x_set_agc(struct dvb_frontend *fe, enum qm1d1c004x_agc agc)
+{
+	u8	dat		= (agc == QM1D1C004X_AGC_AUTO) ? 0xff : 0x00,
+		pskmsrst	= 0x01;
+	int	err		= qm1d1c004x_w(fe, 0x0a, &dat, 1);
+
+	if (err)
+		return err;
+	dat = 0xb0 | (agc == QM1D1C004X_AGC_AUTO ? 1 : 0);
+	err = qm1d1c004x_w(fe, 0x10, &dat, 1);
+	if (err)
+		return err;
+	dat = (agc == QM1D1C004X_AGC_AUTO) ? 0x40 : 0x00;
+	return	(err = qm1d1c004x_w(fe, 0x11, &dat, 1)) ?
+		err : qm1d1c004x_w(fe, 0x03, &pskmsrst, 1);
+}
+
+int qm1d1c004x_sleep(struct dvb_frontend *fe)
+{
+	u8	buf	= 1,
+		*reg	= ((struct qm1d1c004x *)fe->tuner_priv)->reg;
+
+	reg[0x01] &= (~(1 << 3)) & 0xff;
+	reg[0x01] |= 1 << 0;
+	reg[0x05] |= 1 << 3;
+	return	qm1d1c004x_set_agc(fe, QM1D1C004X_AGC_MANUAL)	||
+		qm1d1c004x_w_tuner(fe, 0x05, reg[0x05])		||
+		qm1d1c004x_w_tuner(fe, 0x01, reg[0x01])		||
+		qm1d1c004x_w(fe, 0x17, &buf, 1);
+}
+
+int qm1d1c004x_wakeup(struct dvb_frontend *fe)
+{
+	u8	regs[][32] = {
+			{	/* QM1D1C0042	Earthsoft PT3	*/
+			0x48, 0x1c, 0xa0, 0x10, 0xbc, 0xc5, 0x20, 0x33,	0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+			0x00, 0xff, 0xf3, 0x00, 0x2a, 0x64, 0xa6, 0x86,	0x8c, 0xcf, 0xb8, 0xf1, 0xa8, 0xf2, 0x89, 0x00,
+			}, {	/* QM1D1C0045	untested!	*/
+			0x58, 0x1C, 0xC0, 0x10, 0xBC, 0xC1, 0x15, 0x34, 0x06, 0x3e, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00,
+			0x11, 0xFF, 0xF3, 0x00, 0x3E, 0x25, 0x5C, 0xD6, 0x55, 0x8F, 0x95, 0xF6, 0x36, 0xF2, 0x09, 0x00,
+			}, {	/* QM1D1C0045_2	PLEX PX-BCUD	*/
+			0x68, 0x1c, 0xc0, 0x10, 0xbc, 0xc1, 0x11, 0x33,	0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+			0x00, 0xff, 0xf3, 0x00, 0x3f, 0x25, 0x5c, 0xd6,	0x55, 0xcf, 0x95, 0xf6, 0x36, 0xf2, 0x09, 0x00,
+			}
+		},
+		*reg	= ((struct qm1d1c004x *)i2c_get_clientdata(fe->tuner_priv))->reg,
+		dat	= 0,
+		i;
+
+	for (i = 0; i < ARRAY_SIZE(regs); i++) {
+		if (!qm1d1c004x_r(fe, 0, &dat))
+			return -EIO;
+		if (dat == regs[i][0])
+			break;
+	}
+	if (i == ARRAY_SIZE(regs))
+		return -ENOTSUPP;
+	memcpy(reg, regs[i], 32);
+	reg[0x01] |= 1 << 3;
+	reg[0x01] &= (~(1 << 0)) & 0xff;
+	reg[0x05] &= (~(1 << 3)) & 0xff;
+	dat = 0;
+	return	qm1d1c004x_w(fe, 0x17, &dat, 1)		||
+		qm1d1c004x_w_tuner(fe, 0x01, reg[0x01])	||
+		qm1d1c004x_w_tuner(fe, 0x05, reg[0x05]);
+}
+
+int qm1d1c004x_tune(struct dvb_frontend *fe)
+{
+	u32	fgap_tab[9][3]	= {
+		{2151000, 1, 7},	{1950000, 1, 6},	{1800000, 1, 5},
+		{1600000, 1, 4},	{1450000, 1, 3},	{1250000, 1, 2},
+		{1200000, 0, 7},	{ 975000, 0, 6},	{ 950000, 0, 0}
+	};
+	u8	*reg	= ((struct qm1d1c004x *)fe->tuner_priv)->reg;
+	u32	kHz	= fe->dtv_property_cache.frequency - 500,
+		XtalkHz	= 16000,
+		i	= ((kHz + XtalkHz / 2) / XtalkHz) * XtalkHz;
+	s64	b	= kHz - i;
+	u8	N	= i / (4 * XtalkHz) - 3,
+		A	= (i / XtalkHz) - 4 * (N + 1) - 5;
+	int	sd	= b < 0 ? (0x100000 / XtalkHz) * b + 0x400000 : (0x100000 / XtalkHz) * b,
+		err	= qm1d1c004x_set_agc(fe, QM1D1C004X_AGC_MANUAL);
+
+	if (err)
+		return -EIO;
+
+	/* div2/vco_band */
+	for (i = 0; i < 8; i++)
+		if ((fgap_tab[i+1][0] <= kHz) && (kHz < fgap_tab[i][0]))
+			qm1d1c004x_w_tuner(fe, 0x02, (reg[0x02] & 0x0f) | fgap_tab[i][1] << 7 | fgap_tab[i][2] << 4);
+
+	reg[0x06] &= 0x40;
+	reg[0x06] |= N;
+	reg[0x07] &= 0xf0;
+	reg[0x07] |= A & 0x0f;
+
+	/* LPF */
+	reg[0x08] &= 0xf0;
+	reg[0x08] |= 0x09;
+	reg[0x13] &= 0x9f;
+	reg[0x13] |= 0x20;
+	err =	qm1d1c004x_w_tuner(fe, 0x06, reg[0x06])	||
+		qm1d1c004x_w_tuner(fe, 0x07, reg[0x07])	||
+		qm1d1c004x_w_tuner(fe, 0x08, (reg[0x08] & 0xf0) | 2);
+	if (err)
+		return err;
+	reg[0x09] &= 0xc0;
+	reg[0x09] |= (sd >> 16) & 0x3f;
+	reg[0x0a] = (sd >> 8) & 0xff;
+	reg[0x0b] = (sd >> 0) & 0xff;
+	err =	qm1d1c004x_w_tuner(fe, 0x09, reg[0x09])	||
+		qm1d1c004x_w_tuner(fe, 0x0a, reg[0x0a])	||
+		qm1d1c004x_w_tuner(fe, 0x0b, reg[0x0b])	||
+		qm1d1c004x_w_tuner(fe, 0x0c, reg[0x0c] & 0x3f);
+	if (err)
+		return err;
+	msleep_interruptible(1);
+	err =	qm1d1c004x_w_tuner(fe, 0x0c, reg[0x0c] | 0xc0)	||
+		qm1d1c004x_w_tuner(fe, 0x08, 0x09)		||
+		qm1d1c004x_w_tuner(fe, 0x13, reg[0x13]);
+	if (err)
+		return err;
+	for (i = 0; i < 500; i++) {
+		if (!qm1d1c004x_r(fe, 0x0d, &reg[0x0d]))
+			return -EIO;
+		if (reg[0x0d] & 0x40)	/* locked */
+			return qm1d1c004x_set_agc(fe, QM1D1C004X_AGC_AUTO);
+		msleep_interruptible(1);
+	}
+	return -ETIMEDOUT;
+}
+
+int qm1d1c004x_remove(struct i2c_client *t)
+{
+	kfree(i2c_get_clientdata(t));
+	return 0;
+}
+
+int qm1d1c004x_probe(struct i2c_client *t, const struct i2c_device_id *id)
+{
+	struct dvb_frontend	*fe	= t->dev.platform_data;
+	struct qm1d1c004x	*q	= kzalloc(sizeof(struct qm1d1c004x), GFP_KERNEL);
+	u8			d[]	= {0x10, 0x15, 0x04};
+
+	if (!q)
+		return -ENOMEM;
+	i2c_set_clientdata(t, q);
+	fe->ops.tuner_ops.set_params	= qm1d1c004x_tune;
+	fe->ops.tuner_ops.sleep		= qm1d1c004x_sleep;
+	fe->ops.tuner_ops.init		= qm1d1c004x_wakeup;
+	return	qm1d1c004x_w(fe, 0x1e, d,   1)	||
+		qm1d1c004x_w(fe, 0x1c, d+1, 1)	||
+		qm1d1c004x_w(fe, 0x1f, d+2, 1);
+}
+
+static struct i2c_device_id qm1d1c004x_id[] = {
+	{QM1D1C004X_MODNAME, 0},
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, qm1d1c004x_id);
+
+static struct i2c_driver qm1d1c004x_driver = {
+	.driver.name	= qm1d1c004x_id->name,
+	.probe		= qm1d1c004x_probe,
+	.remove		= qm1d1c004x_remove,
+	.id_table	= qm1d1c004x_id,
+};
+module_i2c_driver(qm1d1c004x_driver);
+
+MODULE_AUTHOR("Budi Rachmanto, AreMa Inc. <knightrider(@)are.ma>");
+MODULE_DESCRIPTION("Earthsoft PT3 QM1D1C004X ISDB-S tuner driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/media/tuners/qm1d1c004x.h b/drivers/media/tuners/qm1d1c004x.h
new file mode 100644
index 0000000..2fdf9cb
--- /dev/null
+++ b/drivers/media/tuners/qm1d1c004x.h
@@ -0,0 +1,23 @@
+/*
+	Sharp VA4M6JC2103 QM1D1C004x ISDB-S tuner driver
+
+	Copyright (C) Budi Rachmanto, AreMa Inc. <info@are.ma>
+
+	CHIP		VER.	CARD
+	QM1D1C0042	0x48	Earthsoft PT3
+	QM1D1C0045	0x58
+	QM1D1C0045_2	0x68	PLEX PX-BCUD
+
+	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 QM1D1C004X_H
+#define QM1D1C004X_H
+
+#define QM1D1C004X_MODNAME "qm1d1c004x"
+
+#endif
+
-- 
2.7.4

[toc] | [prev] | [next] | [standalone]


#1368582 — [media 4/8] Toshiba TC905xx demodulator for PT3/PX-Q3PE/PX-BCUD

Frominfo@are.ma
Date2016-03-31 21:50 +0200
Subject[media 4/8] Toshiba TC905xx demodulator for PT3/PX-Q3PE/PX-BCUD
Message-ID<riQLo-1p2-21@gated-at.bofh.it>
In reply to#1368563
From: Буди Романто, AreMa Inc <knightrider@are.ma>

Toshiba TC905xx demodulator driver for PT3, PX-Q3PE & PX-BCUD

Signed-off-by: Буди Романто, AreMa Inc <knightrider@are.ma>
---
 drivers/media/dvb-frontends/tc90522.c | 255 ++++++++++++++++++++++++++++++++++
 drivers/media/dvb-frontends/tc90522.h |  18 +++
 2 files changed, 273 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..97007ec
--- /dev/null
+++ b/drivers/media/dvb-frontends/tc90522.c
@@ -0,0 +1,255 @@
+/*
+	Toshiba TC90522XBG 2ch OFDM(ISDB-T) + 2ch 8PSK(ISDB-S) demodulator
+
+	Copyright (C) Budi Rachmanto, AreMa Inc. <info@are.ma>
+
+	CHIP		CARDS
+	TC90522XBG	Earthsoft PT3, PLEX PX-Q3PE
+	TC90532		PLEX PX-BCUD
+
+	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 <linux/pci.h>
+#include "dvb_math.h"
+#include "dvb_frontend.h"
+#include "tc90522.h"
+
+bool tc90522_r(struct i2c_client *d, u8 slvadr, u8 *buf, u8 len)
+{
+	struct i2c_msg msg[] = {
+		{.addr = d->addr,	.flags = 0,		.buf = &slvadr,	.len = 1,},
+		{.addr = d->addr,	.flags = I2C_M_RD,	.buf = buf,	.len = len,},
+	};
+	return i2c_transfer(d->adapter, msg, 2) == 2;
+}
+
+bool tc90522_w(struct i2c_client *d, u8 slvadr, u8 dat)
+{
+	u8 buf[] = {slvadr, dat};
+	struct i2c_msg msg[] = {
+		{.addr = d->addr,	.flags = 0,	.buf = buf,	.len = 2,},
+	};
+	return i2c_transfer(d->adapter, 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 <arpa/inet.h>'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->demodulator_priv, 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)
+{
+	enum fe_status			*festat	= i2c_get_clientdata(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 = *festat;
+	return *festat;
+}
+
+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)
+	{
+		if (fno < 12)
+			return 1049480 + 38360 * fno;		/* BS		*/
+		else if (fno < 24)
+			return 1613000 + 40000 * (fno - 12);	/* CS110 right	*/
+		return 1593000 + 40000 * (fno - 24);		/* CS110 left	*/
+	}
+
+	void s_kHz(u32 *f)
+	{
+		*f =	*f > 3000000 ? fno2kHz(14)	:	/* max kHz, CNN	*/
+			*f >= 1049480 ? *f		:	/* min real kHz	*/
+			*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 i2c_client	*d	= fe->demodulator_priv;
+	enum fe_status		*festat	= i2c_get_clientdata(d);
+	u16			set_id	= fe->dtv_property_cache.stream_id,
+				i	= 999;
+	u8			data[16];
+
+	if (!retune)		/* once is enough */
+		return 0;
+	*festat = 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(d, 0xC3, data, 1), !(data[0] & 0x10))	&&	/* locked	*/
+			(tc90522_r(d, 0xCE, data, 2), *(u16 *)data != 0)	&&	/* valid TSID	*/
+			tc90522_r(d, 0xC3, data, 1)				&&
+			tc90522_r(d, 0xCE, data, 16))
+			break;
+		msleep_interruptible(5);
+	}
+	if (!i)
+		goto ERR;
+	for (i = 0; i < 8; i++) {
+		u16 tsid = tc90522_n2int(data + i*2, 2);
+
+		if ((tsid == set_id || set_id == i)	&&
+			tc90522_w(d, 0x8F, tsid >> 8)	&&
+			tc90522_w(d, 0x90, tsid & 0xFF)	&&
+			tc90522_r(d, 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(d, 0x80, data, 1) || !tc90522_r(d, 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:
+			*festat = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK;
+			*stat = *festat;
+			return 0;
+		}
+		if (retryov)
+			break;
+		msleep_interruptible(1);
+	}
+ERR:
+	*stat = *festat;
+	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,		/* actual limit settings are set by .tune */
+		.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 *d, const struct i2c_device_id *id)
+{
+	struct dvb_frontend	*fe	= d->dev.platform_data;
+	static enum fe_status	festat;
+
+	memcpy(&fe->ops, &tc90522_ops, sizeof(struct dvb_frontend_ops));
+	festat = 0;
+	i2c_set_clientdata(d, &festat);
+	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.name	= tc90522_id->name,
+	.probe		= tc90522_probe,
+	.id_table	= tc90522_id,
+};
+module_i2c_driver(tc90522_driver);
+
+MODULE_AUTHOR("Budi Rachmanto, AreMa Inc. <knightrider(@)are.ma>");
+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. <info@are.ma>
+ *
+ * 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
+
-- 
2.7.4

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web