Devicetree
 help / color / mirror / Atom feed
* Re: [PATCH v2] ARM: dts: imx: ventana: fix DTC warnings
From: Shawn Guo @ 2017-04-14  2:42 UTC (permalink / raw)
  To: Tim Harvey
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Sascha Hauer,
	Fabio Estevam, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <1491857890-10554-1-git-send-email-tharvey-UMMOYl/HMS+akBO8gow8eQ@public.gmane.org>

On Mon, Apr 10, 2017 at 01:58:10PM -0700, Tim Harvey wrote:
> Remove the sky2 ethernet device node from the pcie controller which was
> invalid to begin with.
> 
> The original intent was to allow the bootloader to populate the MAC via
> dt but this requires the PCI bus topology to be complete in dt as well
> and as these boards have an expansion connector that topology is dynamic
> and can't be represented here.
> 
> Signed-off-by: Tim Harvey <tharvey-UMMOYl/HMS+akBO8gow8eQ@public.gmane.org>

Applied, thanks.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH v2 12/15] [media] cxd2880: Add DVB-T2 monitor and integration layer functions
From: Yasunari.Takiguchi-7U/KSKJipcs @ 2017-04-14  2:40 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA
  Cc: tbird20d-Re5JQEeQqe8AvxtiuMwx3w,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w, Yasunari Takiguchi,
	Masayuki Yamamoto, Hideki Nozawa, Kota Yonezawa,
	Toshihiko Matsumoto, Satoshi Watanabe
In-Reply-To: <20170414015043.16731-1-Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>

From: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>

Provide monitor and integration layer functions (DVB-T2)
for the Sony CXD2880 DVB-T2/T tuner + demodulator driver.

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe-7U/KSKJipcs@public.gmane.org>
---
 .../dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c    |  311 +++
 .../dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h    |   64 +
 .../cxd2880/cxd2880_tnrdmd_dvbt2_mon.c             | 2523 ++++++++++++++++++++
 .../cxd2880/cxd2880_tnrdmd_dvbt2_mon.h             |  170 ++
 4 files changed, 3068 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h

diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c
new file mode 100644
index 000000000000..1d60b9c236d8
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c
@@ -0,0 +1,311 @@
+/*
+ * cxd2880_integ_dvbt2.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * integration layer functions for DVB-T2
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_tnrdmd_dvbt2.h"
+#include "cxd2880_tnrdmd_dvbt2_mon.h"
+#include "cxd2880_integ_dvbt2.h"
+
+static enum cxd2880_ret dvbt2_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd,
+					      enum cxd2880_dvbt2_profile
+					      profile);
+
+static enum cxd2880_ret dvbt2_wait_l1_post_lock(struct cxd2880_tnrdmd *tnr_dmd);
+
+enum cxd2880_ret cxd2880_integ_dvbt2_tune(struct cxd2880_tnrdmd *tnr_dmd,
+					  struct cxd2880_dvbt2_tune_param
+					  *tune_param)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!tune_param))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	cxd2880_atomic_set(&tnr_dmd->cancel, 0);
+
+	if ((tune_param->bandwidth != CXD2880_DTV_BW_1_7_MHZ) &&
+	    (tune_param->bandwidth != CXD2880_DTV_BW_5_MHZ) &&
+	    (tune_param->bandwidth != CXD2880_DTV_BW_6_MHZ) &&
+	    (tune_param->bandwidth != CXD2880_DTV_BW_7_MHZ) &&
+	    (tune_param->bandwidth != CXD2880_DTV_BW_8_MHZ)) {
+		return CXD2880_RESULT_ERROR_NOSUPPORT;
+	}
+
+	if ((tune_param->profile != CXD2880_DVBT2_PROFILE_BASE) &&
+	    (tune_param->profile != CXD2880_DVBT2_PROFILE_LITE))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	ret = cxd2880_tnrdmd_dvbt2_tune1(tnr_dmd, tune_param);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	CXD2880_SLEEP(CXD2880_TNRDMD_WAIT_AGC_STABLE);
+
+	ret = cxd2880_tnrdmd_dvbt2_tune2(tnr_dmd, tune_param);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	ret = dvbt2_wait_demod_lock(tnr_dmd, tune_param->profile);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	ret = cxd2880_tnrdmd_dvbt2_diver_fef_setting(tnr_dmd);
+	if (ret == CXD2880_RESULT_ERROR_HW_STATE)
+		return CXD2880_RESULT_ERROR_UNLOCK;
+	else if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	ret = dvbt2_wait_l1_post_lock(tnr_dmd);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	{
+		u8 plp_not_found;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_data_plp_error(tnr_dmd,
+							    &plp_not_found);
+		if (ret == CXD2880_RESULT_ERROR_HW_STATE)
+			return CXD2880_RESULT_ERROR_UNLOCK;
+		else if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		if (plp_not_found) {
+			ret = CXD2880_RESULT_OK_CONFIRM;
+			tune_param->tune_info =
+			    CXD2880_TNRDMD_DVBT2_TUNE_INFO_INVALID_PLP_ID;
+		} else {
+			tune_param->tune_info =
+			    CXD2880_TNRDMD_DVBT2_TUNE_INFO_OK;
+		}
+	}
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_integ_dvbt2_wait_ts_lock(struct cxd2880_tnrdmd
+						  *tnr_dmd,
+						  enum cxd2880_dvbt2_profile
+						  profile)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	enum cxd2880_tnrdmd_lock_result lock =
+	    CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+	u16 timeout = 0;
+	struct cxd2880_stopwatch timer;
+	u8 continue_wait = 1;
+	u32 elapsed = 0;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	ret = cxd2880_stopwatch_start(&timer);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if (profile == CXD2880_DVBT2_PROFILE_BASE)
+		timeout = CXD2880_DVBT2_BASE_WAIT_TS_LOCK;
+	else if (profile == CXD2880_DVBT2_PROFILE_LITE)
+		timeout = CXD2880_DVBT2_LITE_WAIT_TS_LOCK;
+	else
+		return CXD2880_RESULT_ERROR_ARG;
+
+	for (;;) {
+		ret = cxd2880_stopwatch_elapsed(&timer, &elapsed);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		if (elapsed >= timeout)
+			continue_wait = 0;
+
+		ret = cxd2880_tnrdmd_dvbt2_check_ts_lock(tnr_dmd, &lock);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		switch (lock) {
+		case CXD2880_TNRDMD_LOCK_RESULT_LOCKED:
+			return CXD2880_RESULT_OK;
+
+		case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED:
+			return CXD2880_RESULT_ERROR_UNLOCK;
+
+		default:
+			break;
+		}
+
+		ret = cxd2880_integ_check_cancellation(tnr_dmd);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		if (continue_wait) {
+			ret =
+			    cxd2880_stopwatch_sleep(&timer,
+					    CXD2880_DVBT2_WAIT_LOCK_INTVL);
+			if (ret != CXD2880_RESULT_OK)
+				return ret;
+		} else {
+			ret = CXD2880_RESULT_ERROR_TIMEOUT;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static enum cxd2880_ret dvbt2_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd,
+					      enum cxd2880_dvbt2_profile
+					      profile)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	enum cxd2880_tnrdmd_lock_result lock =
+	    CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+	u16 timeout = 0;
+	struct cxd2880_stopwatch timer;
+	u8 continue_wait = 1;
+	u32 elapsed = 0;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	ret = cxd2880_stopwatch_start(&timer);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if (profile == CXD2880_DVBT2_PROFILE_BASE)
+		timeout = CXD2880_DVBT2_BASE_WAIT_DMD_LOCK;
+	else if ((profile == CXD2880_DVBT2_PROFILE_LITE) ||
+		 (profile == CXD2880_DVBT2_PROFILE_ANY))
+		timeout = CXD2880_DVBT2_LITE_WAIT_DMD_LOCK;
+	else
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	for (;;) {
+		ret = cxd2880_stopwatch_elapsed(&timer, &elapsed);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		if (elapsed >= timeout)
+			continue_wait = 0;
+
+		ret = cxd2880_tnrdmd_dvbt2_check_demod_lock(tnr_dmd, &lock);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		switch (lock) {
+		case CXD2880_TNRDMD_LOCK_RESULT_LOCKED:
+			return CXD2880_RESULT_OK;
+
+		case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED:
+			return CXD2880_RESULT_ERROR_UNLOCK;
+
+		default:
+			break;
+		}
+
+		ret = cxd2880_integ_check_cancellation(tnr_dmd);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		if (continue_wait) {
+			ret =
+			    cxd2880_stopwatch_sleep(&timer,
+					    CXD2880_DVBT2_WAIT_LOCK_INTVL);
+			if (ret != CXD2880_RESULT_OK)
+				return ret;
+		} else {
+			ret = CXD2880_RESULT_ERROR_TIMEOUT;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static enum cxd2880_ret dvbt2_wait_l1_post_lock(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	struct cxd2880_stopwatch timer;
+	u8 continue_wait = 1;
+	u32 elapsed = 0;
+	u8 l1_post_valid;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	ret = cxd2880_stopwatch_start(&timer);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	for (;;) {
+		ret = cxd2880_stopwatch_elapsed(&timer, &elapsed);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		if (elapsed >= CXD2880_DVBT2_L1POST_TIMEOUT)
+			continue_wait = 0;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_check_l1post_valid(tnr_dmd,
+							    &l1_post_valid);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		if (l1_post_valid)
+			return CXD2880_RESULT_OK;
+
+		ret = cxd2880_integ_check_cancellation(tnr_dmd);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		if (continue_wait) {
+			ret =
+			    cxd2880_stopwatch_sleep(&timer,
+					    CXD2880_DVBT2_WAIT_LOCK_INTVL);
+			if (ret != CXD2880_RESULT_OK)
+				return ret;
+		} else {
+			ret = CXD2880_RESULT_ERROR_TIMEOUT;
+			break;
+		}
+	}
+
+	return ret;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h
new file mode 100644
index 000000000000..bc72eb8188f2
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h
@@ -0,0 +1,64 @@
+/*
+ * cxd2880_integ_dvbt2.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * integration layer interface for DVB-T2
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_INTEG_DVBT2_H
+#define CXD2880_INTEG_DVBT2_H
+
+#include "cxd2880_tnrdmd.h"
+#include "cxd2880_tnrdmd_dvbt2.h"
+#include "cxd2880_integ.h"
+
+#define CXD2880_DVBT2_BASE_WAIT_DMD_LOCK     3500
+#define CXD2880_DVBT2_BASE_WAIT_TS_LOCK	1500
+#define CXD2880_DVBT2_LITE_WAIT_DMD_LOCK     5000
+#define CXD2880_DVBT2_LITE_WAIT_TS_LOCK	2300
+#define CXD2880_DVBT2_WAIT_LOCK_INTVL       10
+#define CXD2880_DVBT2_L1POST_TIMEOUT	   500
+
+struct cxd2880_integ_dvbt2_scan_param {
+	u32 start_frequency_khz;
+	u32 end_frequency_khz;
+	u32 step_frequency_khz;
+	enum cxd2880_dtv_bandwidth bandwidth;
+	enum cxd2880_dvbt2_profile t2_profile;
+};
+
+struct cxd2880_integ_dvbt2_scan_result {
+	u32 center_freq_khz;
+	enum cxd2880_ret tune_result;
+	struct cxd2880_dvbt2_tune_param dvbt2_tune_param;
+};
+
+enum cxd2880_ret cxd2880_integ_dvbt2_tune(struct cxd2880_tnrdmd *tnr_dmd,
+					  struct cxd2880_dvbt2_tune_param
+					  *tune_param);
+
+enum cxd2880_ret cxd2880_integ_dvbt2_wait_ts_lock(struct cxd2880_tnrdmd
+						  *tnr_dmd,
+						  enum cxd2880_dvbt2_profile
+						  profile);
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
new file mode 100644
index 000000000000..235db16f4a08
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
@@ -0,0 +1,2523 @@
+/*
+ * cxd2880_tnrdmd_dvbt2_mon.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * DVB-T2 monitor functions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_tnrdmd_mon.h"
+#include "cxd2880_tnrdmd_dvbt2.h"
+#include "cxd2880_tnrdmd_dvbt2_mon.h"
+#include "cxd2880_math.h"
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_tnrdmd
+						    *tnr_dmd, u8 *sync_stat,
+						    u8 *ts_lock_stat,
+						    u8 *unlock_detected)
+{
+	if ((!tnr_dmd) || (!sync_stat) || (!ts_lock_stat) || (!unlock_detected))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x0B) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	{
+		u8 data;
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x10, &data,
+					   sizeof(data)) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		*sync_stat = data & 0x07;
+		*ts_lock_stat = ((data & 0x20) ? 1 : 0);
+		*unlock_detected = ((data & 0x10) ? 1 : 0);
+	}
+
+	if (*sync_stat == 0x07)
+		return CXD2880_RESULT_ERROR_HW_STATE;
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(struct cxd2880_tnrdmd
+							*tnr_dmd,
+							u8 *sync_stat,
+							u8 *unlock_detected)
+{
+	u8 ts_lock_stat = 0;
+
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!sync_stat) || (!unlock_detected))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd->diver_sub, sync_stat,
+					       &ts_lock_stat, unlock_detected);
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_carrier_offset(struct cxd2880_tnrdmd
+							 *tnr_dmd, int *offset)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!offset))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	{
+		u8 data[4];
+		u32 ctl_val = 0;
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+
+		if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (sync_state != 6) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_HW_STATE;
+		}
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x0B) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x30, data,
+					   sizeof(data)) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		ctl_val =
+		    ((data[0] & 0x0F) << 24) | (data[1] << 16) | (data[2] << 8)
+		    | (data[3]);
+		*offset = cxd2880_convert2s_complement(ctl_val, 28);
+
+		switch (tnr_dmd->bandwidth) {
+		case CXD2880_DTV_BW_1_7_MHZ:
+			*offset = -1 * ((*offset) / 582);
+			break;
+		case CXD2880_DTV_BW_5_MHZ:
+		case CXD2880_DTV_BW_6_MHZ:
+		case CXD2880_DTV_BW_7_MHZ:
+		case CXD2880_DTV_BW_8_MHZ:
+			*offset =
+			    -1 * ((*offset) * (u8)tnr_dmd->bandwidth / 940);
+			break;
+		default:
+			return CXD2880_RESULT_ERROR_SW_STATE;
+		}
+	}
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_carrier_offset_sub(struct
+							     cxd2880_tnrdmd
+							     *tnr_dmd,
+							     int *offset)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!offset))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_carrier_offset(tnr_dmd->diver_sub, offset);
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_l1_pre(struct cxd2880_tnrdmd *tnr_dmd,
+						 struct cxd2880_dvbt2_l1pre
+						 *l1_pre)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!l1_pre))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	{
+		u8 data[37];
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+		u8 version = 0;
+		enum cxd2880_dvbt2_profile profile;
+
+		if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (sync_state < 5) {
+			if (tnr_dmd->diver_mode ==
+			    CXD2880_TNRDMD_DIVERMODE_MAIN) {
+				ret =
+				    cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub
+				    (tnr_dmd, &sync_state, &unlock_detected);
+				if (ret != CXD2880_RESULT_OK) {
+					slvt_unfreeze_reg(tnr_dmd);
+					return ret;
+				}
+
+				if (sync_state < 5) {
+					slvt_unfreeze_reg(tnr_dmd);
+					return CXD2880_RESULT_ERROR_HW_STATE;
+				}
+			} else {
+				slvt_unfreeze_reg(tnr_dmd);
+				return CXD2880_RESULT_ERROR_HW_STATE;
+			}
+		}
+
+		ret = cxd2880_tnrdmd_dvbt2_mon_profile(tnr_dmd, &profile);
+		if (ret != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x0B) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x61, data,
+					   sizeof(data)) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+		slvt_unfreeze_reg(tnr_dmd);
+
+		l1_pre->type = (enum cxd2880_dvbt2_l1pre_type)data[0];
+		l1_pre->bw_ext = data[1] & 0x01;
+		l1_pre->s1 = (enum cxd2880_dvbt2_s1)(data[2] & 0x07);
+		l1_pre->s2 = data[3] & 0x0F;
+		l1_pre->l1_rep = data[4] & 0x01;
+		l1_pre->gi = (enum cxd2880_dvbt2_guard)(data[5] & 0x07);
+		l1_pre->papr = (enum cxd2880_dvbt2_papr)(data[6] & 0x0F);
+		l1_pre->mod =
+		    (enum cxd2880_dvbt2_l1post_constell)(data[7] & 0x0F);
+		l1_pre->cr = (enum cxd2880_dvbt2_l1post_cr)(data[8] & 0x03);
+		l1_pre->fec =
+		    (enum cxd2880_dvbt2_l1post_fec_type)(data[9] & 0x03);
+		l1_pre->l1_post_size = (data[10] & 0x03) << 16;
+		l1_pre->l1_post_size |= (data[11]) << 8;
+		l1_pre->l1_post_size |= (data[12]);
+		l1_pre->l1_post_info_size = (data[13] & 0x03) << 16;
+		l1_pre->l1_post_info_size |= (data[14]) << 8;
+		l1_pre->l1_post_info_size |= (data[15]);
+		l1_pre->pp = (enum cxd2880_dvbt2_pp)(data[16] & 0x0F);
+		l1_pre->tx_id_availability = data[17];
+		l1_pre->cell_id = (data[18] << 8);
+		l1_pre->cell_id |= (data[19]);
+		l1_pre->network_id = (data[20] << 8);
+		l1_pre->network_id |= (data[21]);
+		l1_pre->sys_id = (data[22] << 8);
+		l1_pre->sys_id |= (data[23]);
+		l1_pre->num_frames = data[24];
+		l1_pre->num_symbols = (data[25] & 0x0F) << 8;
+		l1_pre->num_symbols |= data[26];
+		l1_pre->regen = data[27] & 0x07;
+		l1_pre->post_ext = data[28] & 0x01;
+		l1_pre->num_rf_freqs = data[29] & 0x07;
+		l1_pre->rf_idx = data[30] & 0x07;
+		version = (data[31] & 0x03) << 2;
+		version |= (data[32] & 0xC0) >> 6;
+		l1_pre->t2_version = (enum cxd2880_dvbt2_version)version;
+		l1_pre->l1_post_scrambled = (data[32] & 0x20) >> 5;
+		l1_pre->t2_base_lite = (data[32] & 0x10) >> 4;
+		l1_pre->crc32 = (data[33] << 24);
+		l1_pre->crc32 |= (data[34] << 16);
+		l1_pre->crc32 |= (data[35] << 8);
+		l1_pre->crc32 |= data[36];
+
+		if (profile == CXD2880_DVBT2_PROFILE_BASE) {
+			switch ((l1_pre->s2 >> 1)) {
+			case CXD2880_DVBT2_BASE_S2_M1K_G_ANY:
+				l1_pre->fft_mode = CXD2880_DVBT2_M1K;
+				break;
+			case CXD2880_DVBT2_BASE_S2_M2K_G_ANY:
+				l1_pre->fft_mode = CXD2880_DVBT2_M2K;
+				break;
+			case CXD2880_DVBT2_BASE_S2_M4K_G_ANY:
+				l1_pre->fft_mode = CXD2880_DVBT2_M4K;
+				break;
+			case CXD2880_DVBT2_BASE_S2_M8K_G_DVBT:
+			case CXD2880_DVBT2_BASE_S2_M8K_G_DVBT2:
+				l1_pre->fft_mode = CXD2880_DVBT2_M8K;
+				break;
+			case CXD2880_DVBT2_BASE_S2_M16K_G_ANY:
+				l1_pre->fft_mode = CXD2880_DVBT2_M16K;
+				break;
+			case CXD2880_DVBT2_BASE_S2_M32K_G_DVBT:
+			case CXD2880_DVBT2_BASE_S2_M32K_G_DVBT2:
+				l1_pre->fft_mode = CXD2880_DVBT2_M32K;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_HW_STATE;
+			}
+		} else if (profile == CXD2880_DVBT2_PROFILE_LITE) {
+			switch ((l1_pre->s2 >> 1)) {
+			case CXD2880_DVBT2_LITE_S2_M2K_G_ANY:
+				l1_pre->fft_mode = CXD2880_DVBT2_M2K;
+				break;
+			case CXD2880_DVBT2_LITE_S2_M4K_G_ANY:
+				l1_pre->fft_mode = CXD2880_DVBT2_M4K;
+				break;
+			case CXD2880_DVBT2_LITE_S2_M8K_G_DVBT:
+			case CXD2880_DVBT2_LITE_S2_M8K_G_DVBT2:
+				l1_pre->fft_mode = CXD2880_DVBT2_M8K;
+				break;
+			case CXD2880_DVBT2_LITE_S2_M16K_G_DVBT:
+			case CXD2880_DVBT2_LITE_S2_M16K_G_DVBT2:
+				l1_pre->fft_mode = CXD2880_DVBT2_M16K;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_HW_STATE;
+			}
+		} else {
+			return CXD2880_RESULT_ERROR_HW_STATE;
+		}
+
+		l1_pre->mixed = l1_pre->s2 & 0x01;
+	}
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_version(struct cxd2880_tnrdmd
+						  *tnr_dmd,
+						  enum cxd2880_dvbt2_version
+						  *ver)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	u8 version = 0;
+
+	if ((!tnr_dmd) || (!ver))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	{
+		u8 data[2];
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+
+		if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (sync_state < 5) {
+			if (tnr_dmd->diver_mode ==
+			    CXD2880_TNRDMD_DIVERMODE_MAIN) {
+				ret =
+				    cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub
+				    (tnr_dmd, &sync_state, &unlock_detected);
+				if (ret != CXD2880_RESULT_OK) {
+					slvt_unfreeze_reg(tnr_dmd);
+					return ret;
+				}
+
+				if (sync_state < 5) {
+					slvt_unfreeze_reg(tnr_dmd);
+					return CXD2880_RESULT_ERROR_HW_STATE;
+				}
+			} else {
+				slvt_unfreeze_reg(tnr_dmd);
+				return CXD2880_RESULT_ERROR_HW_STATE;
+			}
+		}
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x0B) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x80, data,
+					   sizeof(data)) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		version = ((data[0] & 0x03) << 2);
+		version |= ((data[1] & 0xC0) >> 6);
+		*ver = (enum cxd2880_dvbt2_version)version;
+	}
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ofdm(struct cxd2880_tnrdmd *tnr_dmd,
+					       struct cxd2880_dvbt2_ofdm *ofdm)
+{
+	if ((!tnr_dmd) || (!ofdm))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	{
+		u8 data[5];
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+		enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+		if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (sync_state != 6) {
+			slvt_unfreeze_reg(tnr_dmd);
+
+			ret = CXD2880_RESULT_ERROR_HW_STATE;
+
+			if (tnr_dmd->diver_mode ==
+			    CXD2880_TNRDMD_DIVERMODE_MAIN)
+				ret =
+				    cxd2880_tnrdmd_dvbt2_mon_ofdm(
+					tnr_dmd->diver_sub, ofdm);
+
+			return ret;
+		}
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x0B) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x1D, data,
+					   sizeof(data)) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		ofdm->mixed = ((data[0] & 0x20) ? 1 : 0);
+		ofdm->is_miso = ((data[0] & 0x10) >> 4);
+		ofdm->mode = (enum cxd2880_dvbt2_mode)(data[0] & 0x07);
+		ofdm->gi = (enum cxd2880_dvbt2_guard)((data[1] & 0x70) >> 4);
+		ofdm->pp = (enum cxd2880_dvbt2_pp)(data[1] & 0x07);
+		ofdm->bw_ext = (data[2] & 0x10) >> 4;
+		ofdm->papr = (enum cxd2880_dvbt2_papr)(data[2] & 0x0F);
+		ofdm->num_symbols = (data[3] << 8) | data[4];
+	}
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_tnrdmd
+						    *tnr_dmd, u8 *plp_ids,
+						    u8 *num_plps)
+{
+	if ((!tnr_dmd) || (!num_plps))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	{
+		u8 l1_post_ok = 0;
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x0B) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x86,
+					   &l1_post_ok,
+					   1) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (!(l1_post_ok & 0x01)) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_HW_STATE;
+		}
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0xC1, num_plps,
+					   1) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (*num_plps == 0) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_OTHER;
+		}
+
+		if (!plp_ids) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_OK;
+		}
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0xC2, plp_ids,
+					   ((*num_plps >
+					     62) ? 62 : *num_plps)) !=
+		    CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (*num_plps > 62) {
+			if (tnr_dmd->io->write_reg(tnr_dmd->io,
+						   CXD2880_IO_TGT_DMD, 0x00,
+						   0x0C) != CXD2880_RESULT_OK) {
+				slvt_unfreeze_reg(tnr_dmd);
+				return CXD2880_RESULT_ERROR_IO;
+			}
+
+			if (tnr_dmd->io->read_regs(tnr_dmd->io,
+						   CXD2880_IO_TGT_DMD, 0x10,
+						   plp_ids + 62,
+						   *num_plps - 62) !=
+			    CXD2880_RESULT_OK) {
+				slvt_unfreeze_reg(tnr_dmd);
+				return CXD2880_RESULT_ERROR_IO;
+			}
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+	}
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_active_plp(struct cxd2880_tnrdmd
+						     *tnr_dmd,
+						     enum
+						     cxd2880_dvbt2_plp_btype
+						     type,
+						     struct cxd2880_dvbt2_plp
+						     *plp_info)
+{
+	if ((!tnr_dmd) || (!plp_info))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	{
+		u8 data[20];
+		u8 addr = 0;
+		u8 index = 0;
+		u8 l1_post_ok = 0;
+
+		if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x0B) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x86,
+					   &l1_post_ok,
+					   1) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (!l1_post_ok) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_HW_STATE;
+		}
+
+		if (type == CXD2880_DVBT2_PLP_COMMON)
+			addr = 0xA9;
+		else
+			addr = 0x96;
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, addr, data,
+					   sizeof(data)) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		if ((type == CXD2880_DVBT2_PLP_COMMON) && (data[13] == 0))
+			return CXD2880_RESULT_ERROR_HW_STATE;
+
+		plp_info->id = data[index++];
+		plp_info->type =
+		    (enum cxd2880_dvbt2_plp_type)(data[index++] & 0x07);
+		plp_info->payload =
+		    (enum cxd2880_dvbt2_plp_payload)(data[index++] & 0x1F);
+		plp_info->ff = data[index++] & 0x01;
+		plp_info->first_rf_idx = data[index++] & 0x07;
+		plp_info->first_frm_idx = data[index++];
+		plp_info->group_id = data[index++];
+		plp_info->plp_cr =
+		    (enum cxd2880_dvbt2_plp_code_rate)(data[index++] & 0x07);
+		plp_info->constell =
+		    (enum cxd2880_dvbt2_plp_constell)(data[index++] & 0x07);
+		plp_info->rot = data[index++] & 0x01;
+		plp_info->fec =
+		    (enum cxd2880_dvbt2_plp_fec)(data[index++] & 0x03);
+		plp_info->num_blocks_max = (u16)((data[index++] & 0x03)) << 8;
+		plp_info->num_blocks_max |= data[index++];
+		plp_info->frm_int = data[index++];
+		plp_info->til_len = data[index++];
+		plp_info->til_type = data[index++] & 0x01;
+
+		plp_info->in_band_a_flag = data[index++] & 0x01;
+		plp_info->rsvd = data[index++] << 8;
+		plp_info->rsvd |= data[index++];
+
+		plp_info->in_band_b_flag =
+		    (u8)((plp_info->rsvd & 0x8000) >> 15);
+		plp_info->plp_mode =
+		    (enum cxd2880_dvbt2_plp_mode)((plp_info->rsvd & 0x000C) >>
+						  2);
+		plp_info->static_flag = (u8)((plp_info->rsvd & 0x0002) >> 1);
+		plp_info->static_padding_flag = (u8)(plp_info->rsvd & 0x0001);
+		plp_info->rsvd = (u16)((plp_info->rsvd & 0x7FF0) >> 4);
+	}
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_data_plp_error(struct cxd2880_tnrdmd
+							 *tnr_dmd,
+							 u8 *plp_error)
+{
+	if ((!tnr_dmd) || (!plp_error))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	{
+		u8 data;
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x0B) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x86, &data,
+					   1) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if ((data & 0x01) == 0x00) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_HW_STATE;
+		}
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0xC0, &data,
+					   1) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		*plp_error = data & 0x01;
+	}
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_l1_change(struct cxd2880_tnrdmd
+						    *tnr_dmd, u8 *l1_change)
+{
+	if ((!tnr_dmd) || (!l1_change))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	{
+		u8 data;
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+		enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+		if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (sync_state < 5) {
+			if (tnr_dmd->diver_mode ==
+			    CXD2880_TNRDMD_DIVERMODE_MAIN) {
+				ret =
+				    cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub
+				    (tnr_dmd, &sync_state, &unlock_detected);
+				if (ret != CXD2880_RESULT_OK) {
+					slvt_unfreeze_reg(tnr_dmd);
+					return ret;
+				}
+
+				if (sync_state < 5) {
+					slvt_unfreeze_reg(tnr_dmd);
+					return CXD2880_RESULT_ERROR_HW_STATE;
+				}
+			} else {
+				slvt_unfreeze_reg(tnr_dmd);
+				return CXD2880_RESULT_ERROR_HW_STATE;
+			}
+		}
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x0B) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x5F, &data,
+					   sizeof(data)) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		*l1_change = data & 0x01;
+		if (*l1_change) {
+			if (tnr_dmd->io->write_reg(tnr_dmd->io,
+						   CXD2880_IO_TGT_DMD, 0x00,
+						   0x22) != CXD2880_RESULT_OK) {
+				slvt_unfreeze_reg(tnr_dmd);
+				return CXD2880_RESULT_ERROR_IO;
+			}
+
+			if (tnr_dmd->io->write_reg(tnr_dmd->io,
+						   CXD2880_IO_TGT_DMD, 0x16,
+						   0x01) != CXD2880_RESULT_OK) {
+				slvt_unfreeze_reg(tnr_dmd);
+				return CXD2880_RESULT_ERROR_IO;
+			}
+		}
+		slvt_unfreeze_reg(tnr_dmd);
+	}
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_l1_post(struct cxd2880_tnrdmd
+						  *tnr_dmd,
+						  struct cxd2880_dvbt2_l1post
+						  *l1_post)
+{
+	if ((!tnr_dmd) || (!l1_post))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	{
+		u8 data[16];
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x0B) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x86, data,
+					   sizeof(data)) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (!(data[0] & 0x01))
+			return CXD2880_RESULT_ERROR_HW_STATE;
+
+		l1_post->sub_slices_per_frame = (data[1] & 0x7F) << 8;
+		l1_post->sub_slices_per_frame |= data[2];
+		l1_post->num_plps = data[3];
+		l1_post->num_aux = data[4] & 0x0F;
+		l1_post->aux_cfg_rfu = data[5];
+		l1_post->rf_idx = data[6] & 0x07;
+		l1_post->freq = data[7] << 24;
+		l1_post->freq |= data[8] << 16;
+		l1_post->freq |= data[9] << 8;
+		l1_post->freq |= data[10];
+		l1_post->fef_type = data[11] & 0x0F;
+		l1_post->fef_length = data[12] << 16;
+		l1_post->fef_length |= data[13] << 8;
+		l1_post->fef_length |= data[14];
+		l1_post->fef_intvl = data[15];
+	}
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_bbheader(struct cxd2880_tnrdmd
+						   *tnr_dmd,
+						   enum cxd2880_dvbt2_plp_btype
+						   type,
+						   struct cxd2880_dvbt2_bbheader
+						   *bbheader)
+{
+	if ((!tnr_dmd) || (!bbheader))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	{
+		enum cxd2880_ret ret = CXD2880_RESULT_OK;
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (!ts_lock) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_HW_STATE;
+		}
+	}
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x0B) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (type == CXD2880_DVBT2_PLP_COMMON) {
+		u8 l1_post_ok;
+		u8 data;
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x86,
+					   &l1_post_ok,
+					   1) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (!(l1_post_ok & 0x01)) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_HW_STATE;
+		}
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0xB6, &data,
+					   1) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (data == 0) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_HW_STATE;
+		}
+	}
+
+	{
+		u8 data[14];
+		u8 addr = 0;
+
+		if (type == CXD2880_DVBT2_PLP_COMMON)
+			addr = 0x51;
+		else
+			addr = 0x42;
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, addr, data,
+					   sizeof(data)) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		bbheader->stream_input =
+		    (enum cxd2880_dvbt2_stream)((data[0] >> 6) & 0x03);
+		bbheader->is_single_input_stream = (u8)((data[0] >> 5) & 0x01);
+		bbheader->is_constant_coding_modulation =
+		    (u8)((data[0] >> 4) & 0x01);
+		bbheader->issy_indicator = (u8)((data[0] >> 3) & 0x01);
+		bbheader->null_packet_deletion = (u8)((data[0] >> 2) & 0x01);
+		bbheader->ext = (u8)(data[0] & 0x03);
+
+		bbheader->input_stream_identifier = data[1];
+		bbheader->plp_mode =
+		    (data[3] & 0x01) ? CXD2880_DVBT2_PLP_MODE_HEM :
+		    CXD2880_DVBT2_PLP_MODE_NM;
+		bbheader->data_field_length = (u16)((data[4] << 8) | data[5]);
+
+		if (bbheader->plp_mode == CXD2880_DVBT2_PLP_MODE_NM) {
+			bbheader->user_packet_length =
+			    (u16)((data[6] << 8) | data[7]);
+			bbheader->sync_byte = data[8];
+			bbheader->issy = 0;
+		} else {
+			bbheader->user_packet_length = 0;
+			bbheader->sync_byte = 0;
+			bbheader->issy =
+			    (u32)((data[11] << 16) | (data[12] << 8) |
+				   data[13]);
+		}
+	}
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_in_bandb_ts_rate(struct cxd2880_tnrdmd
+						   *tnr_dmd,
+						   enum
+						   cxd2880_dvbt2_plp_btype
+						   type,
+						   u32 *ts_rate_bps)
+{
+	if ((!tnr_dmd) || (!ts_rate_bps))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	{
+		enum cxd2880_ret ret = CXD2880_RESULT_OK;
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (!ts_lock) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_HW_STATE;
+		}
+	}
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x0B) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	{
+		u8 l1_post_ok = 0;
+		u8 addr = 0;
+		u8 data = 0;
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x86,
+					   &l1_post_ok,
+					   1) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (!(l1_post_ok & 0x01)) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_HW_STATE;
+		}
+
+		if (type == CXD2880_DVBT2_PLP_COMMON)
+			addr = 0xBA;
+		else
+			addr = 0xA7;
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, addr, &data,
+					   1) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if ((data & 0x80) == 0x00) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_HW_STATE;
+		}
+	}
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x25) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	{
+		u8 data[4];
+		u8 addr = 0;
+
+		if (type == CXD2880_DVBT2_PLP_COMMON)
+			addr = 0xA6;
+		else
+			addr = 0xAA;
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, addr, &data[0],
+					   4) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		*ts_rate_bps =
+		    (u32)(((data[0] & 0x07) << 24) | (data[1] << 16) |
+			   (data[2] << 8) | data[3]);
+	}
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(struct cxd2880_tnrdmd
+						 *tnr_dmd,
+						 enum
+						 cxd2880_tnrdmd_spectrum_sense
+						 *sense)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	u8 sync_state = 0;
+	u8 ts_lock = 0;
+	u8 early_unlock = 0;
+
+	if ((!tnr_dmd) || (!sense))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, &ts_lock,
+					       &early_unlock);
+	if (ret != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	if (sync_state != 6) {
+		slvt_unfreeze_reg(tnr_dmd);
+
+		ret = CXD2880_RESULT_ERROR_HW_STATE;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
+			ret =
+			    cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(
+				tnr_dmd->diver_sub, sense);
+
+		return ret;
+	}
+
+	{
+		u8 data = 0;
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x0B) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x2F, &data,
+					   sizeof(data)) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		*sense =
+		    (data & 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV :
+		    CXD2880_TNRDMD_SPECTRUM_NORMAL;
+	}
+
+	return CXD2880_RESULT_OK;
+}
+
+static enum cxd2880_ret dvbt2_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd,
+					   u16 *reg_value)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!reg_value))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	{
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+		u8 data[2];
+
+		if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (sync_state != 6) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_HW_STATE;
+		}
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x0B) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x13, data,
+					   sizeof(data)) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		*reg_value = (data[0] << 8) | data[1];
+	}
+
+	return ret;
+}
+
+static enum cxd2880_ret dvbt2_calc_snr(struct cxd2880_tnrdmd *tnr_dmd,
+				       u32 reg_value, int *snr)
+{
+	if ((!tnr_dmd) || (!snr))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (reg_value == 0)
+		return CXD2880_RESULT_ERROR_HW_STATE;
+
+	if (reg_value > 10876)
+		reg_value = 10876;
+
+	*snr =
+	    10 * 10 * ((int)cxd2880_math_log10(reg_value) -
+		       (int)cxd2880_math_log10(12600 - reg_value));
+	*snr += 32000;
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
+					      int *snr)
+{
+	u16 reg_value = 0;
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!snr))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	*snr = -1000 * 1000;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
+		ret = dvbt2_read_snr_reg(tnr_dmd, &reg_value);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		ret = dvbt2_calc_snr(tnr_dmd, reg_value, snr);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	} else {
+		int snr_main = 0;
+		int snr_sub = 0;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_snr_diver(tnr_dmd, snr, &snr_main,
+						       &snr_sub);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	}
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_snr_diver(struct cxd2880_tnrdmd
+						    *tnr_dmd, int *snr,
+						    int *snr_main, int *snr_sub)
+{
+	u16 reg_value = 0;
+	u32 reg_value_sum = 0;
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!snr) || (!snr_main) || (!snr_sub))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	*snr = -1000 * 1000;
+	*snr_main = -1000 * 1000;
+	*snr_sub = -1000 * 1000;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	ret = dvbt2_read_snr_reg(tnr_dmd, &reg_value);
+	if (ret == CXD2880_RESULT_OK) {
+		ret = dvbt2_calc_snr(tnr_dmd, reg_value, snr_main);
+		if (ret != CXD2880_RESULT_OK)
+			reg_value = 0;
+	} else if (ret == CXD2880_RESULT_ERROR_HW_STATE) {
+		reg_value = 0;
+	} else {
+		return ret;
+	}
+
+	reg_value_sum += reg_value;
+
+	ret = dvbt2_read_snr_reg(tnr_dmd->diver_sub, &reg_value);
+	if (ret == CXD2880_RESULT_OK) {
+		ret = dvbt2_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub);
+		if (ret != CXD2880_RESULT_OK)
+			reg_value = 0;
+	} else if (ret == CXD2880_RESULT_ERROR_HW_STATE) {
+		reg_value = 0;
+	} else {
+		return ret;
+	}
+
+	reg_value_sum += reg_value;
+
+	ret = dvbt2_calc_snr(tnr_dmd, reg_value_sum, snr);
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_pre_ldpcber(struct cxd2880_tnrdmd
+						      *tnr_dmd, u32 *ber)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	u32 bit_error = 0;
+	u32 period_exp = 0;
+	u32 n_ldpc = 0;
+
+	if ((!tnr_dmd) || (!ber))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x0B) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	{
+		u8 data[5];
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x3C, data,
+					   sizeof(data)) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (!(data[0] & 0x01)) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_HW_STATE;
+		}
+
+		bit_error =
+		    ((data[1] & 0x0F) << 24) | (data[2] << 16) | (data[3] << 8)
+		    | data[4];
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0xA0, data,
+					   1) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (((enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03)) ==
+		    CXD2880_DVBT2_FEC_LDPC_16K)
+			n_ldpc = 16200;
+		else
+			n_ldpc = 64800;
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x20) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x6F, data,
+					   1) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		period_exp = data[0] & 0x0F;
+	}
+
+	if (bit_error > ((1U << period_exp) * n_ldpc))
+		return CXD2880_RESULT_ERROR_HW_STATE;
+
+	{
+		u32 div = 0;
+		u32 Q = 0;
+		u32 R = 0;
+
+		if (period_exp >= 4) {
+			div = (1U << (period_exp - 4)) * (n_ldpc / 200);
+
+			Q = (bit_error * 5) / div;
+			R = (bit_error * 5) % div;
+
+			R *= 625;
+			Q = Q * 625 + R / div;
+			R = R % div;
+		} else {
+			div = (1U << period_exp) * (n_ldpc / 200);
+
+			Q = (bit_error * 10) / div;
+			R = (bit_error * 10) % div;
+
+			R *= 5000;
+			Q = Q * 5000 + R / div;
+			R = R % div;
+		}
+
+		if (div / 2 <= R)
+			*ber = Q + 1;
+		else
+			*ber = Q;
+	}
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_post_bchfer(struct cxd2880_tnrdmd
+						      *tnr_dmd, u32 *fer)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	u32 fec_error = 0;
+	u32 period = 0;
+
+	if ((!tnr_dmd) || (!fer))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x0B) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	{
+		u8 data[2];
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x1B, data,
+					   2) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (!(data[0] & 0x80))
+			return CXD2880_RESULT_ERROR_HW_STATE;
+
+		fec_error = ((data[0] & 0x7F) << 8) | (data[1]);
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x20) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x72, data,
+					   1) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		period = (1 << (data[0] & 0x0F));
+	}
+
+	if ((period == 0) || (fec_error > period))
+		return CXD2880_RESULT_ERROR_HW_STATE;
+
+	{
+		u32 div = 0;
+		u32 Q = 0;
+		u32 R = 0;
+
+		div = period;
+
+		Q = (fec_error * 1000) / div;
+		R = (fec_error * 1000) % div;
+
+		R *= 1000;
+		Q = Q * 1000 + R / div;
+		R = R % div;
+
+		if ((div != 1) && (div / 2 <= R))
+			*fer = Q + 1;
+		else
+			*fer = Q;
+	}
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_pre_bchber(struct cxd2880_tnrdmd
+						     *tnr_dmd, u32 *ber)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	u32 bit_error = 0;
+	u32 period_exp = 0;
+	u32 n_bch = 0;
+
+	if ((!tnr_dmd) || (!ber))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	{
+		u8 data[3];
+		enum cxd2880_dvbt2_plp_fec plp_fec_type =
+		    CXD2880_DVBT2_FEC_LDPC_16K;
+		enum cxd2880_dvbt2_plp_code_rate plp_cr = CXD2880_DVBT2_R1_2;
+
+		static const u16 n_bch_bits_lookup[2][8] = {
+			{7200, 9720, 10800, 11880, 12600, 13320, 5400, 6480},
+			{32400, 38880, 43200, 48600, 51840, 54000, 21600, 25920}
+		};
+
+		if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x0B) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x15, data,
+					   3) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (!(data[0] & 0x40)) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_HW_STATE;
+		}
+
+		bit_error = ((data[0] & 0x3F) << 16) | (data[1] << 8) | data[2];
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x9D, data,
+					   1) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		plp_cr = (enum cxd2880_dvbt2_plp_code_rate)(data[0] & 0x07);
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0xA0, data,
+					   1) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		plp_fec_type = (enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03);
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x20) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x72, data,
+					   1) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		period_exp = data[0] & 0x0F;
+
+		if ((plp_fec_type > CXD2880_DVBT2_FEC_LDPC_64K) ||
+		    (plp_cr > CXD2880_DVBT2_R2_5))
+			return CXD2880_RESULT_ERROR_HW_STATE;
+
+		n_bch = n_bch_bits_lookup[plp_fec_type][plp_cr];
+	}
+
+	if (bit_error > ((1U << period_exp) * n_bch))
+		return CXD2880_RESULT_ERROR_HW_STATE;
+
+	{
+		u32 div = 0;
+		u32 Q = 0;
+		u32 R = 0;
+
+		if (period_exp >= 6) {
+			div = (1U << (period_exp - 6)) * (n_bch / 40);
+
+			Q = (bit_error * 625) / div;
+			R = (bit_error * 625) % div;
+
+			R *= 625;
+			Q = Q * 625 + R / div;
+			R = R % div;
+		} else {
+			div = (1U << period_exp) * (n_bch / 40);
+
+			Q = (bit_error * 1000) / div;
+			R = (bit_error * 1000) % div;
+
+			R *= 25000;
+			Q = Q * 25000 + R / div;
+			R = R % div;
+		}
+
+		if (div / 2 <= R)
+			*ber = Q + 1;
+		else
+			*ber = Q;
+	}
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_packet_error_number(struct
+							      cxd2880_tnrdmd
+							      *tnr_dmd,
+							      u32 *pen)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	u8 data[3];
+
+	if ((!tnr_dmd) || (!pen))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x0B) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x39, data,
+				   sizeof(data)) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (!(data[0] & 0x01))
+		return CXD2880_RESULT_ERROR_HW_STATE;
+
+	*pen = ((data[1] << 8) | data[2]);
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sampling_offset(struct cxd2880_tnrdmd
+							  *tnr_dmd, int *ppm)
+{
+	if ((!tnr_dmd) || (!ppm))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	{
+		u8 ctl_val_reg[5];
+		u8 nominal_rate_reg[5];
+		u32 trl_ctl_val = 0;
+		u32 trcg_nominal_rate = 0;
+		int num;
+		int den;
+		enum cxd2880_ret ret = CXD2880_RESULT_OK;
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+		s8 diff_upper = 0;
+
+		if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (sync_state != 6) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_HW_STATE;
+		}
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x0B) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x34,
+					   ctl_val_reg,
+					   sizeof(ctl_val_reg)) !=
+		    CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x04) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x10,
+					   nominal_rate_reg,
+					   sizeof(nominal_rate_reg)) !=
+		    CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		diff_upper =
+		    (ctl_val_reg[0] & 0x7F) - (nominal_rate_reg[0] & 0x7F);
+
+		if ((diff_upper < -1) || (diff_upper > 1))
+			return CXD2880_RESULT_ERROR_HW_STATE;
+
+		trl_ctl_val = ctl_val_reg[1] << 24;
+		trl_ctl_val |= ctl_val_reg[2] << 16;
+		trl_ctl_val |= ctl_val_reg[3] << 8;
+		trl_ctl_val |= ctl_val_reg[4];
+
+		trcg_nominal_rate = nominal_rate_reg[1] << 24;
+		trcg_nominal_rate |= nominal_rate_reg[2] << 16;
+		trcg_nominal_rate |= nominal_rate_reg[3] << 8;
+		trcg_nominal_rate |= nominal_rate_reg[4];
+
+		trl_ctl_val >>= 1;
+		trcg_nominal_rate >>= 1;
+
+		if (diff_upper == 1)
+			num =
+			    (int)((trl_ctl_val + 0x80000000u) -
+				  trcg_nominal_rate);
+		else if (diff_upper == -1)
+			num =
+			    -(int)((trcg_nominal_rate + 0x80000000u) -
+				   trl_ctl_val);
+		else
+			num = (int)(trl_ctl_val - trcg_nominal_rate);
+
+		den = (nominal_rate_reg[0] & 0x7F) << 24;
+		den |= nominal_rate_reg[1] << 16;
+		den |= nominal_rate_reg[2] << 8;
+		den |= nominal_rate_reg[3];
+		den = (den + (390625 / 2)) / 390625;
+
+		den >>= 1;
+
+		if (num >= 0)
+			*ppm = (num + (den / 2)) / den;
+		else
+			*ppm = (num - (den / 2)) / den;
+	}
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct
+							      cxd2880_tnrdmd
+							      *tnr_dmd,
+							      int *ppm)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!ppm))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	ret = cxd2880_tnrdmd_dvbt2_mon_sampling_offset(tnr_dmd->diver_sub, ppm);
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_quality(struct cxd2880_tnrdmd
+						  *tnr_dmd, u8 *quality)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	int snr = 0;
+	int snr_rel = 0;
+	u32 ber = 0;
+	u32 ber_sqi = 0;
+	enum cxd2880_dvbt2_plp_constell qam;
+	enum cxd2880_dvbt2_plp_code_rate code_rate;
+
+	static const int snr_nordig_p1_db_1000[4][8] = {
+		{3500, 4700, 5600, 6600, 7200, 7700, 1300, 2200},
+		{8700, 10100, 11400, 12500, 13300, 13800, 6000, 7200},
+		{13000, 14800, 16200, 17700, 18700, 19400, 9800, 11100},
+		{17000, 19400, 20800, 22900, 24300, 25100, 13200, 14800},
+	};
+
+	if ((!tnr_dmd) || (!quality))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	ret = cxd2880_tnrdmd_dvbt2_mon_pre_bchber(tnr_dmd, &ber);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	ret = cxd2880_tnrdmd_dvbt2_mon_snr(tnr_dmd, &snr);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_qam(tnr_dmd, CXD2880_DVBT2_PLP_DATA, &qam);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_code_rate(tnr_dmd, CXD2880_DVBT2_PLP_DATA,
+					       &code_rate);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if ((code_rate > CXD2880_DVBT2_R2_5) || (qam > CXD2880_DVBT2_QAM256))
+		return CXD2880_RESULT_ERROR_OTHER;
+
+	if (ber > 100000)
+		ber_sqi = 0;
+	else if (ber >= 100)
+		ber_sqi = 6667;
+	else
+		ber_sqi = 16667;
+
+	snr_rel = snr - snr_nordig_p1_db_1000[qam][code_rate];
+
+	if (snr_rel < -3000) {
+		*quality = 0;
+	} else if (snr_rel <= 3000) {
+		u32 temp_sqi =
+		    (((snr_rel + 3000) * ber_sqi) + 500000) / 1000000;
+		*quality = (temp_sqi > 100) ? 100 : (u8)temp_sqi;
+	} else {
+		*quality = 100;
+	}
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ts_rate(struct cxd2880_tnrdmd
+						  *tnr_dmd, u32 *ts_rate_kbps)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	u32 rd_smooth_dp = 0;
+	u32 ep_ck_nume = 0;
+	u32 ep_ck_deno = 0;
+	u8 issy_on_data = 0;
+
+	if ((!tnr_dmd) || (!ts_rate_kbps))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	{
+		u8 data[12];
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+
+		if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (!ts_lock) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_HW_STATE;
+		}
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x0B) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x23, data,
+					   12) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		rd_smooth_dp = (u32)((data[0] & 0x1F) << 24);
+		rd_smooth_dp |= (u32)(data[1] << 16);
+		rd_smooth_dp |= (u32)(data[2] << 8);
+		rd_smooth_dp |= (u32)data[3];
+
+		if (rd_smooth_dp < 214958) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_HW_STATE;
+		}
+
+		ep_ck_nume = (u32)((data[4] & 0x3F) << 24);
+		ep_ck_nume |= (u32)(data[5] << 16);
+		ep_ck_nume |= (u32)(data[6] << 8);
+		ep_ck_nume |= (u32)data[7];
+
+		ep_ck_deno = (u32)((data[8] & 0x3F) << 24);
+		ep_ck_deno |= (u32)(data[9] << 16);
+		ep_ck_deno |= (u32)(data[10] << 8);
+		ep_ck_deno |= (u32)data[11];
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x41, data,
+					   1) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		issy_on_data = data[0] & 0x01;
+
+		slvt_unfreeze_reg(tnr_dmd);
+	}
+
+	if (issy_on_data) {
+		if ((ep_ck_deno == 0) || (ep_ck_nume == 0) ||
+		    (ep_ck_deno >= ep_ck_nume))
+			return CXD2880_RESULT_ERROR_HW_STATE;
+	}
+
+	{
+		u32 ick_x100;
+		u32 div = 0;
+		u32 Q = 0;
+		u32 R = 0;
+
+		switch (tnr_dmd->clk_mode) {
+		case CXD2880_TNRDMD_CLOCKMODE_A:
+			ick_x100 = 8228;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_B:
+			ick_x100 = 9330;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_C:
+			ick_x100 = 9600;
+			break;
+		default:
+			return CXD2880_RESULT_ERROR_SW_STATE;
+		}
+
+		div = rd_smooth_dp;
+
+		Q = ick_x100 * 262144U / div;
+		R = ick_x100 * 262144U % div;
+
+		R *= 5U;
+		Q = Q * 5 + R / div;
+		R = R % div;
+
+		R *= 2U;
+		Q = Q * 2 + R / div;
+		R = R % div;
+
+		if (div / 2 <= R)
+			*ts_rate_kbps = Q + 1;
+		else
+			*ts_rate_kbps = Q;
+	}
+
+	if (issy_on_data) {
+		u32 diff = ep_ck_nume - ep_ck_deno;
+
+		while (diff > 0x7FFF) {
+			diff >>= 1;
+			ep_ck_nume >>= 1;
+		}
+
+		*ts_rate_kbps -=
+		    (*ts_rate_kbps * diff + ep_ck_nume / 2) / ep_ck_nume;
+	}
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_per(struct cxd2880_tnrdmd *tnr_dmd,
+					      u32 *per)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	u32 packet_error = 0;
+	u32 period = 0;
+
+	if (!tnr_dmd || !per)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	{
+		u8 rdata[3];
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x0B) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x18, rdata,
+					   3) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if ((rdata[0] & 0x01) == 0)
+			return CXD2880_RESULT_ERROR_HW_STATE;
+
+		packet_error = (rdata[1] << 8) | rdata[2];
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x24) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0xDC, rdata,
+					   1) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		period = 1U << (rdata[0] & 0x0F);
+	}
+
+	if ((period == 0) || (packet_error > period))
+		return CXD2880_RESULT_ERROR_HW_STATE;
+
+	{
+		u32 div = 0;
+		u32 Q = 0;
+		u32 R = 0;
+
+		div = period;
+
+		Q = (packet_error * 1000) / div;
+		R = (packet_error * 1000) % div;
+
+		R *= 1000;
+		Q = Q * 1000 + R / div;
+		R = R % div;
+
+		if ((div != 1) && (div / 2 <= R))
+			*per = Q + 1;
+		else
+			*per = Q;
+	}
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_qam(struct cxd2880_tnrdmd *tnr_dmd,
+					      enum cxd2880_dvbt2_plp_btype type,
+					      enum cxd2880_dvbt2_plp_constell
+					      *qam)
+{
+	u8 data;
+	u8 l1_post_ok = 0;
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!qam))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x0B) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x86, &l1_post_ok,
+				   1) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (!(l1_post_ok & 0x01)) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return CXD2880_RESULT_ERROR_HW_STATE;
+	}
+
+	if (type == CXD2880_DVBT2_PLP_COMMON) {
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0xB6, &data,
+					   1) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (data == 0) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_HW_STATE;
+		}
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0xB1, &data,
+					   1) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+	} else {
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x9E, &data,
+					   1) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+	}
+
+	slvt_unfreeze_reg(tnr_dmd);
+
+	*qam = (enum cxd2880_dvbt2_plp_constell)(data & 0x07);
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_code_rate(struct cxd2880_tnrdmd
+						    *tnr_dmd,
+						    enum cxd2880_dvbt2_plp_btype
+						    type,
+						    enum
+						    cxd2880_dvbt2_plp_code_rate
+						    *code_rate)
+{
+	u8 data;
+	u8 l1_post_ok = 0;
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!code_rate))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x0B) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x86, &l1_post_ok,
+				   1) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (!(l1_post_ok & 0x01)) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return CXD2880_RESULT_ERROR_HW_STATE;
+	}
+
+	if (type == CXD2880_DVBT2_PLP_COMMON) {
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0xB6, &data,
+					   1) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (data == 0) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_HW_STATE;
+		}
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0xB0, &data,
+					   1) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+	} else {
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x9D, &data,
+					   1) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+	}
+
+	slvt_unfreeze_reg(tnr_dmd);
+
+	*code_rate = (enum cxd2880_dvbt2_plp_code_rate)(data & 0x07);
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_profile(struct cxd2880_tnrdmd
+						  *tnr_dmd,
+						  enum cxd2880_dvbt2_profile
+						  *profile)
+{
+	if ((!tnr_dmd) || (!profile))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x0B) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	{
+		u8 data;
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x22, &data,
+					   sizeof(data)) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (data & 0x02) {
+			if (data & 0x01)
+				*profile = CXD2880_DVBT2_PROFILE_LITE;
+			else
+				*profile = CXD2880_DVBT2_PROFILE_BASE;
+		} else {
+			enum cxd2880_ret ret = CXD2880_RESULT_ERROR_HW_STATE;
+
+			if (tnr_dmd->diver_mode ==
+			    CXD2880_TNRDMD_DIVERMODE_MAIN)
+				ret =
+				    cxd2880_tnrdmd_dvbt2_mon_profile(
+					tnr_dmd->diver_sub, profile);
+
+			return ret;
+		}
+	}
+
+	return CXD2880_RESULT_OK;
+}
+
+static enum cxd2880_ret dvbt2_calc_sdi(struct cxd2880_tnrdmd *tnr_dmd,
+				       int rf_lvl, u8 *ssi)
+{
+	enum cxd2880_dvbt2_plp_constell qam;
+	enum cxd2880_dvbt2_plp_code_rate code_rate;
+	int prel;
+	int temp_ssi = 0;
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	static const int ref_dbm_1000[4][8] = {
+		{-96000, -95000, -94000, -93000, -92000, -92000, -98000,
+		 -97000},
+		{-91000, -89000, -88000, -87000, -86000, -86000, -93000,
+		 -92000},
+		{-86000, -85000, -83000, -82000, -81000, -80000, -89000,
+		 -88000},
+		{-82000, -80000, -78000, -76000, -75000, -74000, -86000,
+		 -84000},
+	};
+
+	if ((!tnr_dmd) || (!ssi))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_qam(tnr_dmd, CXD2880_DVBT2_PLP_DATA, &qam);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_code_rate(tnr_dmd, CXD2880_DVBT2_PLP_DATA,
+					       &code_rate);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if ((code_rate > CXD2880_DVBT2_R2_5) || (qam > CXD2880_DVBT2_QAM256))
+		return CXD2880_RESULT_ERROR_OTHER;
+
+	prel = rf_lvl - ref_dbm_1000[qam][code_rate];
+
+	if (prel < -15000)
+		temp_ssi = 0;
+	else if (prel < 0)
+		temp_ssi = ((2 * (prel + 15000)) + 1500) / 3000;
+	else if (prel < 20000)
+		temp_ssi = (((4 * prel) + 500) / 1000) + 10;
+	else if (prel < 35000)
+		temp_ssi = (((2 * (prel - 20000)) + 1500) / 3000) + 90;
+	else
+		temp_ssi = 100;
+
+	*ssi = (temp_ssi > 100) ? 100 : (u8)temp_ssi;
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
+					      u8 *ssi)
+{
+	int rf_lvl = 0;
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!ssi))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd, &rf_lvl);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	ret = dvbt2_calc_sdi(tnr_dmd, rf_lvl, ssi);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ssi_sub(struct cxd2880_tnrdmd
+						  *tnr_dmd, u8 *ssi)
+{
+	int rf_lvl = 0;
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!ssi))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	ret = dvbt2_calc_sdi(tnr_dmd, rf_lvl, ssi);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	return ret;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h
new file mode 100644
index 000000000000..784ad2844d1b
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h
@@ -0,0 +1,170 @@
+/*
+ * cxd2880_tnrdmd_dvbt2_mon.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * DVB-T2 monitor interface
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_TNRDMD_DVBT2_MON_H
+#define CXD2880_TNRDMD_DVBT2_MON_H
+
+#include "cxd2880_tnrdmd.h"
+#include "cxd2880_dvbt2.h"
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_tnrdmd
+						    *tnr_dmd, u8 *sync_stat,
+						    u8 *ts_lock_stat,
+						    u8 *unlock_detected);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(struct cxd2880_tnrdmd
+							*tnr_dmd,
+							u8 *sync_stat,
+							u8 *unlock_detected);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_carrier_offset(struct cxd2880_tnrdmd
+							 *tnr_dmd, int *offset);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_carrier_offset_sub(struct
+							     cxd2880_tnrdmd
+							     *tnr_dmd,
+							     int *offset);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_l1_pre(struct cxd2880_tnrdmd *tnr_dmd,
+						 struct cxd2880_dvbt2_l1pre
+						 *l1_pre);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_version(struct cxd2880_tnrdmd
+						  *tnr_dmd,
+						  enum cxd2880_dvbt2_version
+						  *ver);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ofdm(struct cxd2880_tnrdmd *tnr_dmd,
+					       struct cxd2880_dvbt2_ofdm *ofdm);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_tnrdmd
+						    *tnr_dmd, u8 *plp_ids,
+						    u8 *num_plps);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_active_plp(struct cxd2880_tnrdmd
+						     *tnr_dmd,
+						     enum
+						     cxd2880_dvbt2_plp_btype
+						     type,
+						     struct cxd2880_dvbt2_plp
+						     *plp_info);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_data_plp_error(struct cxd2880_tnrdmd
+							 *tnr_dmd,
+							 u8 *plp_error);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_l1_change(struct cxd2880_tnrdmd
+						    *tnr_dmd, u8 *l1_change);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_l1_post(struct cxd2880_tnrdmd
+						  *tnr_dmd,
+						  struct cxd2880_dvbt2_l1post
+						  *l1_post);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_bbheader(struct cxd2880_tnrdmd
+						   *tnr_dmd,
+						   enum cxd2880_dvbt2_plp_btype
+						   type,
+						   struct cxd2880_dvbt2_bbheader
+						   *bbheader);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_in_bandb_ts_rate(struct cxd2880_tnrdmd
+						   *tnr_dmd,
+						   enum
+						   cxd2880_dvbt2_plp_btype
+						   type,
+						   u32 *ts_rate_bps);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(struct cxd2880_tnrdmd
+						 *tnr_dmd,
+						 enum
+						 cxd2880_tnrdmd_spectrum_sense
+						 *sense);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
+					      int *snr);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_snr_diver(struct cxd2880_tnrdmd
+						    *tnr_dmd, int *snr,
+						    int *snr_main,
+						    int *snr_sub);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_pre_ldpcber(struct cxd2880_tnrdmd
+						      *tnr_dmd, u32 *ber);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_post_bchfer(struct cxd2880_tnrdmd
+						      *tnr_dmd, u32 *fer);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_pre_bchber(struct cxd2880_tnrdmd
+						     *tnr_dmd, u32 *ber);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_packet_error_number(struct
+							      cxd2880_tnrdmd
+							      *tnr_dmd,
+							      u32 *pen);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sampling_offset(struct cxd2880_tnrdmd
+							  *tnr_dmd, int *ppm);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct
+							      cxd2880_tnrdmd
+							      *tnr_dmd,
+							      int *ppm);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ts_rate(struct cxd2880_tnrdmd
+						  *tnr_dmd, u32 *ts_rate_kbps);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_quality(struct cxd2880_tnrdmd
+						  *tnr_dmd, u8 *quality);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_per(struct cxd2880_tnrdmd *tnr_dmd,
+					      u32 *per);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_qam(struct cxd2880_tnrdmd *tnr_dmd,
+					      enum cxd2880_dvbt2_plp_btype type,
+					      enum cxd2880_dvbt2_plp_constell
+					      *qam);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_code_rate(struct cxd2880_tnrdmd
+						    *tnr_dmd,
+						    enum cxd2880_dvbt2_plp_btype
+						    type,
+						    enum
+						    cxd2880_dvbt2_plp_code_rate
+						    *code_rate);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_profile(struct cxd2880_tnrdmd
+						  *tnr_dmd,
+						  enum cxd2880_dvbt2_profile
+						  *profile);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
+					      u8 *ssi);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ssi_sub(struct cxd2880_tnrdmd
+						  *tnr_dmd, u8 *ssi);
+
+#endif
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v2 11/15] [media] cxd2880: Add DVB-T2 control functions for the driver
From: Yasunari.Takiguchi @ 2017-04-14  2:38 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-media
  Cc: tbird20d, frowand.list, Yasunari Takiguchi, Masayuki Yamamoto,
	Hideki Nozawa, Kota Yonezawa, Toshihiko Matsumoto,
	Satoshi Watanabe
In-Reply-To: <20170414015043.16731-1-Yasunari.Takiguchi@sony.com>

From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

Provide definitions, interfaces and functions needed for DVB-T2
of the Sony CXD2880 DVB-T2/T tuner + demodulator driver.

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
---
 .../media/dvb-frontends/cxd2880/cxd2880_dvbt2.h    |  402 ++++++
 .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c   | 1309 ++++++++++++++++++++
 .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h   |   82 ++
 3 files changed, 1793 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h

diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
new file mode 100644
index 000000000000..1870398cba9d
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
@@ -0,0 +1,402 @@
+/*
+ * cxd2880_dvbt2.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * DVB-T2 related definitions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_DVBT2_H
+#define CXD2880_DVBT2_H
+
+#include "cxd2880_common.h"
+
+enum cxd2880_dvbt2_profile {
+	CXD2880_DVBT2_PROFILE_BASE,
+	CXD2880_DVBT2_PROFILE_LITE,
+	CXD2880_DVBT2_PROFILE_ANY
+};
+
+enum cxd2880_dvbt2_version {
+	CXD2880_DVBT2_V111,
+	CXD2880_DVBT2_V121,
+	CXD2880_DVBT2_V131
+};
+
+enum cxd2880_dvbt2_s1 {
+	CXD2880_DVBT2_S1_BASE_SISO = 0x00,
+	CXD2880_DVBT2_S1_BASE_MISO = 0x01,
+	CXD2880_DVBT2_S1_NON_DVBT2 = 0x02,
+	CXD2880_DVBT2_S1_LITE_SISO = 0x03,
+	CXD2880_DVBT2_S1_LITE_MISO = 0x04,
+	CXD2880_DVBT2_S1_RSVD3 = 0x05,
+	CXD2880_DVBT2_S1_RSVD4 = 0x06,
+	CXD2880_DVBT2_S1_RSVD5 = 0x07,
+	CXD2880_DVBT2_S1_UNKNOWN = 0xFF
+};
+
+enum cxd2880_dvbt2_base_s2 {
+	CXD2880_DVBT2_BASE_S2_M2K_G_ANY = 0x00,
+	CXD2880_DVBT2_BASE_S2_M8K_G_DVBT = 0x01,
+	CXD2880_DVBT2_BASE_S2_M4K_G_ANY = 0x02,
+	CXD2880_DVBT2_BASE_S2_M1K_G_ANY = 0x03,
+	CXD2880_DVBT2_BASE_S2_M16K_G_ANY = 0x04,
+	CXD2880_DVBT2_BASE_S2_M32K_G_DVBT = 0x05,
+	CXD2880_DVBT2_BASE_S2_M8K_G_DVBT2 = 0x06,
+	CXD2880_DVBT2_BASE_S2_M32K_G_DVBT2 = 0x07,
+	CXD2880_DVBT2_BASE_S2_UNKNOWN = 0xFF
+};
+
+enum cxd2880_dvbt2_lite_s2 {
+	CXD2880_DVBT2_LITE_S2_M2K_G_ANY = 0x00,
+	CXD2880_DVBT2_LITE_S2_M8K_G_DVBT = 0x01,
+	CXD2880_DVBT2_LITE_S2_M4K_G_ANY = 0x02,
+	CXD2880_DVBT2_LITE_S2_M16K_G_DVBT2 = 0x03,
+	CXD2880_DVBT2_LITE_S2_M16K_G_DVBT = 0x04,
+	CXD2880_DVBT2_LITE_S2_RSVD1 = 0x05,
+	CXD2880_DVBT2_LITE_S2_M8K_G_DVBT2 = 0x06,
+	CXD2880_DVBT2_LITE_S2_RSVD2 = 0x07,
+	CXD2880_DVBT2_LITE_S2_UNKNOWN = 0xFF
+};
+
+enum cxd2880_dvbt2_guard {
+	CXD2880_DVBT2_G1_32 = 0x00,
+	CXD2880_DVBT2_G1_16 = 0x01,
+	CXD2880_DVBT2_G1_8 = 0x02,
+	CXD2880_DVBT2_G1_4 = 0x03,
+	CXD2880_DVBT2_G1_128 = 0x04,
+	CXD2880_DVBT2_G19_128 = 0x05,
+	CXD2880_DVBT2_G19_256 = 0x06,
+	CXD2880_DVBT2_G_RSVD1 = 0x07,
+	CXD2880_DVBT2_G_UNKNOWN = 0xFF
+};
+
+enum cxd2880_dvbt2_mode {
+	CXD2880_DVBT2_M2K = 0x00,
+	CXD2880_DVBT2_M8K = 0x01,
+	CXD2880_DVBT2_M4K = 0x02,
+	CXD2880_DVBT2_M1K = 0x03,
+	CXD2880_DVBT2_M16K = 0x04,
+	CXD2880_DVBT2_M32K = 0x05,
+	CXD2880_DVBT2_M_RSVD1 = 0x06,
+	CXD2880_DVBT2_M_RSVD2 = 0x07
+};
+
+enum cxd2880_dvbt2_bw {
+	CXD2880_DVBT2_BW_8 = 0x00,
+	CXD2880_DVBT2_BW_7 = 0x01,
+	CXD2880_DVBT2_BW_6 = 0x02,
+	CXD2880_DVBT2_BW_5 = 0x03,
+	CXD2880_DVBT2_BW_10 = 0x04,
+	CXD2880_DVBT2_BW_1_7 = 0x05,
+	CXD2880_DVBT2_BW_RSVD1 = 0x06,
+	CXD2880_DVBT2_BW_RSVD2 = 0x07,
+	CXD2880_DVBT2_BW_RSVD3 = 0x08,
+	CXD2880_DVBT2_BW_RSVD4 = 0x09,
+	CXD2880_DVBT2_BW_RSVD5 = 0x0A,
+	CXD2880_DVBT2_BW_RSVD6 = 0x0B,
+	CXD2880_DVBT2_BW_RSVD7 = 0x0C,
+	CXD2880_DVBT2_BW_RSVD8 = 0x0D,
+	CXD2880_DVBT2_BW_RSVD9 = 0x0E,
+	CXD2880_DVBT2_BW_RSVD10 = 0x0F,
+	CXD2880_DVBT2_BW_UNKNOWN = 0xFF
+};
+
+enum cxd2880_dvbt2_l1pre_type {
+	CXD2880_DVBT2_L1PRE_TYPE_TS = 0x00,
+	CXD2880_DVBT2_L1PRE_TYPE_GS = 0x01,
+	CXD2880_DVBT2_L1PRE_TYPE_TS_GS = 0x02,
+	CXD2880_DVBT2_L1PRE_TYPE_RESERVED = 0x03,
+	CXD2880_DVBT2_L1PRE_TYPE_UNKNOWN = 0xFF
+};
+
+enum cxd2880_dvbt2_papr {
+	CXD2880_DVBT2_PAPR_0 = 0x00,
+	CXD2880_DVBT2_PAPR_1 = 0x01,
+	CXD2880_DVBT2_PAPR_2 = 0x02,
+	CXD2880_DVBT2_PAPR_3 = 0x03,
+	CXD2880_DVBT2_PAPR_RSVD1 = 0x04,
+	CXD2880_DVBT2_PAPR_RSVD2 = 0x05,
+	CXD2880_DVBT2_PAPR_RSVD3 = 0x06,
+	CXD2880_DVBT2_PAPR_RSVD4 = 0x07,
+	CXD2880_DVBT2_PAPR_RSVD5 = 0x08,
+	CXD2880_DVBT2_PAPR_RSVD6 = 0x09,
+	CXD2880_DVBT2_PAPR_RSVD7 = 0x0A,
+	CXD2880_DVBT2_PAPR_RSVD8 = 0x0B,
+	CXD2880_DVBT2_PAPR_RSVD9 = 0x0C,
+	CXD2880_DVBT2_PAPR_RSVD10 = 0x0D,
+	CXD2880_DVBT2_PAPR_RSVD11 = 0x0E,
+	CXD2880_DVBT2_PAPR_RSVD12 = 0x0F,
+	CXD2880_DVBT2_PAPR_UNKNOWN = 0xFF
+};
+
+enum cxd2880_dvbt2_l1post_constell {
+	CXD2880_DVBT2_L1POST_BPSK = 0x00,
+	CXD2880_DVBT2_L1POST_QPSK = 0x01,
+	CXD2880_DVBT2_L1POST_QAM16 = 0x02,
+	CXD2880_DVBT2_L1POST_QAM64 = 0x03,
+	CXD2880_DVBT2_L1POST_C_RSVD1 = 0x04,
+	CXD2880_DVBT2_L1POST_C_RSVD2 = 0x05,
+	CXD2880_DVBT2_L1POST_C_RSVD3 = 0x06,
+	CXD2880_DVBT2_L1POST_C_RSVD4 = 0x07,
+	CXD2880_DVBT2_L1POST_C_RSVD5 = 0x08,
+	CXD2880_DVBT2_L1POST_C_RSVD6 = 0x09,
+	CXD2880_DVBT2_L1POST_C_RSVD7 = 0x0A,
+	CXD2880_DVBT2_L1POST_C_RSVD8 = 0x0B,
+	CXD2880_DVBT2_L1POST_C_RSVD9 = 0x0C,
+	CXD2880_DVBT2_L1POST_C_RSVD10 = 0x0D,
+	CXD2880_DVBT2_L1POST_C_RSVD11 = 0x0E,
+	CXD2880_DVBT2_L1POST_C_RSVD12 = 0x0F,
+	CXD2880_DVBT2_L1POST_CONSTELL_UNKNOWN = 0xFF
+};
+
+enum cxd2880_dvbt2_l1post_cr {
+	CXD2880_DVBT2_L1POST_R1_2 = 0x00,
+	CXD2880_DVBT2_L1POST_R_RSVD1 = 0x01,
+	CXD2880_DVBT2_L1POST_R_RSVD2 = 0x02,
+	CXD2880_DVBT2_L1POST_R_RSVD3 = 0x03,
+	CXD2880_DVBT2_L1POST_R_UNKNOWN = 0xFF
+};
+
+enum cxd2880_dvbt2_l1post_fec_type {
+	CXD2880_DVBT2_L1POST_FEC_LDPC16K = 0x00,
+	CXD2880_DVBT2_L1POST_FEC_RSVD1 = 0x01,
+	CXD2880_DVBT2_L1POST_FEC_RSVD2 = 0x02,
+	CXD2880_DVBT2_L1POST_FEC_RSVD3 = 0x03,
+	CXD2880_DVBT2_L1POST_FEC_UNKNOWN = 0xFF
+};
+
+enum cxd2880_dvbt2_pp {
+	CXD2880_DVBT2_PP1 = 0x00,
+	CXD2880_DVBT2_PP2 = 0x01,
+	CXD2880_DVBT2_PP3 = 0x02,
+	CXD2880_DVBT2_PP4 = 0x03,
+	CXD2880_DVBT2_PP5 = 0x04,
+	CXD2880_DVBT2_PP6 = 0x05,
+	CXD2880_DVBT2_PP7 = 0x06,
+	CXD2880_DVBT2_PP8 = 0x07,
+	CXD2880_DVBT2_PP_RSVD1 = 0x08,
+	CXD2880_DVBT2_PP_RSVD2 = 0x09,
+	CXD2880_DVBT2_PP_RSVD3 = 0x0A,
+	CXD2880_DVBT2_PP_RSVD4 = 0x0B,
+	CXD2880_DVBT2_PP_RSVD5 = 0x0C,
+	CXD2880_DVBT2_PP_RSVD6 = 0x0D,
+	CXD2880_DVBT2_PP_RSVD7 = 0x0E,
+	CXD2880_DVBT2_PP_RSVD8 = 0x0F,
+	CXD2880_DVBT2_PP_UNKNOWN = 0xFF
+};
+
+enum cxd2880_dvbt2_plp_code_rate {
+	CXD2880_DVBT2_R1_2 = 0x00,
+	CXD2880_DVBT2_R3_5 = 0x01,
+	CXD2880_DVBT2_R2_3 = 0x02,
+	CXD2880_DVBT2_R3_4 = 0x03,
+	CXD2880_DVBT2_R4_5 = 0x04,
+	CXD2880_DVBT2_R5_6 = 0x05,
+	CXD2880_DVBT2_R1_3 = 0x06,
+	CXD2880_DVBT2_R2_5 = 0x07,
+	CXD2880_DVBT2_PLP_CR_UNKNOWN = 0xFF
+};
+
+enum cxd2880_dvbt2_plp_constell {
+	CXD2880_DVBT2_QPSK = 0x00,
+	CXD2880_DVBT2_QAM16 = 0x01,
+	CXD2880_DVBT2_QAM64 = 0x02,
+	CXD2880_DVBT2_QAM256 = 0x03,
+	CXD2880_DVBT2_CON_RSVD1 = 0x04,
+	CXD2880_DVBT2_CON_RSVD2 = 0x05,
+	CXD2880_DVBT2_CON_RSVD3 = 0x06,
+	CXD2880_DVBT2_CON_RSVD4 = 0x07,
+	CXD2880_DVBT2_CONSTELL_UNKNOWN = 0xFF
+};
+
+enum cxd2880_dvbt2_plp_type {
+	CXD2880_DVBT2_PLP_TYPE_COMMON = 0x00,
+	CXD2880_DVBT2_PLP_TYPE_DATA1 = 0x01,
+	CXD2880_DVBT2_PLP_TYPE_DATA2 = 0x02,
+	CXD2880_DVBT2_PLP_TYPE_RSVD1 = 0x03,
+	CXD2880_DVBT2_PLP_TYPE_RSVD2 = 0x04,
+	CXD2880_DVBT2_PLP_TYPE_RSVD3 = 0x05,
+	CXD2880_DVBT2_PLP_TYPE_RSVD4 = 0x06,
+	CXD2880_DVBT2_PLP_TYPE_RSVD5 = 0x07,
+	CXD2880_DVBT2_PLP_TYPE_UNKNOWN = 0xFF
+};
+
+enum cxd2880_dvbt2_plp_payload {
+	CXD2880_DVBT2_PLP_PAYLOAD_GFPS = 0x00,
+	CXD2880_DVBT2_PLP_PAYLOAD_GCS = 0x01,
+	CXD2880_DVBT2_PLP_PAYLOAD_GSE = 0x02,
+	CXD2880_DVBT2_PLP_PAYLOAD_TS = 0x03,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD1 = 0x04,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD2 = 0x05,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD3 = 0x06,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD4 = 0x07,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD5 = 0x08,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD6 = 0x09,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD7 = 0x0A,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD8 = 0x0B,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD9 = 0x0C,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD10 = 0x0D,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD11 = 0x0E,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD12 = 0x0F,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD13 = 0x10,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD14 = 0x11,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD15 = 0x12,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD16 = 0x13,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD17 = 0x14,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD18 = 0x15,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD19 = 0x16,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD20 = 0x17,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD21 = 0x18,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD22 = 0x19,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD23 = 0x1A,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD24 = 0x1B,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD25 = 0x1C,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD26 = 0x1D,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD27 = 0x1E,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD28 = 0x1F,
+	CXD2880_DVBT2_PLP_PAYLOAD_UNKNOWN = 0xFF
+};
+
+enum cxd2880_dvbt2_plp_fec {
+	CXD2880_DVBT2_FEC_LDPC_16K = 0x00,
+	CXD2880_DVBT2_FEC_LDPC_64K = 0x01,
+	CXD2880_DVBT2_FEC_RSVD1 = 0x02,
+	CXD2880_DVBT2_FEC_RSVD2 = 0x03,
+	CXD2880_DVBT2_FEC_UNKNOWN = 0xFF
+};
+
+enum cxd2880_dvbt2_plp_mode {
+	CXD2880_DVBT2_PLP_MODE_NOTSPECIFIED = 0x00,
+	CXD2880_DVBT2_PLP_MODE_NM = 0x01,
+	CXD2880_DVBT2_PLP_MODE_HEM = 0x02,
+	CXD2880_DVBT2_PLP_MODE_RESERVED = 0x03,
+	CXD2880_DVBT2_PLP_MODE_UNKNOWN = 0xFF
+};
+
+enum cxd2880_dvbt2_plp_btype {
+	CXD2880_DVBT2_PLP_COMMON,
+	CXD2880_DVBT2_PLP_DATA
+};
+
+enum cxd2880_dvbt2_stream {
+	CXD2880_DVBT2_STREAM_GENERIC_PACKETIZED = 0x00,
+	CXD2880_DVBT2_STREAM_GENERIC_CONTINUOUS = 0x01,
+	CXD2880_DVBT2_STREAM_GENERIC_ENCAPSULATED = 0x02,
+	CXD2880_DVBT2_STREAM_TRANSPORT = 0x03,
+	CXD2880_DVBT2_STREAM_UNKNOWN = 0xFF
+};
+
+struct cxd2880_dvbt2_l1pre {
+	enum cxd2880_dvbt2_l1pre_type type;
+	u8 bw_ext;
+	enum cxd2880_dvbt2_s1 s1;
+	u8 s2;
+	u8 mixed;
+	enum cxd2880_dvbt2_mode fft_mode;
+	u8 l1_rep;
+	enum cxd2880_dvbt2_guard gi;
+	enum cxd2880_dvbt2_papr papr;
+	enum cxd2880_dvbt2_l1post_constell mod;
+	enum cxd2880_dvbt2_l1post_cr cr;
+	enum cxd2880_dvbt2_l1post_fec_type fec;
+	u32 l1_post_size;
+	u32 l1_post_info_size;
+	enum cxd2880_dvbt2_pp pp;
+	u8 tx_id_availability;
+	u16 cell_id;
+	u16 network_id;
+	u16 sys_id;
+	u8 num_frames;
+	u16 num_symbols;
+	u8 regen;
+	u8 post_ext;
+	u8 num_rf_freqs;
+	u8 rf_idx;
+	enum cxd2880_dvbt2_version t2_version;
+	u8 l1_post_scrambled;
+	u8 t2_base_lite;
+	u32 crc32;
+};
+
+struct cxd2880_dvbt2_plp {
+	u8 id;
+	enum cxd2880_dvbt2_plp_type type;
+	enum cxd2880_dvbt2_plp_payload payload;
+	u8 ff;
+	u8 first_rf_idx;
+	u8 first_frm_idx;
+	u8 group_id;
+	enum cxd2880_dvbt2_plp_constell constell;
+	enum cxd2880_dvbt2_plp_code_rate plp_cr;
+	u8 rot;
+	enum cxd2880_dvbt2_plp_fec fec;
+	u16 num_blocks_max;
+	u8 frm_int;
+	u8 til_len;
+	u8 til_type;
+	u8 in_band_a_flag;
+	u8 in_band_b_flag;
+	u16 rsvd;
+	enum cxd2880_dvbt2_plp_mode plp_mode;
+	u8 static_flag;
+	u8 static_padding_flag;
+};
+
+struct cxd2880_dvbt2_l1post {
+	u16 sub_slices_per_frame;
+	u8 num_plps;
+	u8 num_aux;
+	u8 aux_cfg_rfu;
+	u8 rf_idx;
+	u32 freq;
+	u8 fef_type;
+	u32 fef_length;
+	u8 fef_intvl;
+};
+
+struct cxd2880_dvbt2_ofdm {
+	u8 mixed;
+	u8 is_miso;
+	enum cxd2880_dvbt2_mode mode;
+	enum cxd2880_dvbt2_guard gi;
+	enum cxd2880_dvbt2_pp pp;
+	u8 bw_ext;
+	enum cxd2880_dvbt2_papr papr;
+	u16 num_symbols;
+};
+
+struct cxd2880_dvbt2_bbheader {
+	enum cxd2880_dvbt2_stream stream_input;
+	u8 is_single_input_stream;
+	u8 is_constant_coding_modulation;
+	u8 issy_indicator;
+	u8 null_packet_deletion;
+	u8 ext;
+	u8 input_stream_identifier;
+	u16 user_packet_length;
+	u16 data_field_length;
+	u8 sync_byte;
+	u32 issy;
+	enum cxd2880_dvbt2_plp_mode plp_mode;
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
new file mode 100644
index 000000000000..bdad65b7298a
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
@@ -0,0 +1,1309 @@
+/*
+ * cxd2880_tnrdmd_dvbt2.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * control functions for DVB-T2
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_tnrdmd_dvbt2.h"
+#include "cxd2880_tnrdmd_dvbt2_mon.h"
+
+static enum cxd2880_ret x_tune_dvbt2_demod_setting(struct cxd2880_tnrdmd
+						   *tnr_dmd,
+						   enum cxd2880_dtv_bandwidth
+						   bandwidth,
+						   enum cxd2880_tnrdmd_clockmode
+						   clk_mode)
+{
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x31,
+				   0x02) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x04) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x5D,
+				   0x0B) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
+		u8 data[2] = { 0x01, 0x01 };
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x00) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->write_regs(tnr_dmd->io,
+					    CXD2880_IO_TGT_DMD, 0xCE, data,
+					    2) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	}
+
+	{
+		u8 data[14] = { 0x07, 0x06, 0x01, 0xF0,
+			0x00, 0x00, 0x04, 0xB0, 0x00, 0x00, 0x09, 0x9C, 0x0E,
+			    0x4C
+		};
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x20) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x8A,
+					   data[0]) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x90,
+					   data[1]) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x25) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->write_regs(tnr_dmd->io,
+					    CXD2880_IO_TGT_DMD, 0xF0, &data[2],
+					    2) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x2A) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0xDC,
+					   data[4]) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0xDE,
+					   data[5]) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x2D) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->write_regs(tnr_dmd->io,
+					    CXD2880_IO_TGT_DMD, 0x73, &data[6],
+					    4) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->write_regs(tnr_dmd->io,
+					    CXD2880_IO_TGT_DMD, 0x8F, &data[10],
+					    4) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	}
+
+	{
+		u8 data_a_1[9] = { 0x52, 0x49, 0x2C, 0x51,
+			0x51, 0x3D, 0x15, 0x29, 0x0C
+		};
+		u8 data_b_1[9] = { 0x5D, 0x55, 0x32, 0x5C,
+			0x5C, 0x45, 0x17, 0x2E, 0x0D
+		};
+		u8 data_c_1[9] = { 0x60, 0x00, 0x34, 0x5E,
+			0x5E, 0x47, 0x18, 0x2F, 0x0E
+		};
+
+		u8 data_a_2[13] = { 0x04, 0xE7, 0x94, 0x92,
+			0x09, 0xCF, 0x7E, 0xD0, 0x49, 0xCD, 0xCD, 0x1F, 0x5B
+		};
+		u8 data_b_2[13] = { 0x05, 0x90, 0x27, 0x55,
+			0x0B, 0x20, 0x8F, 0xD6, 0xEA, 0xC8, 0xC8, 0x23, 0x91
+		};
+		u8 data_c_2[13] = { 0x05, 0xB8, 0xD8, 0x00,
+			0x0B, 0x72, 0x93, 0xF3, 0x00, 0xCD, 0xCD, 0x24, 0x95
+		};
+
+		u8 data_a_3[5] = { 0x0B, 0x6A, 0xC9, 0x03,
+			0x33
+		};
+		u8 data_b_3[5] = { 0x01, 0x02, 0xE4, 0x03,
+			0x39
+		};
+		u8 data_c_3[5] = { 0x01, 0x02, 0xEB, 0x03,
+			0x3B
+		};
+
+		u8 *data_1 = NULL;
+		u8 *data_2 = NULL;
+		u8 *data_3 = NULL;
+
+		switch (clk_mode) {
+		case CXD2880_TNRDMD_CLOCKMODE_A:
+			data_1 = data_a_1;
+			data_2 = data_a_2;
+			data_3 = data_a_3;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_B:
+			data_1 = data_b_1;
+			data_2 = data_b_2;
+			data_3 = data_b_3;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_C:
+			data_1 = data_c_1;
+			data_2 = data_c_2;
+			data_3 = data_c_3;
+			break;
+		default:
+			return CXD2880_RESULT_ERROR_SW_STATE;
+		}
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x04) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->write_regs(tnr_dmd->io,
+					    CXD2880_IO_TGT_DMD, 0x1D,
+					    &data_1[0], 3) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x22,
+					   data_1[3]) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x24,
+					   data_1[4]) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x26,
+					   data_1[5]) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->write_regs(tnr_dmd->io,
+					    CXD2880_IO_TGT_DMD, 0x29,
+					    &data_1[6], 2) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x2D,
+					   data_1[8]) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x2E,
+						    &data_2[0],
+						    6) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x35,
+						    &data_2[6],
+						    7) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->io->write_regs(tnr_dmd->io,
+					    CXD2880_IO_TGT_DMD, 0x3C,
+					    &data_3[0], 2) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->write_regs(tnr_dmd->io,
+					    CXD2880_IO_TGT_DMD, 0x56,
+					    &data_3[2], 3) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	}
+
+	switch (bandwidth) {
+	case CXD2880_DTV_BW_8_MHZ:
+
+		{
+			u8 data_ac[6] = { 0x15, 0x00, 0x00, 0x00,
+				0x00, 0x00
+			};
+			u8 data_b[6] = { 0x14, 0x6A, 0xAA, 0xAA,
+				0xAB, 0x00
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_ac;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x10,
+						    data,
+						    6) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x4A,
+					   0x00) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		{
+			u8 data_a[2] = { 0x19, 0xD2 };
+			u8 data_bc[2] = { 0x3F, 0xFF };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_bc;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x19,
+						    data,
+						    2) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		{
+			u8 data_a[2] = { 0x06, 0x2A };
+			u8 data_b[2] = { 0x06, 0x29 };
+			u8 data_c[2] = { 0x06, 0x28 };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x1B,
+						    data,
+						    2) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			u8 data_a[9] = { 0x28, 0x00, 0x50, 0x00,
+				0x60, 0x00, 0x00, 0x90, 0x00
+			};
+			u8 data_b[9] = { 0x2D, 0x5E, 0x5A, 0xBD,
+				0x6C, 0xE3, 0x00, 0xA3, 0x55
+			};
+			u8 data_c[9] = { 0x2E, 0xAA, 0x5D, 0x55,
+				0x70, 0x00, 0x00, 0xA8, 0x00
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x4B,
+						    data,
+						    9) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+		break;
+
+	case CXD2880_DTV_BW_7_MHZ:
+
+		{
+			u8 data_ac[6] = { 0x18, 0x00, 0x00, 0x00,
+				0x00, 0x00
+			};
+			u8 data_b[6] = { 0x17, 0x55, 0x55, 0x55,
+				0x55, 0x00
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_ac;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x10,
+						    data,
+						    6) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x4A,
+					   0x02) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		{
+			u8 data[2] = { 0x3F, 0xFF };
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x19,
+						    data,
+						    2) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		{
+			u8 data_a[2] = { 0x06, 0x23 };
+			u8 data_b[2] = { 0x06, 0x22 };
+			u8 data_c[2] = { 0x06, 0x21 };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x1B,
+						    data,
+						    2) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			u8 data_a[9] = { 0x2D, 0xB6, 0x5B, 0x6D,
+				0x6D, 0xB6, 0x00, 0xA4, 0x92
+			};
+			u8 data_b[9] = { 0x33, 0xDA, 0x67, 0xB4,
+				0x7C, 0x71, 0x00, 0xBA, 0xAA
+			};
+			u8 data_c[9] = { 0x35, 0x55, 0x6A, 0xAA,
+				0x80, 0x00, 0x00, 0xC0, 0x00
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x4B,
+						    data,
+						    9) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+		break;
+
+	case CXD2880_DTV_BW_6_MHZ:
+
+		{
+			u8 data_ac[6] = { 0x1C, 0x00, 0x00, 0x00,
+				0x00, 0x00
+			};
+			u8 data_b[6] = { 0x1B, 0x38, 0xE3, 0x8E,
+				0x39, 0x00
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_ac;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x10,
+						    data,
+						    6) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x4A,
+					   0x04) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		{
+			u8 data[2] = { 0x3F, 0xFF };
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x19,
+						    data,
+						    2) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		{
+			u8 data_a[2] = { 0x06, 0x1C };
+			u8 data_b[2] = { 0x06, 0x1B };
+			u8 data_c[2] = { 0x06, 0x1A };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x1B,
+						    data,
+						    2) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			u8 data_a[9] = { 0x35, 0x55, 0x6A, 0xAA,
+				0x80, 0x00, 0x00, 0xC0, 0x00
+			};
+			u8 data_b[9] = { 0x3C, 0x7E, 0x78, 0xFC,
+				0x91, 0x2F, 0x00, 0xD9, 0xC7
+			};
+			u8 data_c[9] = { 0x3E, 0x38, 0x7C, 0x71,
+				0x95, 0x55, 0x00, 0xDF, 0xFF
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x4B,
+						    data,
+						    9) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+		break;
+
+	case CXD2880_DTV_BW_5_MHZ:
+
+		{
+			u8 data_ac[6] = { 0x21, 0x99, 0x99, 0x99,
+				0x9A, 0x00
+			};
+			u8 data_b[6] = { 0x20, 0xAA, 0xAA, 0xAA,
+				0xAB, 0x00
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_ac;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x10,
+						    data,
+						    6) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x4A,
+					   0x06) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		{
+			u8 data[2] = { 0x3F, 0xFF };
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x19,
+						    data,
+						    2) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		{
+			u8 data_a[2] = { 0x06, 0x15 };
+			u8 data_b[2] = { 0x06, 0x15 };
+			u8 data_c[2] = { 0x06, 0x14 };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x1B,
+						    data,
+						    2) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			u8 data_a[9] = { 0x40, 0x00, 0x6A, 0xAA,
+				0x80, 0x00, 0x00, 0xE6, 0x66
+			};
+			u8 data_b[9] = { 0x48, 0x97, 0x78, 0xFC,
+				0x91, 0x2F, 0x01, 0x05, 0x55
+			};
+			u8 data_c[9] = { 0x4A, 0xAA, 0x7C, 0x71,
+				0x95, 0x55, 0x01, 0x0C, 0xCC
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x4B,
+						    data,
+						    9) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+		break;
+
+	case CXD2880_DTV_BW_1_7_MHZ:
+
+		{
+			u8 data_a[6] = { 0x68, 0x0F, 0xA2, 0x32,
+				0xCF, 0x03
+			};
+			u8 data_c[6] = { 0x68, 0x0F, 0xA2, 0x32,
+				0xCF, 0x03
+			};
+			u8 data_b[6] = { 0x65, 0x2B, 0xA4, 0xCD,
+				0xD8, 0x03
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x10,
+						    data,
+						    6) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x4A,
+					   0x03) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		{
+			u8 data[2] = { 0x3F, 0xFF };
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x19,
+						    data,
+						    2) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		{
+			u8 data_a[2] = { 0x06, 0x0C };
+			u8 data_b[2] = { 0x06, 0x0C };
+			u8 data_c[2] = { 0x06, 0x0B };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x1B,
+						    data,
+						    2) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			u8 data_a[9] = { 0x40, 0x00, 0x6A, 0xAA,
+				0x80, 0x00, 0x02, 0xC9, 0x8F
+			};
+			u8 data_b[9] = { 0x48, 0x97, 0x78, 0xFC,
+				0x91, 0x2F, 0x03, 0x29, 0x5D
+			};
+			u8 data_c[9] = { 0x4A, 0xAA, 0x7C, 0x71,
+				0x95, 0x55, 0x03, 0x40, 0x7D
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x4B,
+						    data,
+						    9) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+		break;
+
+	default:
+		return CXD2880_RESULT_ERROR_SW_STATE;
+	}
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0xFD,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	return CXD2880_RESULT_OK;
+}
+
+static enum cxd2880_ret x_sleep_dvbt2_demod_setting(struct cxd2880_tnrdmd
+						    *tnr_dmd)
+{
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		u8 data[] = { 0, 1, 0, 2,
+			0, 4, 0, 8, 0, 16, 0, 32
+		};
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x1D) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->write_regs(tnr_dmd->io,
+					    CXD2880_IO_TGT_DMD, 0x47, data,
+					    12) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	}
+
+	return CXD2880_RESULT_OK;
+}
+
+static enum cxd2880_ret dvbt2_set_profile(struct cxd2880_tnrdmd *tnr_dmd,
+					  enum cxd2880_dvbt2_profile profile)
+{
+	u8 t2_mode_tune_mode = 0;
+	u8 seq_not2_dtime = 0;
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	{
+		u8 dtime1 = 0;
+		u8 dtime2 = 0;
+
+		switch (tnr_dmd->clk_mode) {
+		case CXD2880_TNRDMD_CLOCKMODE_A:
+			dtime1 = 0x27;
+			dtime2 = 0x0C;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_B:
+			dtime1 = 0x2C;
+			dtime2 = 0x0D;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_C:
+			dtime1 = 0x2E;
+			dtime2 = 0x0E;
+			break;
+		default:
+			return CXD2880_RESULT_ERROR_SW_STATE;
+		}
+
+		switch (profile) {
+		case CXD2880_DVBT2_PROFILE_BASE:
+			t2_mode_tune_mode = 0x01;
+			seq_not2_dtime = dtime2;
+			break;
+
+		case CXD2880_DVBT2_PROFILE_LITE:
+			t2_mode_tune_mode = 0x05;
+			seq_not2_dtime = dtime1;
+			break;
+
+		case CXD2880_DVBT2_PROFILE_ANY:
+			t2_mode_tune_mode = 0x00;
+			seq_not2_dtime = dtime1;
+			break;
+
+		default:
+			return CXD2880_RESULT_ERROR_ARG;
+		}
+	}
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x2E) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x10,
+				   t2_mode_tune_mode) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x04) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x2C,
+				   seq_not2_dtime) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_tune1(struct cxd2880_tnrdmd *tnr_dmd,
+					    struct cxd2880_dvbt2_tune_param
+					    *tune_param)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!tune_param))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if ((tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) &&
+	    (tune_param->profile == CXD2880_DVBT2_PROFILE_ANY))
+		return CXD2880_RESULT_ERROR_NOSUPPORT;
+
+	ret =
+	    cxd2880_tnrdmd_common_tune_setting1(tnr_dmd, CXD2880_DTV_SYS_DVBT2,
+						tune_param->center_freq_khz,
+						tune_param->bandwidth, 0, 0);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	ret =
+	    x_tune_dvbt2_demod_setting(tnr_dmd, tune_param->bandwidth,
+				       tnr_dmd->clk_mode);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret =
+		    x_tune_dvbt2_demod_setting(tnr_dmd->diver_sub,
+					       tune_param->bandwidth,
+					       tnr_dmd->diver_sub->clk_mode);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	}
+
+	ret = dvbt2_set_profile(tnr_dmd, tune_param->profile);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret =
+		    dvbt2_set_profile(tnr_dmd->diver_sub, tune_param->profile);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	}
+
+	if (tune_param->data_plp_id == CXD2880_DVBT2_TUNE_PARAM_PLPID_AUTO) {
+		ret = cxd2880_tnrdmd_dvbt2_set_plp_cfg(tnr_dmd, 1, 0);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	} else {
+		ret =
+		    cxd2880_tnrdmd_dvbt2_set_plp_cfg(tnr_dmd, 0,
+					     (u8)(tune_param->data_plp_id));
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	}
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_tune2(struct cxd2880_tnrdmd *tnr_dmd,
+					    struct cxd2880_dvbt2_tune_param
+					    *tune_param)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!tune_param))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	{
+		u8 en_fef_intmtnt_ctrl = 1;
+
+		switch (tune_param->profile) {
+		case CXD2880_DVBT2_PROFILE_BASE:
+			en_fef_intmtnt_ctrl = tnr_dmd->en_fef_intmtnt_base;
+			break;
+		case CXD2880_DVBT2_PROFILE_LITE:
+			en_fef_intmtnt_ctrl = tnr_dmd->en_fef_intmtnt_lite;
+			break;
+		case CXD2880_DVBT2_PROFILE_ANY:
+			if (tnr_dmd->en_fef_intmtnt_base &&
+			    tnr_dmd->en_fef_intmtnt_lite)
+				en_fef_intmtnt_ctrl = 1;
+			else
+				en_fef_intmtnt_ctrl = 0;
+			break;
+		default:
+			return CXD2880_RESULT_ERROR_ARG;
+		}
+
+		ret =
+		    cxd2880_tnrdmd_common_tune_setting2(tnr_dmd,
+							CXD2880_DTV_SYS_DVBT2,
+							en_fef_intmtnt_ctrl);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	}
+
+	tnr_dmd->state = CXD2880_TNRDMD_STATE_ACTIVE;
+	tnr_dmd->frequency_khz = tune_param->center_freq_khz;
+	tnr_dmd->sys = CXD2880_DTV_SYS_DVBT2;
+	tnr_dmd->bandwidth = tune_param->bandwidth;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_ACTIVE;
+		tnr_dmd->diver_sub->frequency_khz = tune_param->center_freq_khz;
+		tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_DVBT2;
+		tnr_dmd->diver_sub->bandwidth = tune_param->bandwidth;
+	}
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_sleep_setting(struct cxd2880_tnrdmd
+						    *tnr_dmd)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	ret = x_sleep_dvbt2_demod_setting(tnr_dmd);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = x_sleep_dvbt2_demod_setting(tnr_dmd->diver_sub);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	}
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd
+					       *tnr_dmd,
+					       enum
+					       cxd2880_tnrdmd_lock_result
+					       *lock)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	u8 sync_stat = 0;
+	u8 ts_lock = 0;
+	u8 unlock_detected = 0;
+	u8 unlock_detected_sub = 0;
+
+	if ((!tnr_dmd) || (!lock))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
+					       &unlock_detected);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
+		if (sync_stat == 6)
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+		else if (unlock_detected)
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+		else
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+		return ret;
+	}
+
+	if (sync_stat == 6) {
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+		return ret;
+	}
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(tnr_dmd, &sync_stat,
+						   &unlock_detected_sub);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if (sync_stat == 6)
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+	else if (unlock_detected && unlock_detected_sub)
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+	else
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd
+						    *tnr_dmd,
+						    enum
+						    cxd2880_tnrdmd_lock_result
+						    *lock)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	u8 sync_stat = 0;
+	u8 ts_lock = 0;
+	u8 unlock_detected = 0;
+	u8 unlock_detected_sub = 0;
+
+	if ((!tnr_dmd) || (!lock))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
+					       &unlock_detected);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
+		if (ts_lock)
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+		else if (unlock_detected)
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+		else
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+		return ret;
+	}
+
+	if (ts_lock) {
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+		return ret;
+	} else if (!unlock_detected) {
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+		return ret;
+	}
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(tnr_dmd, &sync_stat,
+						   &unlock_detected_sub);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if (unlock_detected && unlock_detected_sub)
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+	else
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd
+						  *tnr_dmd, u8 auto_plp,
+						  u8 plp_id)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x23) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (!auto_plp) {
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0xAF,
+					   plp_id) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0xAD,
+				   auto_plp ? 0x00 : 0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_diver_fef_setting(struct cxd2880_tnrdmd
+							*tnr_dmd)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE)
+		return CXD2880_RESULT_OK;
+
+	{
+		struct cxd2880_dvbt2_ofdm ofdm;
+
+		ret = cxd2880_tnrdmd_dvbt2_mon_ofdm(tnr_dmd, &ofdm);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		if (!ofdm.mixed)
+			return CXD2880_RESULT_OK;
+	}
+
+	{
+		u8 data[] = { 0, 8, 0, 16,
+			0, 32, 0, 64, 0, 128, 1, 0
+		};
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x1D) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->write_regs(tnr_dmd->io,
+					    CXD2880_IO_TGT_DMD, 0x47, data,
+					    12) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	}
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_check_l1post_valid(struct cxd2880_tnrdmd
+							 *tnr_dmd,
+							 u8 *l1_post_valid)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	u8 data;
+
+	if ((!tnr_dmd) || (!l1_post_valid))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x0B) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x86, &data,
+				   1) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	*l1_post_valid = data & 0x01;
+
+	return ret;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h
new file mode 100644
index 000000000000..8735280f0143
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h
@@ -0,0 +1,82 @@
+/*
+ * cxd2880_tnrdmd_dvbt2.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * control interface for DVB-T2
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_TNRDMD_DVBT2_H
+#define CXD2880_TNRDMD_DVBT2_H
+
+#include "cxd2880_common.h"
+#include "cxd2880_tnrdmd.h"
+
+enum cxd2880_tnrdmd_dvbt2_tune_info {
+	CXD2880_TNRDMD_DVBT2_TUNE_INFO_OK,
+	CXD2880_TNRDMD_DVBT2_TUNE_INFO_INVALID_PLP_ID
+};
+
+struct cxd2880_dvbt2_tune_param {
+	u32 center_freq_khz;
+	enum cxd2880_dtv_bandwidth bandwidth;
+	u16 data_plp_id;
+	enum cxd2880_dvbt2_profile profile;
+	enum cxd2880_tnrdmd_dvbt2_tune_info tune_info;
+};
+
+#define CXD2880_DVBT2_TUNE_PARAM_PLPID_AUTO  0xFFFF
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_tune1(struct cxd2880_tnrdmd *tnr_dmd,
+					    struct cxd2880_dvbt2_tune_param
+					    *tune_param);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_tune2(struct cxd2880_tnrdmd *tnr_dmd,
+					    struct cxd2880_dvbt2_tune_param
+					    *tune_param);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_sleep_setting(struct cxd2880_tnrdmd
+						    *tnr_dmd);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd
+					       *tnr_dmd,
+					       enum
+					       cxd2880_tnrdmd_lock_result
+					       *lock);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd
+						    *tnr_dmd,
+						    enum
+						    cxd2880_tnrdmd_lock_result
+						    *lock);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd
+						  *tnr_dmd, u8 auto_plp,
+						  u8 plp_id);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_diver_fef_setting(struct cxd2880_tnrdmd
+							*tnr_dmd);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt2_check_l1post_valid(struct cxd2880_tnrdmd
+							 *tnr_dmd,
+							 u8 *l1_post_valid);
+
+#endif
-- 
2.11.0

^ permalink raw reply related

* [PATCH v2 10/15] [media] cxd2880: Add DVB-T monitor and integration layer functions
From: Yasunari.Takiguchi-7U/KSKJipcs @ 2017-04-14  2:35 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA
  Cc: tbird20d-Re5JQEeQqe8AvxtiuMwx3w,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w, Yasunari Takiguchi,
	Masayuki Yamamoto, Hideki Nozawa, Kota Yonezawa,
	Toshihiko Matsumoto, Satoshi Watanabe
In-Reply-To: <20170414015043.16731-1-Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>

From: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>

Provide monitor and integration layer functions (DVB-T)
for the Sony CXD2880 DVB-T2/T tuner + demodulator driver.

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe-7U/KSKJipcs@public.gmane.org>
---
 .../dvb-frontends/cxd2880/cxd2880_integ_dvbt.c     |  197 ++++
 .../dvb-frontends/cxd2880/cxd2880_integ_dvbt.h     |   58 +
 .../cxd2880/cxd2880_tnrdmd_dvbt_mon.c              | 1190 ++++++++++++++++++++
 .../cxd2880/cxd2880_tnrdmd_dvbt_mon.h              |  106 ++
 4 files changed, 1551 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h

diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c
new file mode 100644
index 000000000000..43b7da69fc6d
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c
@@ -0,0 +1,197 @@
+/*
+ * cxd2880_integ_dvbt.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * integration layer functions for DVB-T
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_tnrdmd_dvbt.h"
+#include "cxd2880_integ_dvbt.h"
+
+static enum cxd2880_ret dvbt_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd);
+
+enum cxd2880_ret cxd2880_integ_dvbt_tune(struct cxd2880_tnrdmd *tnr_dmd,
+					 struct cxd2880_dvbt_tune_param
+					 *tune_param)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!tune_param))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	cxd2880_atomic_set(&tnr_dmd->cancel, 0);
+
+	if ((tune_param->bandwidth != CXD2880_DTV_BW_5_MHZ) &&
+	    (tune_param->bandwidth != CXD2880_DTV_BW_6_MHZ) &&
+	    (tune_param->bandwidth != CXD2880_DTV_BW_7_MHZ) &&
+	    (tune_param->bandwidth != CXD2880_DTV_BW_8_MHZ)) {
+		return CXD2880_RESULT_ERROR_NOSUPPORT;
+	}
+
+	ret = cxd2880_tnrdmd_dvbt_tune1(tnr_dmd, tune_param);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	CXD2880_SLEEP(CXD2880_TNRDMD_WAIT_AGC_STABLE);
+
+	ret = cxd2880_tnrdmd_dvbt_tune2(tnr_dmd, tune_param);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	ret = dvbt_wait_demod_lock(tnr_dmd);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_integ_dvbt_wait_ts_lock(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	enum cxd2880_tnrdmd_lock_result lock =
+	    CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+	struct cxd2880_stopwatch timer;
+	u8 continue_wait = 1;
+	u32 elapsed = 0;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	ret = cxd2880_stopwatch_start(&timer);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	for (;;) {
+		ret = cxd2880_stopwatch_elapsed(&timer, &elapsed);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		if (elapsed >= CXD2880_DVBT_WAIT_TS_LOCK)
+			continue_wait = 0;
+
+		ret = cxd2880_tnrdmd_dvbt_check_ts_lock(tnr_dmd, &lock);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		switch (lock) {
+		case CXD2880_TNRDMD_LOCK_RESULT_LOCKED:
+			return CXD2880_RESULT_OK;
+
+		case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED:
+			return CXD2880_RESULT_ERROR_UNLOCK;
+
+		default:
+			break;
+		}
+
+		ret = cxd2880_integ_check_cancellation(tnr_dmd);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		if (continue_wait) {
+			ret =
+			    cxd2880_stopwatch_sleep(&timer,
+					    CXD2880_DVBT_WAIT_LOCK_INTVL);
+			if (ret != CXD2880_RESULT_OK)
+				return ret;
+		} else {
+			ret = CXD2880_RESULT_ERROR_TIMEOUT;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static enum cxd2880_ret dvbt_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	enum cxd2880_tnrdmd_lock_result lock =
+	    CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+	struct cxd2880_stopwatch timer;
+	u8 continue_wait = 1;
+	u32 elapsed = 0;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	ret = cxd2880_stopwatch_start(&timer);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	for (;;) {
+		ret = cxd2880_stopwatch_elapsed(&timer, &elapsed);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		if (elapsed >= CXD2880_DVBT_WAIT_DMD_LOCK)
+			continue_wait = 0;
+
+		ret = cxd2880_tnrdmd_dvbt_check_demod_lock(tnr_dmd, &lock);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		switch (lock) {
+		case CXD2880_TNRDMD_LOCK_RESULT_LOCKED:
+			return CXD2880_RESULT_OK;
+
+		case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED:
+			return CXD2880_RESULT_ERROR_UNLOCK;
+
+		default:
+			break;
+		}
+
+		ret = cxd2880_integ_check_cancellation(tnr_dmd);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		if (continue_wait) {
+			ret =
+			    cxd2880_stopwatch_sleep(&timer,
+					    CXD2880_DVBT_WAIT_LOCK_INTVL);
+			if (ret != CXD2880_RESULT_OK)
+				return ret;
+		} else {
+			ret = CXD2880_RESULT_ERROR_TIMEOUT;
+			break;
+		}
+	}
+
+	return ret;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h
new file mode 100644
index 000000000000..41f35c07a15e
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h
@@ -0,0 +1,58 @@
+/*
+ * cxd2880_integ_dvbt.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * integration layer interface for DVB-T
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_INTEG_DVBT_H
+#define CXD2880_INTEG_DVBT_H
+
+#include "cxd2880_tnrdmd.h"
+#include "cxd2880_tnrdmd_dvbt.h"
+#include "cxd2880_integ.h"
+
+#define CXD2880_DVBT_WAIT_DMD_LOCK	   1000
+#define CXD2880_DVBT_WAIT_TS_LOCK	      1000
+#define CXD2880_DVBT_WAIT_LOCK_INTVL	10
+
+struct cxd2880_integ_dvbt_scan_param {
+	u32 start_frequency_khz;
+	u32 end_frequency_khz;
+	u32 step_frequency_khz;
+	enum cxd2880_dtv_bandwidth bandwidth;
+};
+
+struct cxd2880_integ_dvbt_scan_result {
+	u32 center_freq_khz;
+	enum cxd2880_ret tune_result;
+	struct cxd2880_dvbt_tune_param dvbt_tune_param;
+};
+
+enum cxd2880_ret cxd2880_integ_dvbt_tune(struct cxd2880_tnrdmd *tnr_dmd,
+					 struct cxd2880_dvbt_tune_param
+					 *tune_param);
+
+enum cxd2880_ret cxd2880_integ_dvbt_wait_ts_lock(struct cxd2880_tnrdmd
+						 *tnr_dmd);
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
new file mode 100644
index 000000000000..d890081b6424
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
@@ -0,0 +1,1190 @@
+/*
+ * cxd2880_tnrdmd_dvbt_mon.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * DVB-T monitor functions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_tnrdmd_mon.h"
+#include "cxd2880_tnrdmd_dvbt.h"
+#include "cxd2880_tnrdmd_dvbt_mon.h"
+#include "cxd2880_math.h"
+
+static enum cxd2880_ret is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd
+						   *tnr_dmd, u8 *sync_stat,
+						   u8 *ts_lock_stat,
+						   u8 *unlock_detected)
+{
+	u8 rdata = 0x00;
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!sync_stat) || (!ts_lock_stat) || (!unlock_detected))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x0D) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x10, &rdata,
+				   1) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	*unlock_detected = (u8)((rdata & 0x10) ? 1 : 0);
+	*sync_stat = (u8)(rdata & 0x07);
+	*ts_lock_stat = (u8)((rdata & 0x20) ? 1 : 0);
+
+	if (*sync_stat == 0x07)
+		return CXD2880_RESULT_ERROR_HW_STATE;
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd
+						       *tnr_dmd, u8 *sync_stat,
+						       u8 *unlock_detected)
+{
+	u8 ts_lock_stat = 0;
+
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!sync_stat) || (!unlock_detected))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd->diver_sub, sync_stat,
+					      &ts_lock_stat, unlock_detected);
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd
+						    *tnr_dmd,
+						    enum cxd2880_dvbt_mode
+						    *mode,
+						    enum cxd2880_dvbt_guard
+						    *guard)
+{
+	u8 rdata = 0x00;
+
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!mode) || (!guard))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	ret = is_tps_locked(tnr_dmd);
+	if (ret != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
+			ret =
+			    cxd2880_tnrdmd_dvbt_mon_mode_guard(
+					tnr_dmd->diver_sub, mode, guard);
+
+		return ret;
+	}
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x0D) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x1B, &rdata,
+				   1) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	slvt_unfreeze_reg(tnr_dmd);
+
+	*mode = (enum cxd2880_dvbt_mode)((rdata >> 2) & 0x03);
+	*guard = (enum cxd2880_dvbt_guard)(rdata & 0x03);
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd
+							*tnr_dmd, int *offset)
+{
+	u8 rdata[4];
+	u32 ctl_val = 0;
+
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!offset))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	ret = is_tps_locked(tnr_dmd);
+	if (ret != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x0D) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x1D, rdata,
+				   4) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	slvt_unfreeze_reg(tnr_dmd);
+
+	ctl_val =
+	    ((rdata[0] & 0x1F) << 24) | (rdata[1] << 16) | (rdata[2] << 8) |
+	    (rdata[3]);
+	*offset = cxd2880_convert2s_complement(ctl_val, 29);
+	*offset = -1 * ((*offset) * (u8)tnr_dmd->bandwidth / 235);
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct
+							    cxd2880_tnrdmd
+							    *tnr_dmd,
+							    int *offset)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!offset))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt_mon_carrier_offset(tnr_dmd->diver_sub, offset);
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_pre_viterbiber(struct cxd2880_tnrdmd
+							*tnr_dmd, u32 *ber)
+{
+	u8 rdata[2];
+	u32 bit_error = 0;
+	u32 period = 0;
+
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!ber))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x10) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x39, rdata,
+				   1) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if ((rdata[0] & 0x01) == 0) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return CXD2880_RESULT_ERROR_HW_STATE;
+	}
+
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x22, rdata,
+				   2) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	bit_error = (rdata[0] << 8) | rdata[1];
+
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x6F, rdata,
+				   1) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	slvt_unfreeze_reg(tnr_dmd);
+
+	period = ((rdata[0] & 0x07) == 0) ? 256 : (0x1000 << (rdata[0] & 0x07));
+
+	if ((period == 0) || (bit_error > period))
+		return CXD2880_RESULT_ERROR_HW_STATE;
+
+	{
+		u32 div = 0;
+		u32 Q = 0;
+		u32 R = 0;
+
+		div = period / 128;
+
+		Q = (bit_error * 3125) / div;
+		R = (bit_error * 3125) % div;
+
+		R *= 25;
+		Q = Q * 25 + R / div;
+		R = R % div;
+
+		if (div / 2 <= R)
+			*ber = Q + 1;
+		else
+			*ber = Q;
+	}
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_pre_rsber(struct cxd2880_tnrdmd
+						   *tnr_dmd, u32 *ber)
+{
+	u8 rdata[3];
+	u32 bit_error = 0;
+	u32 period_exp = 0;
+
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!ber))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x0D) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x15, rdata,
+				   3) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if ((rdata[0] & 0x40) == 0)
+		return CXD2880_RESULT_ERROR_HW_STATE;
+
+	bit_error = ((rdata[0] & 0x3F) << 16) | (rdata[1] << 8) | rdata[2];
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x10) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x60, rdata,
+				   1) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	period_exp = (rdata[0] & 0x1F);
+
+	if ((period_exp <= 11) && (bit_error > (1U << period_exp) * 204 * 8))
+		return CXD2880_RESULT_ERROR_HW_STATE;
+
+	{
+		u32 div = 0;
+		u32 Q = 0;
+		u32 R = 0;
+
+		if (period_exp <= 8)
+			div = (1U << period_exp) * 51;
+		else
+			div = (1U << 8) * 51;
+
+		Q = (bit_error * 250) / div;
+		R = (bit_error * 250) % div;
+
+		R *= 1250;
+		Q = Q * 1250 + R / div;
+		R = R % div;
+
+		if (period_exp > 8) {
+			*ber =
+			    (Q + (1 << (period_exp - 9))) >> (period_exp - 8);
+		} else {
+			if (div / 2 <= R)
+				*ber = Q + 1;
+			else
+				*ber = Q;
+		}
+	}
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd
+						  *tnr_dmd,
+						  struct cxd2880_dvbt_tpsinfo
+						  *info)
+{
+	u8 rdata[7];
+	u8 cell_id_ok = 0;
+
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!info))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	ret = is_tps_locked(tnr_dmd);
+	if (ret != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
+			ret =
+			    cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd->diver_sub,
+							     info);
+
+		return ret;
+	}
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x0D) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x29, rdata,
+				   7) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x11) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0xD5, &cell_id_ok,
+				   1) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	slvt_unfreeze_reg(tnr_dmd);
+
+	info->constellation =
+	    (enum cxd2880_dvbt_constellation)((rdata[0] >> 6) & 0x03);
+	info->hierarchy = (enum cxd2880_dvbt_hierarchy)((rdata[0] >> 3) & 0x07);
+	info->rate_hp = (enum cxd2880_dvbt_coderate)(rdata[0] & 0x07);
+	info->rate_lp = (enum cxd2880_dvbt_coderate)((rdata[1] >> 5) & 0x07);
+	info->guard = (enum cxd2880_dvbt_guard)((rdata[1] >> 3) & 0x03);
+	info->mode = (enum cxd2880_dvbt_mode)((rdata[1] >> 1) & 0x03);
+	info->fnum = (rdata[2] >> 6) & 0x03;
+	info->length_indicator = rdata[2] & 0x3F;
+	info->cell_id = (u16)((rdata[3] << 8) | rdata[4]);
+	info->reserved_even = rdata[5] & 0x3F;
+	info->reserved_odd = rdata[6] & 0x3F;
+
+	info->cell_id_ok = cell_id_ok & 0x01;
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct
+							     cxd2880_tnrdmd
+							     *tnr_dmd,
+							     u32 *pen)
+{
+	u8 rdata[3];
+
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!pen))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x0D) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x26, rdata,
+				   3) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (!(rdata[0] & 0x01))
+		return CXD2880_RESULT_ERROR_HW_STATE;
+
+	*pen = (rdata[1] << 8) | rdata[2];
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd
+						*tnr_dmd,
+						enum
+						cxd2880_tnrdmd_spectrum_sense
+						*sense)
+{
+	u8 data = 0;
+
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!sense))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	ret = is_tps_locked(tnr_dmd);
+	if (ret != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
+			ret =
+				cxd2880_tnrdmd_dvbt_mon_spectrum_sense(
+					tnr_dmd->diver_sub, sense);
+
+		return ret;
+	}
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x0D) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x1C, &data,
+				   sizeof(data)) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	slvt_unfreeze_reg(tnr_dmd);
+
+	*sense =
+	    (data & 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV :
+	    CXD2880_TNRDMD_SPECTRUM_NORMAL;
+
+	return ret;
+}
+
+static enum cxd2880_ret dvbt_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd,
+					  u16 *reg_value)
+{
+	u8 rdata[2];
+
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!reg_value))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	ret = is_tps_locked(tnr_dmd);
+	if (ret != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x0D) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x13, rdata,
+				   2) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	slvt_unfreeze_reg(tnr_dmd);
+
+	*reg_value = (rdata[0] << 8) | rdata[1];
+
+	return ret;
+}
+
+static enum cxd2880_ret dvbt_calc_snr(struct cxd2880_tnrdmd *tnr_dmd,
+				      u32 reg_value, int *snr)
+{
+	if ((!tnr_dmd) || (!snr))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (reg_value == 0)
+		return CXD2880_RESULT_ERROR_HW_STATE;
+
+	if (reg_value > 4996)
+		reg_value = 4996;
+
+	*snr =
+	    10 * 10 * ((int)cxd2880_math_log10(reg_value) -
+		       (int)cxd2880_math_log10(5350 - reg_value));
+	*snr += 28500;
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
+					     int *snr)
+{
+	u16 reg_value = 0;
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!snr))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	*snr = -1000 * 1000;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
+		ret = dvbt_read_snr_reg(tnr_dmd, &reg_value);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		ret = dvbt_calc_snr(tnr_dmd, reg_value, snr);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	} else {
+		int snr_main = 0;
+		int snr_sub = 0;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt_mon_snr_diver(tnr_dmd, snr, &snr_main,
+						      &snr_sub);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	}
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd
+						   *tnr_dmd, int *snr,
+						   int *snr_main, int *snr_sub)
+{
+	u16 reg_value = 0;
+	u32 reg_value_sum = 0;
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!snr) || (!snr_main) || (!snr_sub))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	*snr = -1000 * 1000;
+	*snr_main = -1000 * 1000;
+	*snr_sub = -1000 * 1000;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	ret = dvbt_read_snr_reg(tnr_dmd, &reg_value);
+	if (ret == CXD2880_RESULT_OK) {
+		ret = dvbt_calc_snr(tnr_dmd, reg_value, snr_main);
+		if (ret != CXD2880_RESULT_OK)
+			reg_value = 0;
+	} else if (ret == CXD2880_RESULT_ERROR_HW_STATE) {
+		reg_value = 0;
+	} else {
+		return ret;
+	}
+
+	reg_value_sum += reg_value;
+
+	ret = dvbt_read_snr_reg(tnr_dmd->diver_sub, &reg_value);
+	if (ret == CXD2880_RESULT_OK) {
+		ret = dvbt_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub);
+		if (ret != CXD2880_RESULT_OK)
+			reg_value = 0;
+	} else if (ret == CXD2880_RESULT_ERROR_HW_STATE) {
+		reg_value = 0;
+	} else {
+		return ret;
+	}
+
+	reg_value_sum += reg_value;
+
+	ret = dvbt_calc_snr(tnr_dmd, reg_value_sum, snr);
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd
+							 *tnr_dmd, int *ppm)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!ppm))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	{
+		u8 ctl_val_reg[5];
+		u8 nominal_rate_reg[5];
+		u32 trl_ctl_val = 0;
+		u32 trcg_nominal_rate = 0;
+		int num;
+		int den;
+		s8 diff_upper = 0;
+
+		if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		ret = is_tps_locked(tnr_dmd);
+		if (ret != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x0D) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x21,
+					   ctl_val_reg,
+					   sizeof(ctl_val_reg)) !=
+		    CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x04) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x60,
+					   nominal_rate_reg,
+					   sizeof(nominal_rate_reg)) !=
+		    CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		diff_upper =
+		    (ctl_val_reg[0] & 0x7F) - (nominal_rate_reg[0] & 0x7F);
+
+		if ((diff_upper < -1) || (diff_upper > 1))
+			return CXD2880_RESULT_ERROR_HW_STATE;
+
+		trl_ctl_val = ctl_val_reg[1] << 24;
+		trl_ctl_val |= ctl_val_reg[2] << 16;
+		trl_ctl_val |= ctl_val_reg[3] << 8;
+		trl_ctl_val |= ctl_val_reg[4];
+
+		trcg_nominal_rate = nominal_rate_reg[1] << 24;
+		trcg_nominal_rate |= nominal_rate_reg[2] << 16;
+		trcg_nominal_rate |= nominal_rate_reg[3] << 8;
+		trcg_nominal_rate |= nominal_rate_reg[4];
+
+		trl_ctl_val >>= 1;
+		trcg_nominal_rate >>= 1;
+
+		if (diff_upper == 1)
+			num =
+			    (int)((trl_ctl_val + 0x80000000u) -
+				  trcg_nominal_rate);
+		else if (diff_upper == -1)
+			num =
+			    -(int)((trcg_nominal_rate + 0x80000000u) -
+				   trl_ctl_val);
+		else
+			num = (int)(trl_ctl_val - trcg_nominal_rate);
+
+		den = (nominal_rate_reg[0] & 0x7F) << 24;
+		den |= nominal_rate_reg[1] << 16;
+		den |= nominal_rate_reg[2] << 8;
+		den |= nominal_rate_reg[3];
+		den = (den + (390625 / 2)) / 390625;
+
+		den >>= 1;
+
+		if (num >= 0)
+			*ppm = (num + (den / 2)) / den;
+		else
+			*ppm = (num - (den / 2)) / den;
+	}
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct
+							     cxd2880_tnrdmd
+							     *tnr_dmd, int *ppm)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!ppm))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	ret = cxd2880_tnrdmd_dvbt_mon_sampling_offset(tnr_dmd->diver_sub, ppm);
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_quality(struct cxd2880_tnrdmd *tnr_dmd,
+						 u8 *quality)
+{
+	struct cxd2880_dvbt_tpsinfo tps;
+	enum cxd2880_dvbt_profile profile = CXD2880_DVBT_PROFILE_HP;
+	u32 ber = 0;
+	int sn = 0;
+	int sn_rel = 0;
+	int ber_sqi = 0;
+
+	static const int nordig_non_hdvbt_db_1000[3][5] = {
+		{5100, 6900, 7900, 8900, 9700},
+		{10800, 13100, 14600, 15600, 16000},
+		{16500, 18700, 20200, 21600, 22500}
+	};
+
+	static const int nordig_hier_hp_dvbt_db_1000[3][2][5] = {
+		{
+		 {9100, 12000, 13600, 15000, 16600},
+		 {10900, 14100, 15700, 19400, 20600}
+		 },
+		{
+		 {6800, 9100, 10400, 11900, 12700},
+		 {8500, 11000, 12800, 15000, 16000}
+		 },
+		{
+		 {5800, 7900, 9100, 10300, 12100},
+		 {8000, 9300, 11600, 13000, 12900}
+		}
+	};
+
+	static const int nordig_hier_lp_dvbt_db_1000[3][2][5] = {
+		{
+		 {12500, 14300, 15300, 16300, 16900},
+		 {16700, 19100, 20900, 22500, 23700}
+		 },
+		{
+		 {15000, 17200, 18400, 19100, 20100},
+		 {18500, 21200, 23600, 24700, 25900}
+		 },
+		{
+		 {19500, 21400, 22500, 23700, 24700},
+		 {21900, 24200, 25600, 26900, 27800}
+		}
+	};
+
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!quality))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	ret = cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd, &tps);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if (tps.hierarchy != CXD2880_DVBT_HIERARCHY_NON) {
+		u8 data = 0;
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x10) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x67, &data,
+					   1) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		profile =
+		    ((data & 0x01) ==
+		     0x01) ? CXD2880_DVBT_PROFILE_LP : CXD2880_DVBT_PROFILE_HP;
+	}
+
+	ret = cxd2880_tnrdmd_dvbt_mon_pre_rsber(tnr_dmd, &ber);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	ret = cxd2880_tnrdmd_dvbt_mon_snr(tnr_dmd, &sn);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if ((tps.constellation >= CXD2880_DVBT_CONSTELLATION_RESERVED_3) ||
+	    (tps.rate_hp >= CXD2880_DVBT_CODERATE_RESERVED_5) ||
+	    (tps.rate_lp >= CXD2880_DVBT_CODERATE_RESERVED_5) ||
+	    (tps.hierarchy > CXD2880_DVBT_HIERARCHY_4)) {
+		return CXD2880_RESULT_ERROR_OTHER;
+	}
+
+	if ((tps.hierarchy != CXD2880_DVBT_HIERARCHY_NON) &&
+	    (tps.constellation == CXD2880_DVBT_CONSTELLATION_QPSK))
+		return CXD2880_RESULT_ERROR_OTHER;
+
+	if (tps.hierarchy == CXD2880_DVBT_HIERARCHY_NON)
+		sn_rel =
+		    sn -
+		    nordig_non_hdvbt_db_1000[tps.constellation][tps.rate_hp];
+	else if (profile == CXD2880_DVBT_PROFILE_LP)
+		sn_rel =
+		    sn - nordig_hier_lp_dvbt_db_1000[(int)tps.hierarchy -
+						     1][(int)tps.constellation -
+							1][tps.rate_lp];
+	else
+		sn_rel =
+		    sn - nordig_hier_hp_dvbt_db_1000[(int)tps.hierarchy -
+						     1][(int)tps.constellation -
+							1][tps.rate_hp];
+
+	if (ber > 10000) {
+		ber_sqi = 0;
+	} else if (ber > 1) {
+		ber_sqi = (int)(10 * cxd2880_math_log10(ber));
+		ber_sqi = 20 * (7 * 1000 - (ber_sqi)) - 40 * 1000;
+	} else {
+		ber_sqi = 100 * 1000;
+	}
+
+	if (sn_rel < -7 * 1000) {
+		*quality = 0;
+	} else if (sn_rel < 3 * 1000) {
+		int tmp_sqi = (((sn_rel - (3 * 1000)) / 10) + 1000);
+		*quality =
+		    (u8)(((tmp_sqi * ber_sqi) +
+			   (1000000 / 2)) / (1000000)) & 0xFF;
+	} else {
+		*quality = (u8)((ber_sqi + 500) / 1000);
+	}
+
+	if (*quality > 100)
+		*quality = 100;
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_per(struct cxd2880_tnrdmd *tnr_dmd,
+					     u32 *per)
+{
+	u32 packet_error = 0;
+	u32 period = 0;
+	u8 rdata[3];
+
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!per))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x0D) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x18, rdata,
+				   3) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if ((rdata[0] & 0x01) == 0)
+		return CXD2880_RESULT_ERROR_HW_STATE;
+
+	packet_error = (rdata[1] << 8) | rdata[2];
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x10) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x5C, rdata,
+				   1) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	period = 1U << (rdata[0] & 0x0F);
+
+	if ((period == 0) || (packet_error > period))
+		return CXD2880_RESULT_ERROR_HW_STATE;
+
+	{
+		u32 div = 0;
+		u32 Q = 0;
+		u32 R = 0;
+
+		div = period;
+
+		Q = (packet_error * 1000) / div;
+		R = (packet_error * 1000) % div;
+
+		R *= 1000;
+		Q = Q * 1000 + R / div;
+		R = R % div;
+
+		if ((div != 1) && (div / 2 <= R))
+			*per = Q + 1;
+		else
+			*per = Q;
+	}
+
+	return ret;
+}
+
+static enum cxd2880_ret dvbt_calc_ssi(struct cxd2880_tnrdmd *tnr_dmd,
+				      int rf_lvl, u8 *ssi)
+{
+	struct cxd2880_dvbt_tpsinfo tps;
+	int prel;
+	int temp_ssi = 0;
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	static const int ref_dbm_1000[3][5] = {
+		{-93000, -91000, -90000, -89000, -88000},
+		{-87000, -85000, -84000, -83000, -82000},
+		{-82000, -80000, -78000, -77000, -76000},
+	};
+
+	if ((!tnr_dmd) || (!ssi))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	ret = cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd, &tps);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if ((tps.constellation >= CXD2880_DVBT_CONSTELLATION_RESERVED_3) ||
+	    (tps.rate_hp >= CXD2880_DVBT_CODERATE_RESERVED_5))
+		return CXD2880_RESULT_ERROR_OTHER;
+
+	prel = rf_lvl - ref_dbm_1000[tps.constellation][tps.rate_hp];
+
+	if (prel < -15000)
+		temp_ssi = 0;
+	else if (prel < 0)
+		temp_ssi = ((2 * (prel + 15000)) + 1500) / 3000;
+	else if (prel < 20000)
+		temp_ssi = (((4 * prel) + 500) / 1000) + 10;
+	else if (prel < 35000)
+		temp_ssi = (((2 * (prel - 20000)) + 1500) / 3000) + 90;
+	else
+		temp_ssi = 100;
+
+	*ssi = (temp_ssi > 100) ? 100 : (u8)temp_ssi;
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
+					     u8 *ssi)
+{
+	int rf_lvl = 0;
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!ssi))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd, &rf_lvl);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	ret = dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd *tnr_dmd,
+						 u8 *ssi)
+{
+	int rf_lvl = 0;
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!ssi))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	ret = dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	return ret;
+}
+
+static enum cxd2880_ret is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	u8 sync = 0;
+	u8 tslock = 0;
+	u8 early_unlock = 0;
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync, &tslock,
+					      &early_unlock);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if (sync != 6)
+		return CXD2880_RESULT_ERROR_HW_STATE;
+
+	return CXD2880_RESULT_OK;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h
new file mode 100644
index 000000000000..486fc466272e
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h
@@ -0,0 +1,106 @@
+/*
+ * cxd2880_tnrdmd_dvbt_mon.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * DVB-T monitor interface
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_TNRDMD_DVBT_MON_H
+#define CXD2880_TNRDMD_DVBT_MON_H
+
+#include "cxd2880_tnrdmd.h"
+#include "cxd2880_dvbt.h"
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd
+						   *tnr_dmd, u8 *sync_stat,
+						   u8 *ts_lock_stat,
+						   u8 *unlock_detected);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd
+						       *tnr_dmd, u8 *sync_stat,
+						       u8 *unlock_detected);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd
+						    *tnr_dmd,
+						    enum cxd2880_dvbt_mode
+						    *mode,
+						    enum cxd2880_dvbt_guard
+						    *guard);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd
+							*tnr_dmd, int *offset);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct
+							    cxd2880_tnrdmd
+							    *tnr_dmd,
+							    int *offset);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_pre_viterbiber(struct cxd2880_tnrdmd
+							*tnr_dmd, u32 *ber);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_pre_rsber(struct cxd2880_tnrdmd
+						   *tnr_dmd, u32 *ber);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd
+						  *tnr_dmd,
+						  struct cxd2880_dvbt_tpsinfo
+						  *info);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct
+							     cxd2880_tnrdmd
+							     *tnr_dmd,
+							     u32 *pen);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd
+						*tnr_dmd,
+						enum
+						cxd2880_tnrdmd_spectrum_sense
+						*sense);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
+					     int *snr);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd
+						   *tnr_dmd, int *snr,
+						   int *snr_main, int *snr_sub);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd
+							 *tnr_dmd, int *ppm);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct
+							     cxd2880_tnrdmd
+							     *tnr_dmd,
+							     int *ppm);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_quality(struct cxd2880_tnrdmd *tnr_dmd,
+						 u8 *quality);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_per(struct cxd2880_tnrdmd *tnr_dmd,
+					     u32 *per);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
+					     u8 *ssi);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd *tnr_dmd,
+						 u8 *ssi);
+
+#endif
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v2 09/15] [media] cxd2880: Add DVB-T control functions the driver
From: Yasunari.Takiguchi-7U/KSKJipcs @ 2017-04-14  2:33 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA
  Cc: tbird20d-Re5JQEeQqe8AvxtiuMwx3w,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w, Yasunari Takiguchi,
	Masayuki Yamamoto, Hideki Nozawa, Kota Yonezawa,
	Toshihiko Matsumoto, Satoshi Watanabe
In-Reply-To: <20170414015043.16731-1-Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>

From: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>

Provide definitions, interfaces and functions needed for DVB-T
of the Sony CXD2880 DVB-T2/T tuner + demodulator driver.

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe-7U/KSKJipcs@public.gmane.org>
---
 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h |   91 ++
 .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c    | 1072 ++++++++++++++++++++
 .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h    |   62 ++
 3 files changed, 1225 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h

diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
new file mode 100644
index 000000000000..345c094760d2
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
@@ -0,0 +1,91 @@
+/*
+ * cxd2880_dvbt.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * DVB-T related definitions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_DVBT_H
+#define CXD2880_DVBT_H
+
+#include "cxd2880_common.h"
+
+enum cxd2880_dvbt_constellation {
+	CXD2880_DVBT_CONSTELLATION_QPSK,
+	CXD2880_DVBT_CONSTELLATION_16QAM,
+	CXD2880_DVBT_CONSTELLATION_64QAM,
+	CXD2880_DVBT_CONSTELLATION_RESERVED_3
+};
+
+enum cxd2880_dvbt_hierarchy {
+	CXD2880_DVBT_HIERARCHY_NON,
+	CXD2880_DVBT_HIERARCHY_1,
+	CXD2880_DVBT_HIERARCHY_2,
+	CXD2880_DVBT_HIERARCHY_4
+};
+
+enum cxd2880_dvbt_coderate {
+	CXD2880_DVBT_CODERATE_1_2,
+	CXD2880_DVBT_CODERATE_2_3,
+	CXD2880_DVBT_CODERATE_3_4,
+	CXD2880_DVBT_CODERATE_5_6,
+	CXD2880_DVBT_CODERATE_7_8,
+	CXD2880_DVBT_CODERATE_RESERVED_5,
+	CXD2880_DVBT_CODERATE_RESERVED_6,
+	CXD2880_DVBT_CODERATE_RESERVED_7
+};
+
+enum cxd2880_dvbt_guard {
+	CXD2880_DVBT_GUARD_1_32,
+	CXD2880_DVBT_GUARD_1_16,
+	CXD2880_DVBT_GUARD_1_8,
+	CXD2880_DVBT_GUARD_1_4
+};
+
+enum cxd2880_dvbt_mode {
+	CXD2880_DVBT_MODE_2K,
+	CXD2880_DVBT_MODE_8K,
+	CXD2880_DVBT_MODE_RESERVED_2,
+	CXD2880_DVBT_MODE_RESERVED_3
+};
+
+enum cxd2880_dvbt_profile {
+	CXD2880_DVBT_PROFILE_HP = 0,
+	CXD2880_DVBT_PROFILE_LP
+};
+
+struct cxd2880_dvbt_tpsinfo {
+	enum cxd2880_dvbt_constellation constellation;
+	enum cxd2880_dvbt_hierarchy hierarchy;
+	enum cxd2880_dvbt_coderate rate_hp;
+	enum cxd2880_dvbt_coderate rate_lp;
+	enum cxd2880_dvbt_guard guard;
+	enum cxd2880_dvbt_mode mode;
+	u8 fnum;
+	u8 length_indicator;
+	u16 cell_id;
+	u8 cell_id_ok;
+	u8 reserved_even;
+	u8 reserved_odd;
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
new file mode 100644
index 000000000000..f36cf533ec17
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
@@ -0,0 +1,1072 @@
+/*
+ * cxd2880_tnrdmd_dvbt.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * control functions for DVB-T
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_tnrdmd_dvbt.h"
+#include "cxd2880_tnrdmd_dvbt_mon.h"
+
+static enum cxd2880_ret x_tune_dvbt_demod_setting(struct cxd2880_tnrdmd
+						  *tnr_dmd,
+						  enum cxd2880_dtv_bandwidth
+						  bandwidth,
+						  enum cxd2880_tnrdmd_clockmode
+						  clk_mode)
+{
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x31,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	{
+		u8 data_a[2] = { 0x52, 0x49 };
+		u8 data_b[2] = { 0x5D, 0x55 };
+		u8 data_c[2] = { 0x60, 0x00 };
+		u8 *data = NULL;
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x04) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		switch (clk_mode) {
+		case CXD2880_TNRDMD_CLOCKMODE_A:
+			data = data_a;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_B:
+			data = data_b;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_C:
+			data = data_c;
+			break;
+		default:
+			return CXD2880_RESULT_ERROR_SW_STATE;
+		}
+
+		if (tnr_dmd->io->write_regs(tnr_dmd->io,
+					    CXD2880_IO_TGT_DMD, 0x65, data,
+					    2) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x5D,
+				   0x07) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
+		u8 data[2] = { 0x01, 0x01 };
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x00) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->write_regs(tnr_dmd->io,
+					    CXD2880_IO_TGT_DMD, 0xCE, data,
+					    2) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x04) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x5C,
+				   0xFB) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x10) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0xA4,
+				   0x03) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x14) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0xB0,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x25) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	{
+		u8 data[2] = { 0x01, 0xF0 };
+
+		if (tnr_dmd->io->write_regs(tnr_dmd->io,
+					    CXD2880_IO_TGT_DMD, 0xF0, data,
+					    2) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if ((tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) ||
+	    (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)) {
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x12) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x44,
+					   0x00) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) {
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x11) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x87,
+					   0xD2) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
+		u8 data_a[3] = { 0x73, 0xCA, 0x49 };
+		u8 data_b[3] = { 0xC8, 0x13, 0xAA };
+		u8 data_c[3] = { 0xDC, 0x6C, 0x00 };
+		u8 *data = NULL;
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x04) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		switch (clk_mode) {
+		case CXD2880_TNRDMD_CLOCKMODE_A:
+			data = data_a;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_B:
+			data = data_b;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_C:
+			data = data_c;
+			break;
+		default:
+			return CXD2880_RESULT_ERROR_SW_STATE;
+		}
+
+		if (tnr_dmd->io->write_regs(tnr_dmd->io,
+					    CXD2880_IO_TGT_DMD, 0x68, data,
+					    3) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x04) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	switch (bandwidth) {
+	case CXD2880_DTV_BW_8_MHZ:
+
+		{
+			u8 data_ac[5] = { 0x15, 0x00, 0x00, 0x00,
+				0x00
+			};
+			u8 data_b[5] = { 0x14, 0x6A, 0xAA, 0xAA,
+				0xAA
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_ac;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x60,
+						    data,
+						    5) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x4A,
+					   0x00) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		{
+			u8 data_a[2] = { 0x01, 0x28 };
+			u8 data_b[2] = { 0x11, 0x44 };
+			u8 data_c[2] = { 0x15, 0x28 };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x7D,
+						    data,
+						    2) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		{
+			u8 data = 0;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = 0x35;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = 0x34;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_reg(tnr_dmd->io,
+						   CXD2880_IO_TGT_DMD, 0x71,
+						   data) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			u8 data_a[5] = { 0x30, 0x00, 0x00, 0x90,
+				0x00
+			};
+			u8 data_b[5] = { 0x36, 0x71, 0x00, 0xA3,
+				0x55
+			};
+			u8 data_c[5] = { 0x38, 0x00, 0x00, 0xA8,
+				0x00
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x4B,
+						    &data[0],
+						    2) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x51,
+						    &data[2],
+						    3) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		{
+			u8 data[4] = { 0xB3, 0x00, 0x01, 0x02 };
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x72,
+						    &data[0],
+						    2) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x6B,
+						    &data[2],
+						    2) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+		break;
+
+	case CXD2880_DTV_BW_7_MHZ:
+
+		{
+			u8 data_ac[5] = { 0x18, 0x00, 0x00, 0x00,
+				0x00
+			};
+			u8 data_b[5] = { 0x17, 0x55, 0x55, 0x55,
+				0x55
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_ac;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x60,
+						    data,
+						    5) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x4A,
+					   0x02) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		{
+			u8 data_a[2] = { 0x12, 0x4C };
+			u8 data_b[2] = { 0x1F, 0x15 };
+			u8 data_c[2] = { 0x1F, 0xF8 };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x7D,
+						    data,
+						    2) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		{
+			u8 data = 0;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = 0x2F;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = 0x2E;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_reg(tnr_dmd->io,
+						   CXD2880_IO_TGT_DMD, 0x71,
+						   data) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			u8 data_a[5] = { 0x36, 0xDB, 0x00, 0xA4,
+				0x92
+			};
+			u8 data_b[5] = { 0x3E, 0x38, 0x00, 0xBA,
+				0xAA
+			};
+			u8 data_c[5] = { 0x40, 0x00, 0x00, 0xC0,
+				0x00
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x4B,
+						    &data[0],
+						    2) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x51,
+						    &data[2],
+						    3) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		{
+			u8 data[4] = { 0xB8, 0x00, 0x00, 0x03 };
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x72,
+						    &data[0],
+						    2) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x6B,
+						    &data[2],
+						    2) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+		break;
+
+	case CXD2880_DTV_BW_6_MHZ:
+
+		{
+			u8 data_ac[5] = { 0x1C, 0x00, 0x00, 0x00,
+				0x00
+			};
+			u8 data_b[5] = { 0x1B, 0x38, 0xE3, 0x8E,
+				0x38
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_ac;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x60,
+						    data,
+						    5) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x4A,
+					   0x04) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		{
+			u8 data_a[2] = { 0x1F, 0xF8 };
+			u8 data_b[2] = { 0x24, 0x43 };
+			u8 data_c[2] = { 0x25, 0x4C };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x7D,
+						    data,
+						    2) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		{
+			u8 data = 0;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = 0x29;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = 0x2A;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_reg(tnr_dmd->io,
+						   CXD2880_IO_TGT_DMD, 0x71,
+						   data) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			u8 data_a[5] = { 0x40, 0x00, 0x00, 0xC0,
+				0x00
+			};
+			u8 data_b[5] = { 0x48, 0x97, 0x00, 0xD9,
+				0xC7
+			};
+			u8 data_c[5] = { 0x4A, 0xAA, 0x00, 0xDF,
+				0xFF
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x4B,
+						    &data[0],
+						    2) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x51,
+						    &data[2],
+						    3) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		{
+			u8 data[4] = { 0xBE, 0xAB, 0x00, 0x03 };
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x72,
+						    &data[0],
+						    2) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x6B,
+						    &data[2],
+						    2) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+		break;
+
+	case CXD2880_DTV_BW_5_MHZ:
+
+		{
+			u8 data_ac[5] = { 0x21, 0x99, 0x99, 0x99,
+				0x99
+			};
+			u8 data_b[5] = { 0x20, 0xAA, 0xAA, 0xAA,
+				0xAA
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_ac;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x60,
+						    data,
+						    5) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x4A,
+					   0x06) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		{
+			u8 data_a[2] = { 0x26, 0x5D };
+			u8 data_b[2] = { 0x2B, 0x84 };
+			u8 data_c[2] = { 0x2C, 0xC2 };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x7D,
+						    data,
+						    2) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		{
+			u8 data = 0;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = 0x24;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = 0x23;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_reg(tnr_dmd->io,
+						   CXD2880_IO_TGT_DMD, 0x71,
+						   data) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			u8 data_a[5] = { 0x4C, 0xCC, 0x00, 0xE6,
+				0x66
+			};
+			u8 data_b[5] = { 0x57, 0x1C, 0x01, 0x05,
+				0x55
+			};
+			u8 data_c[5] = { 0x59, 0x99, 0x01, 0x0C,
+				0xCC
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return CXD2880_RESULT_ERROR_SW_STATE;
+			}
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x4B,
+						    &data[0],
+						    2) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x51,
+						    &data[2],
+						    3) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+
+		{
+			u8 data[4] = { 0xC8, 0x01, 0x00, 0x03 };
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x72,
+						    &data[0],
+						    2) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+
+			if (tnr_dmd->io->write_regs(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x6B,
+						    &data[2],
+						    2) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+		break;
+
+	default:
+		return CXD2880_RESULT_ERROR_SW_STATE;
+	}
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0xFD,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	return CXD2880_RESULT_OK;
+}
+
+static enum cxd2880_ret x_sleep_dvbt_demod_setting(struct cxd2880_tnrdmd
+						   *tnr_dmd)
+{
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x04) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x5C,
+				   0xD8) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x10) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0xA4,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) {
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0x11) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x87,
+					   0x04) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	}
+
+	return CXD2880_RESULT_OK;
+}
+
+static enum cxd2880_ret dvbt_set_profile(struct cxd2880_tnrdmd *tnr_dmd,
+					 enum cxd2880_dvbt_profile profile)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x10) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x67,
+				   (profile ==
+				    CXD2880_DVBT_PROFILE_HP) ? 0x00 : 0x01) !=
+	    CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd,
+					   struct cxd2880_dvbt_tune_param
+					   *tune_param)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!tune_param))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	ret =
+	    cxd2880_tnrdmd_common_tune_setting1(tnr_dmd, CXD2880_DTV_SYS_DVBT,
+						tune_param->center_freq_khz,
+						tune_param->bandwidth, 0, 0);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	ret =
+	    x_tune_dvbt_demod_setting(tnr_dmd, tune_param->bandwidth,
+				      tnr_dmd->clk_mode);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret =
+		    x_tune_dvbt_demod_setting(tnr_dmd->diver_sub,
+					      tune_param->bandwidth,
+					      tnr_dmd->diver_sub->clk_mode);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	}
+
+	ret = dvbt_set_profile(tnr_dmd, tune_param->profile);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd,
+					   struct cxd2880_dvbt_tune_param
+					   *tune_param)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!tune_param))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	ret =
+	    cxd2880_tnrdmd_common_tune_setting2(tnr_dmd, CXD2880_DTV_SYS_DVBT,
+						0);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	tnr_dmd->state = CXD2880_TNRDMD_STATE_ACTIVE;
+	tnr_dmd->frequency_khz = tune_param->center_freq_khz;
+	tnr_dmd->sys = CXD2880_DTV_SYS_DVBT;
+	tnr_dmd->bandwidth = tune_param->bandwidth;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_ACTIVE;
+		tnr_dmd->diver_sub->frequency_khz = tune_param->center_freq_khz;
+		tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_DVBT;
+		tnr_dmd->diver_sub->bandwidth = tune_param->bandwidth;
+	}
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd
+						   *tnr_dmd)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	ret = x_sleep_dvbt_demod_setting(tnr_dmd);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = x_sleep_dvbt_demod_setting(tnr_dmd->diver_sub);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	}
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd
+						      *tnr_dmd,
+						      enum
+						      cxd2880_tnrdmd_lock_result
+						      *lock)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	u8 sync_stat = 0;
+	u8 ts_lock = 0;
+	u8 unlock_detected = 0;
+	u8 unlock_detected_sub = 0;
+
+	if ((!tnr_dmd) || (!lock))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
+					      &unlock_detected);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
+		if (sync_stat == 6)
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+		else if (unlock_detected)
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+		else
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+		return ret;
+	}
+
+	if (sync_stat == 6) {
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+		return ret;
+	}
+
+	ret =
+	    cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(tnr_dmd, &sync_stat,
+						  &unlock_detected_sub);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if (sync_stat == 6)
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+	else if (unlock_detected && unlock_detected_sub)
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+	else
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd
+						   *tnr_dmd,
+						   enum
+						   cxd2880_tnrdmd_lock_result
+						   *lock)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	u8 sync_stat = 0;
+	u8 ts_lock = 0;
+	u8 unlock_detected = 0;
+	u8 unlock_detected_sub = 0;
+
+	if ((!tnr_dmd) || (!lock))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
+					      &unlock_detected);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
+		if (ts_lock)
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+		else if (unlock_detected)
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+		else
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+		return ret;
+	}
+
+	if (ts_lock) {
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+		return ret;
+	} else if (!unlock_detected) {
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+		return ret;
+	}
+
+	ret =
+	    cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(tnr_dmd, &sync_stat,
+						  &unlock_detected_sub);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if (unlock_detected && unlock_detected_sub)
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+	else
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+	return ret;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h
new file mode 100644
index 000000000000..de394d8e27f3
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h
@@ -0,0 +1,62 @@
+/*
+ * cxd2880_tnrdmd_dvbt.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * control interface for DVB-T
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_TNRDMD_DVBT_H
+#define CXD2880_TNRDMD_DVBT_H
+
+#include "cxd2880_common.h"
+#include "cxd2880_tnrdmd.h"
+
+struct cxd2880_dvbt_tune_param {
+	u32 center_freq_khz;
+	enum cxd2880_dtv_bandwidth bandwidth;
+	enum cxd2880_dvbt_profile profile;
+};
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd,
+					   struct cxd2880_dvbt_tune_param
+					   *tune_param);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd,
+					   struct cxd2880_dvbt_tune_param
+					   *tune_param);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd
+						   *tnr_dmd);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd
+						      *tnr_dmd,
+						      enum
+						      cxd2880_tnrdmd_lock_result
+						      *lock);
+
+enum cxd2880_ret cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd
+						   *tnr_dmd,
+						   enum
+						   cxd2880_tnrdmd_lock_result
+						   *lock);
+
+#endif
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v2 08/15] [media] cxd2880: Add top level of the driver
From: Yasunari.Takiguchi @ 2017-04-14  2:31 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-media
  Cc: tbird20d, frowand.list, Yasunari Takiguchi, Masayuki Yamamoto,
	Hideki Nozawa, Kota Yonezawa, Toshihiko Matsumoto,
	Satoshi Watanabe
In-Reply-To: <20170414015043.16731-1-Yasunari.Takiguchi@sony.com>

From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

This provides the main dvb frontend operation functions
for the Sony CXD2880 DVB-T2/T tuner + demodulator driver.

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
---
 drivers/media/dvb-frontends/cxd2880/cxd2880_top.c | 1550 +++++++++++++++++++++
 1 file changed, 1550 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_top.c

diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
new file mode 100644
index 000000000000..66d78fb93a13
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
@@ -0,0 +1,1550 @@
+/*
+ * cxd2880_top.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/spi/spi.h>
+
+#include "dvb_frontend.h"
+
+#include "cxd2880.h"
+#include "cxd2880_tnrdmd_mon.h"
+#include "cxd2880_tnrdmd_dvbt2_mon.h"
+#include "cxd2880_tnrdmd_dvbt_mon.h"
+#include "cxd2880_integ_dvbt2.h"
+#include "cxd2880_integ_dvbt.h"
+#include "cxd2880_devio_spi.h"
+#include "cxd2880_spi_device.h"
+#include "cxd2880_tnrdmd_driver_version.h"
+
+struct cxd2880_priv {
+	struct cxd2880_tnrdmd tnrdmd;
+	struct spi_device *spi;
+	struct cxd2880_io regio;
+	struct cxd2880_spi_device spi_device;
+	struct cxd2880_spi cxd2880_spi;
+	struct cxd2880_dvbt_tune_param dvbt_tune_param;
+	struct cxd2880_dvbt2_tune_param dvbt2_tune_param;
+	struct mutex *spi_mutex; /* For SPI access exclusive control */
+};
+
+/*
+ * return value conversion table
+ */
+static int return_tbl[] = {
+	0,             /* CXD2880_RESULT_OK */
+	-EINVAL,       /* CXD2880_RESULT_ERROR_ARG*/
+	-EIO,          /* CXD2880_RESULT_ERROR_IO */
+	-EPERM,        /* CXD2880_RESULT_ERROR_SW_STATE */
+	-EBUSY,        /* CXD2880_RESULT_ERROR_HW_STATE */
+	-ETIME,        /* CXD2880_RESULT_ERROR_TIMEOUT */
+	-EAGAIN,       /* CXD2880_RESULT_ERROR_UNLOCK */
+	-ERANGE,       /* CXD2880_RESULT_ERROR_RANGE */
+	-EOPNOTSUPP,   /* CXD2880_RESULT_ERROR_NOSUPPORT */
+	-ECANCELED,    /* CXD2880_RESULT_ERROR_CANCEL */
+	-EPERM,        /* CXD2880_RESULT_ERROR_OTHER */
+	-EOVERFLOW,    /* CXD2880_RESULT_ERROR_OVERFLOW */
+	0,             /* CXD2880_RESULT_OK_CONFIRM */
+};
+
+static enum cxd2880_ret cxd2880_pre_bit_err_t(
+		struct cxd2880_tnrdmd *tnrdmd, u32 *pre_bit_err,
+		u32 *pre_bit_count)
+{
+	u8 rdata[2];
+
+	if ((!tnrdmd) || (!pre_bit_err) || (!pre_bit_count))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (slvt_freeze_reg(tnrdmd) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD,
+				0x00, 0x10) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnrdmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD,
+				0x39, rdata, 1) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnrdmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if ((rdata[0] & 0x01) == 0) {
+		slvt_unfreeze_reg(tnrdmd);
+		return CXD2880_RESULT_ERROR_HW_STATE;
+	}
+
+	if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD,
+				0x22, rdata, 2) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnrdmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	*pre_bit_err = (rdata[0] << 8) | rdata[1];
+
+	if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD,
+				0x6F, rdata, 1) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnrdmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	slvt_unfreeze_reg(tnrdmd);
+
+	*pre_bit_count = ((rdata[0] & 0x07) == 0) ?
+			256 : (0x1000 << (rdata[0] & 0x07));
+
+	return CXD2880_RESULT_OK;
+}
+
+static enum cxd2880_ret cxd2880_pre_bit_err_t2(
+		struct cxd2880_tnrdmd *tnrdmd, u32 *pre_bit_err,
+		u32 *pre_bit_count)
+{
+	u32 period_exp = 0;
+	u32 n_ldpc = 0;
+	u8 data[5];
+
+	if ((!tnrdmd) || (!pre_bit_err) || (!pre_bit_count))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (slvt_freeze_reg(tnrdmd) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD,
+				0x00, 0x0B) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnrdmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD,
+				0x3C, data, sizeof(data))
+				 != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnrdmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (!(data[0] & 0x01)) {
+		slvt_unfreeze_reg(tnrdmd);
+		return CXD2880_RESULT_ERROR_HW_STATE;
+	}
+	*pre_bit_err =
+	((data[1] & 0x0F) << 24) | (data[2] << 16) | (data[3] << 8) | data[4];
+
+	if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD,
+				0xA0, data, 1) != CXD2880_RESULT_OK) {
+		slvt_unfreeze_reg(tnrdmd);
+		return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (((enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03)) ==
+	    CXD2880_DVBT2_FEC_LDPC_16K)
+		n_ldpc = 16200;
+	else
+		n_ldpc = 64800;
+	slvt_unfreeze_reg(tnrdmd);
+
+	if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD,
+				0x00, 0x20) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD,
+				0x6F, data, 1) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	period_exp = data[0] & 0x0F;
+
+	*pre_bit_count = (1U << period_exp) * n_ldpc;
+
+	return CXD2880_RESULT_OK;
+}
+
+static enum cxd2880_ret cxd2880_post_bit_err_t(struct cxd2880_tnrdmd *tnrdmd,
+						u32 *post_bit_err,
+						u32 *post_bit_count)
+{
+	u8 rdata[3];
+	u32 bit_error = 0;
+	u32 period_exp = 0;
+
+	if ((!tnrdmd) || (!post_bit_err) || (!post_bit_count))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD,
+				0x00, 0x0D) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD,
+				0x15, rdata, 3) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if ((rdata[0] & 0x40) == 0)
+		return CXD2880_RESULT_ERROR_HW_STATE;
+
+	*post_bit_err = ((rdata[0] & 0x3F) << 16) | (rdata[1] << 8) | rdata[2];
+
+	if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD,
+				0x00, 0x10) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD,
+				0x60, rdata, 1) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	period_exp = (rdata[0] & 0x1F);
+
+	if ((period_exp <= 11) && (bit_error > (1U << period_exp) * 204 * 8))
+		return CXD2880_RESULT_ERROR_HW_STATE;
+
+	if (period_exp == 11)
+		*post_bit_count = 3342336;
+	else
+		*post_bit_count = (1U << period_exp) * 204 * 81;
+
+	return CXD2880_RESULT_OK;
+}
+
+static enum cxd2880_ret cxd2880_post_bit_err_t2(struct cxd2880_tnrdmd *tnrdmd,
+						u32 *post_bit_err,
+						u32 *post_bit_count)
+{
+	u32 period_exp = 0;
+	u32 n_bch = 0;
+
+	if ((!tnrdmd) || (!post_bit_err) || (!post_bit_count))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	{
+		u8 data[3];
+		enum cxd2880_dvbt2_plp_fec plp_fec_type =
+			CXD2880_DVBT2_FEC_LDPC_16K;
+		enum cxd2880_dvbt2_plp_code_rate plp_code_rate =
+			CXD2880_DVBT2_R1_2;
+
+		static const u16 n_bch_bits_lookup[2][8] = {
+			{7200, 9720, 10800, 11880, 12600, 13320, 5400, 6480},
+			{32400, 38880, 43200, 48600, 51840, 54000, 21600, 25920}
+		};
+
+		if (slvt_freeze_reg(tnrdmd) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD,
+					0x00, 0x0B) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnrdmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD,
+					 0x15, data, 3) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnrdmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		if (!(data[0] & 0x40)) {
+			slvt_unfreeze_reg(tnrdmd);
+			return CXD2880_RESULT_ERROR_HW_STATE;
+		}
+
+		*post_bit_err =
+			((data[0] & 0x3F) << 16) | (data[1] << 8) | data[2];
+
+		if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD,
+					0x9D, data, 1) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnrdmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		plp_code_rate =
+		(enum cxd2880_dvbt2_plp_code_rate)(data[0] & 0x07);
+
+		if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD,
+					0xA0, data, 1) != CXD2880_RESULT_OK) {
+			slvt_unfreeze_reg(tnrdmd);
+			return CXD2880_RESULT_ERROR_IO;
+		}
+
+		plp_fec_type = (enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03);
+
+		slvt_unfreeze_reg(tnrdmd);
+
+		if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD,
+					0x00, 0x20) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD,
+					0x72, data, 1) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		period_exp = data[0] & 0x0F;
+
+		if ((plp_fec_type > CXD2880_DVBT2_FEC_LDPC_64K) ||
+			(plp_code_rate > CXD2880_DVBT2_R2_5))
+			return CXD2880_RESULT_ERROR_HW_STATE;
+
+		n_bch = n_bch_bits_lookup[plp_fec_type][plp_code_rate];
+	}
+
+	if (*post_bit_err > ((1U << period_exp) * n_bch))
+		return CXD2880_RESULT_ERROR_HW_STATE;
+
+	*post_bit_count = (1U << period_exp) * n_bch;
+
+	return CXD2880_RESULT_OK;
+}
+
+static enum cxd2880_ret cxd2880_read_block_err_t(
+					struct cxd2880_tnrdmd *tnrdmd,
+					u32 *block_err,
+					u32 *block_count)
+{
+	u8 rdata[3];
+
+	if ((!tnrdmd) || (!block_err) || (!block_count))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD,
+				0x00, 0x0D) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD,
+				0x18, rdata, 3) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if ((rdata[0] & 0x01) == 0)
+		return CXD2880_RESULT_ERROR_HW_STATE;
+
+	*block_err = (rdata[1] << 8) | rdata[2];
+
+	if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD,
+				0x00, 0x10) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD,
+				0x5C, rdata, 1) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	*block_count = 1U << (rdata[0] & 0x0F);
+
+	if ((*block_count == 0) || (*block_err > *block_count))
+		return CXD2880_RESULT_ERROR_HW_STATE;
+
+	return CXD2880_RESULT_OK;
+}
+
+static enum cxd2880_ret cxd2880_read_block_err_t2(
+					struct cxd2880_tnrdmd *tnrdmd,
+					u32 *block_err,
+					u32 *block_count)
+{
+	if ((!tnrdmd) || (!block_err) || (!block_count))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	{
+		u8 rdata[3];
+
+		if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD,
+					0x00, 0x0B) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD,
+					0x18, rdata, 3) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if ((rdata[0] & 0x01) == 0)
+			return CXD2880_RESULT_ERROR_HW_STATE;
+
+		*block_err = (rdata[1] << 8) | rdata[2];
+
+		if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD,
+					0x00, 0x24) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD,
+					0xDC, rdata, 1) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		*block_count = 1U << (rdata[0] & 0x0F);
+	}
+
+	if ((*block_count == 0) || (*block_err > *block_count))
+		return CXD2880_RESULT_ERROR_HW_STATE;
+
+	return CXD2880_RESULT_OK;
+}
+
+static void cxd2880_release(struct dvb_frontend *fe)
+{
+	struct cxd2880_priv *priv = NULL;
+
+	if (!fe) {
+		pr_err("%s: invalid arg.\n", __func__);
+		return;
+	}
+	priv = (struct cxd2880_priv *)fe->demodulator_priv;
+	kfree(priv);
+}
+
+static int cxd2880_init(struct dvb_frontend *fe)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	struct cxd2880_priv *priv = NULL;
+	struct cxd2880_tnrdmd_create_param create_param;
+
+	if (!fe) {
+		pr_err("%s: invalid arg.\n", __func__);
+		return -EINVAL;
+	}
+
+	priv = (struct cxd2880_priv *)fe->demodulator_priv;
+
+	create_param.ts_output_if = CXD2880_TNRDMD_TSOUT_IF_SPI;
+	create_param.xtal_share_type = CXD2880_TNRDMD_XTAL_SHARE_NONE;
+	create_param.en_internal_ldo = 1;
+	create_param.xosc_cap = 18;
+	create_param.xosc_i = 8;
+	create_param.stationary_use = 1;
+
+	mutex_lock(priv->spi_mutex);
+	if (priv->tnrdmd.io != &priv->regio) {
+		ret = cxd2880_tnrdmd_create(&priv->tnrdmd,
+				&priv->regio, &create_param);
+		if (ret != CXD2880_RESULT_OK) {
+			mutex_unlock(priv->spi_mutex);
+			dev_info(&priv->spi->dev,
+				"%s: cxd2880 tnrdmd create failed %d\n",
+				__func__, ret);
+			return return_tbl[ret];
+		}
+	}
+	ret = cxd2880_integ_init(&priv->tnrdmd);
+	if (ret != CXD2880_RESULT_OK) {
+		mutex_unlock(priv->spi_mutex);
+		dev_err(&priv->spi->dev, "%s: cxd2880 integ init failed %d\n",
+				__func__, ret);
+		return return_tbl[ret];
+	}
+	mutex_unlock(priv->spi_mutex);
+
+	dev_dbg(&priv->spi->dev, "%s: OK.\n", __func__);
+
+	return return_tbl[ret];
+}
+
+static int cxd2880_sleep(struct dvb_frontend *fe)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	struct cxd2880_priv *priv = NULL;
+
+	if (!fe) {
+		pr_err("%s: inavlid arg\n", __func__);
+		return -EINVAL;
+	}
+
+	priv = (struct cxd2880_priv *)fe->demodulator_priv;
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_sleep(&priv->tnrdmd);
+	mutex_unlock(priv->spi_mutex);
+
+	dev_dbg(&priv->spi->dev, "%s: tnrdmd_sleep ret %d\n",
+		__func__, ret);
+
+	return return_tbl[ret];
+}
+
+static int cxd2880_read_signal_strength(struct dvb_frontend *fe,
+				u16 *strength)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	struct cxd2880_priv *priv = NULL;
+	struct dtv_frontend_properties *c = NULL;
+	int level = 0;
+
+	if ((!fe) || (!strength)) {
+		pr_err("%s: inavlid arg\n", __func__);
+		return -EINVAL;
+	}
+
+	priv = (struct cxd2880_priv *)fe->demodulator_priv;
+	c = &fe->dtv_property_cache;
+
+	mutex_lock(priv->spi_mutex);
+	if ((c->delivery_system == SYS_DVBT) ||
+		(c->delivery_system == SYS_DVBT2)) {
+		ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &level);
+	} else {
+		dev_dbg(&priv->spi->dev, "%s: invalid system\n", __func__);
+		mutex_unlock(priv->spi_mutex);
+		return -EINVAL;
+	}
+	mutex_unlock(priv->spi_mutex);
+
+	level /= 125;
+	/* -105dBm - -30dBm (-105000/125 = -840, -30000/125 = -240 */
+	level = clamp(level, -840, -240);
+	/* scale value to 0x0000-0xFFFF */
+	*strength = (u16)(((level + 840) * 0xFFFF) / (-240 + 840));
+
+	if (ret != CXD2880_RESULT_OK)
+		dev_dbg(&priv->spi->dev, "%s: ret = %d\n", __func__, ret);
+
+	return return_tbl[ret];
+}
+
+static int cxd2880_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	int snrvalue = 0;
+	struct cxd2880_priv *priv = NULL;
+	struct dtv_frontend_properties *c = NULL;
+
+	if ((!fe) || (!snr)) {
+		pr_err("%s: inavlid arg\n", __func__);
+		return -EINVAL;
+	}
+
+	priv = (struct cxd2880_priv *)fe->demodulator_priv;
+	c = &fe->dtv_property_cache;
+
+	mutex_lock(priv->spi_mutex);
+	if (c->delivery_system == SYS_DVBT) {
+		ret = cxd2880_tnrdmd_dvbt_mon_snr(&priv->tnrdmd,
+						&snrvalue);
+	} else if (c->delivery_system == SYS_DVBT2) {
+		ret = cxd2880_tnrdmd_dvbt2_mon_snr(&priv->tnrdmd,
+						&snrvalue);
+	} else {
+		dev_err(&priv->spi->dev, "%s: invalid system\n", __func__);
+		mutex_unlock(priv->spi_mutex);
+		return -EINVAL;
+	}
+	mutex_unlock(priv->spi_mutex);
+
+	if (snrvalue < 0)
+		snrvalue = 0;
+	*snr = (u16)snrvalue;
+
+	if (ret != CXD2880_RESULT_OK)
+		dev_dbg(&priv->spi->dev, "%s: ret = %d\n", __func__, ret);
+
+	return return_tbl[ret];
+}
+
+static int cxd2880_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	struct cxd2880_priv *priv = NULL;
+	struct dtv_frontend_properties *c = NULL;
+
+	if ((!fe) || (!ucblocks)) {
+		pr_err("%s: inavlid arg\n", __func__);
+		return -EINVAL;
+	}
+
+	priv = (struct cxd2880_priv *)fe->demodulator_priv;
+	c = &fe->dtv_property_cache;
+
+	mutex_lock(priv->spi_mutex);
+	if (c->delivery_system == SYS_DVBT) {
+		ret = cxd2880_tnrdmd_dvbt_mon_packet_error_number(
+								&priv->tnrdmd,
+								ucblocks);
+	} else if (c->delivery_system == SYS_DVBT2) {
+		ret = cxd2880_tnrdmd_dvbt2_mon_packet_error_number(
+								&priv->tnrdmd,
+								ucblocks);
+	} else {
+		dev_err(&priv->spi->dev, "%s: invlaid system\n", __func__);
+		mutex_unlock(priv->spi_mutex);
+		return -EINVAL;
+	}
+	mutex_unlock(priv->spi_mutex);
+
+	if (ret != CXD2880_RESULT_OK)
+		dev_dbg(&priv->spi->dev, "%s: ret = %d\n", __func__, ret);
+
+	return return_tbl[ret];
+}
+
+static int cxd2880_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	struct cxd2880_priv *priv = NULL;
+	struct dtv_frontend_properties *c = NULL;
+
+	if ((!fe) || (!ber)) {
+		pr_err("%s: inavlid arg\n", __func__);
+		return -EINVAL;
+	}
+
+	priv = (struct cxd2880_priv *)fe->demodulator_priv;
+	c = &fe->dtv_property_cache;
+
+	mutex_lock(priv->spi_mutex);
+	if (c->delivery_system == SYS_DVBT) {
+		ret = cxd2880_tnrdmd_dvbt_mon_pre_rsber(&priv->tnrdmd,
+						ber);
+		/* x100 to change unit.(10^7 -> 10^9 */
+		*ber *= 100;
+	} else if (c->delivery_system == SYS_DVBT2) {
+		ret = cxd2880_tnrdmd_dvbt2_mon_pre_bchber(&priv->tnrdmd,
+						ber);
+	} else {
+		dev_err(&priv->spi->dev, "%s: invlaid system\n", __func__);
+		mutex_unlock(priv->spi_mutex);
+		return -EINVAL;
+	}
+	mutex_unlock(priv->spi_mutex);
+
+	if (ret != CXD2880_RESULT_OK)
+		dev_dbg(&priv->spi->dev, "%s: ret = %d\n", __func__, ret);
+
+	return return_tbl[ret];
+}
+
+static int cxd2880_set_frontend(struct dvb_frontend *fe)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	struct dtv_frontend_properties *c;
+	struct cxd2880_priv *priv;
+	enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ;
+
+	if (!fe) {
+		pr_err("%s: inavlid arg\n", __func__);
+		return -EINVAL;
+	}
+
+	priv = (struct cxd2880_priv *)fe->demodulator_priv;
+	c = &fe->dtv_property_cache;
+
+	switch (c->bandwidth_hz) {
+	case 1712000:
+		bw = CXD2880_DTV_BW_1_7_MHZ;
+		break;
+	case 5000000:
+		bw = CXD2880_DTV_BW_5_MHZ;
+		break;
+	case 6000000:
+		bw = CXD2880_DTV_BW_6_MHZ;
+		break;
+	case 7000000:
+		bw = CXD2880_DTV_BW_7_MHZ;
+		break;
+	case 8000000:
+		bw = CXD2880_DTV_BW_8_MHZ;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	dev_info(&priv->spi->dev, "%s: sys:%d freq:%d bw:%d\n", __func__,
+			c->delivery_system, c->frequency, bw);
+	mutex_lock(priv->spi_mutex);
+	if (c->delivery_system == SYS_DVBT) {
+		priv->tnrdmd.sys = CXD2880_DTV_SYS_DVBT;
+		priv->dvbt_tune_param.center_freq_khz = c->frequency / 1000;
+		priv->dvbt_tune_param.bandwidth = bw;
+		priv->dvbt_tune_param.profile = CXD2880_DVBT_PROFILE_HP;
+		ret = cxd2880_integ_dvbt_tune(&priv->tnrdmd,
+						&priv->dvbt_tune_param);
+	} else if (c->delivery_system == SYS_DVBT2) {
+		priv->tnrdmd.sys = CXD2880_DTV_SYS_DVBT2;
+		priv->dvbt2_tune_param.center_freq_khz = c->frequency / 1000;
+		priv->dvbt2_tune_param.bandwidth = bw;
+		priv->dvbt2_tune_param.data_plp_id = (u16)c->stream_id;
+		ret = cxd2880_integ_dvbt2_tune(&priv->tnrdmd,
+						&priv->dvbt2_tune_param);
+	} else {
+		dev_err(&priv->spi->dev, "%s: invalid system\n", __func__);
+		mutex_unlock(priv->spi_mutex);
+		return -EINVAL;
+	}
+	mutex_unlock(priv->spi_mutex);
+	dev_info(&priv->spi->dev, "%s: tune result %d\n", __func__, ret);
+
+	return return_tbl[ret];
+}
+
+static int cxd2880_read_status(struct dvb_frontend *fe,
+				enum fe_status *status)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	u8 sync = 0;
+	u8 lock = 0;
+	u8 unlock = 0;
+	struct cxd2880_priv *priv = NULL;
+	struct dtv_frontend_properties *c = NULL;
+
+	if ((!fe) || (!status)) {
+		pr_err("%s: invalid arg\n", __func__);
+		return -EINVAL;
+	}
+
+	priv = (struct cxd2880_priv *)fe->demodulator_priv;
+	c = &fe->dtv_property_cache;
+	*status = 0;
+
+	if (priv->tnrdmd.state == CXD2880_TNRDMD_STATE_ACTIVE) {
+		mutex_lock(priv->spi_mutex);
+		if (c->delivery_system == SYS_DVBT) {
+			ret = cxd2880_tnrdmd_dvbt_mon_sync_stat(
+							&priv->tnrdmd,
+							&sync,
+							&lock,
+							&unlock);
+		} else if (c->delivery_system == SYS_DVBT2) {
+			ret = cxd2880_tnrdmd_dvbt2_mon_sync_stat(
+							&priv->tnrdmd,
+							&sync,
+							&lock,
+							&unlock);
+		} else {
+			dev_err(&priv->spi->dev,
+				"%s: invlaid system", __func__);
+			mutex_unlock(priv->spi_mutex);
+			return -EINVAL;
+		}
+
+		mutex_unlock(priv->spi_mutex);
+		if (ret != CXD2880_RESULT_OK) {
+			dev_err(&priv->spi->dev, "%s: failed. sys = %d\n",
+				__func__, priv->tnrdmd.sys);
+			return  return_tbl[ret];
+		}
+
+		if (sync == 6) {
+			*status = FE_HAS_SIGNAL |
+					FE_HAS_CARRIER;
+		}
+		if (lock)
+			*status |= FE_HAS_VITERBI |
+					FE_HAS_SYNC |
+					FE_HAS_LOCK;
+	}
+
+	dev_dbg(&priv->spi->dev, "%s: status %d result %d\n", __func__,
+		*status, ret);
+
+	return  return_tbl[CXD2880_RESULT_OK];
+}
+
+static int cxd2880_tune(struct dvb_frontend *fe,
+			bool retune,
+			unsigned int mode_flags,
+			unsigned int *delay,
+			enum fe_status *status)
+{
+	int ret = 0;
+
+	if ((!fe) || (!delay) || (!status)) {
+		pr_err("%s: invalid arg.", __func__);
+		return -EINVAL;
+	}
+
+	if (retune) {
+		ret = cxd2880_set_frontend(fe);
+		if (ret) {
+			pr_err("%s: cxd2880_set_frontend failed %d\n",
+				__func__, ret);
+			return ret;
+		}
+	}
+
+	*delay = HZ / 5;
+
+	return cxd2880_read_status(fe, status);
+}
+
+static int cxd2880_get_frontend_t(struct dvb_frontend *fe,
+				struct dtv_frontend_properties *c)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	int result = 0;
+	struct cxd2880_priv *priv = NULL;
+	enum cxd2880_dvbt_mode mode = CXD2880_DVBT_MODE_2K;
+	enum cxd2880_dvbt_guard guard = CXD2880_DVBT_GUARD_1_32;
+	struct cxd2880_dvbt_tpsinfo tps;
+	enum cxd2880_tnrdmd_spectrum_sense sense;
+	u16 snr = 0;
+	int strength = 0;
+	u32 pre_bit_err = 0, pre_bit_count = 0;
+	u32 post_bit_err = 0, post_bit_count = 0;
+	u32 block_err = 0, block_count = 0;
+
+	if ((!fe) || (!c)) {
+		pr_err("%s: invalid arg\n", __func__);
+		return -EINVAL;
+	}
+
+	priv = (struct cxd2880_priv *)fe->demodulator_priv;
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_dvbt_mon_mode_guard(&priv->tnrdmd,
+						 &mode, &guard);
+	mutex_unlock(priv->spi_mutex);
+	if (ret == CXD2880_RESULT_OK) {
+		switch (mode) {
+		case CXD2880_DVBT_MODE_2K:
+			c->transmission_mode = TRANSMISSION_MODE_2K;
+			break;
+		case CXD2880_DVBT_MODE_8K:
+			c->transmission_mode = TRANSMISSION_MODE_8K;
+			break;
+		default:
+			c->transmission_mode = TRANSMISSION_MODE_2K;
+			dev_err(&priv->spi->dev, "%s: get invalid mode %d\n",
+					__func__, mode);
+			break;
+		}
+		switch (guard) {
+		case CXD2880_DVBT_GUARD_1_32:
+			c->guard_interval = GUARD_INTERVAL_1_32;
+			break;
+		case CXD2880_DVBT_GUARD_1_16:
+			c->guard_interval = GUARD_INTERVAL_1_16;
+			break;
+		case CXD2880_DVBT_GUARD_1_8:
+			c->guard_interval = GUARD_INTERVAL_1_8;
+			break;
+		case CXD2880_DVBT_GUARD_1_4:
+			c->guard_interval = GUARD_INTERVAL_1_4;
+			break;
+		default:
+			c->guard_interval = GUARD_INTERVAL_1_32;
+			dev_err(&priv->spi->dev, "%s: get invalid guard %d\n",
+					__func__, guard);
+			break;
+		}
+	} else {
+		c->transmission_mode = TRANSMISSION_MODE_2K;
+		c->guard_interval = GUARD_INTERVAL_1_32;
+		dev_dbg(&priv->spi->dev,
+			"%s: ModeGuard err %d\n", __func__, ret);
+	}
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_dvbt_mon_tps_info(&priv->tnrdmd, &tps);
+	mutex_unlock(priv->spi_mutex);
+	if (ret == CXD2880_RESULT_OK) {
+		switch (tps.hierarchy) {
+		case CXD2880_DVBT_HIERARCHY_NON:
+			c->hierarchy = HIERARCHY_NONE;
+			break;
+		case CXD2880_DVBT_HIERARCHY_1:
+			c->hierarchy = HIERARCHY_1;
+			break;
+		case CXD2880_DVBT_HIERARCHY_2:
+			c->hierarchy = HIERARCHY_2;
+			break;
+		case CXD2880_DVBT_HIERARCHY_4:
+			c->hierarchy = HIERARCHY_4;
+			break;
+		default:
+			c->hierarchy = HIERARCHY_NONE;
+			dev_err(&priv->spi->dev,
+				"%s: TPSInfo hierarchy invalid %d\n",
+				__func__, tps.hierarchy);
+			break;
+		}
+
+		switch (tps.rate_hp) {
+		case CXD2880_DVBT_CODERATE_1_2:
+			c->code_rate_HP = FEC_1_2;
+			break;
+		case CXD2880_DVBT_CODERATE_2_3:
+			c->code_rate_HP = FEC_2_3;
+			break;
+		case CXD2880_DVBT_CODERATE_3_4:
+			c->code_rate_HP = FEC_3_4;
+			break;
+		case CXD2880_DVBT_CODERATE_5_6:
+			c->code_rate_HP = FEC_5_6;
+			break;
+		case CXD2880_DVBT_CODERATE_7_8:
+			c->code_rate_HP = FEC_7_8;
+			break;
+		default:
+			c->code_rate_HP = FEC_NONE;
+			dev_err(&priv->spi->dev,
+				"%s: TPSInfo rateHP invalid %d\n",
+				__func__, tps.rate_hp);
+			break;
+		}
+		switch (tps.rate_lp) {
+		case CXD2880_DVBT_CODERATE_1_2:
+			c->code_rate_LP = FEC_1_2;
+			break;
+		case CXD2880_DVBT_CODERATE_2_3:
+			c->code_rate_LP = FEC_2_3;
+			break;
+		case CXD2880_DVBT_CODERATE_3_4:
+			c->code_rate_LP = FEC_3_4;
+			break;
+		case CXD2880_DVBT_CODERATE_5_6:
+			c->code_rate_LP = FEC_5_6;
+			break;
+		case CXD2880_DVBT_CODERATE_7_8:
+			c->code_rate_LP = FEC_7_8;
+			break;
+		default:
+			c->code_rate_LP = FEC_NONE;
+			dev_err(&priv->spi->dev,
+				"%s: TPSInfo rateLP invalid %d\n",
+				__func__, tps.rate_lp);
+			break;
+		}
+		switch (tps.constellation) {
+		case CXD2880_DVBT_CONSTELLATION_QPSK:
+			c->modulation = QPSK;
+			break;
+		case CXD2880_DVBT_CONSTELLATION_16QAM:
+			c->modulation = QAM_16;
+			break;
+		case CXD2880_DVBT_CONSTELLATION_64QAM:
+			c->modulation = QAM_64;
+			break;
+		default:
+			c->modulation = QPSK;
+			dev_err(&priv->spi->dev,
+				"%s: TPSInfo constellation invalid %d\n",
+				__func__, tps.constellation);
+			break;
+		}
+	} else {
+		c->hierarchy = HIERARCHY_NONE;
+		c->code_rate_HP = FEC_NONE;
+		c->code_rate_LP = FEC_NONE;
+		c->modulation = QPSK;
+		dev_dbg(&priv->spi->dev,
+			"%s: TPS info err %d\n", __func__, ret);
+	}
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_dvbt_mon_spectrum_sense(&priv->tnrdmd, &sense);
+	mutex_unlock(priv->spi_mutex);
+	if (ret == CXD2880_RESULT_OK) {
+		switch (sense) {
+		case CXD2880_TNRDMD_SPECTRUM_NORMAL:
+			c->inversion = INVERSION_OFF;
+			break;
+		case CXD2880_TNRDMD_SPECTRUM_INV:
+			c->inversion = INVERSION_ON;
+			break;
+		default:
+			c->inversion = INVERSION_OFF;
+			dev_err(&priv->spi->dev,
+				"%s: spectrum sense invalid %d\n",
+				__func__, sense);
+			break;
+		}
+	} else {
+		c->inversion = INVERSION_OFF;
+		dev_dbg(&priv->spi->dev,
+			"%s: spectrum_sense %d\n", __func__, ret);
+	}
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &strength);
+	mutex_unlock(priv->spi_mutex);
+	if (ret == CXD2880_RESULT_OK) {
+		c->strength.len = 1;
+		c->strength.stat[0].scale = FE_SCALE_DECIBEL;
+		c->strength.stat[0].svalue = strength;
+	} else {
+		c->strength.len = 1;
+		c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		dev_dbg(&priv->spi->dev, "%s: mon_rf_lvl %d\n",
+			__func__, result);
+	}
+
+	result = cxd2880_read_snr(fe, &snr);
+	if (!result) {
+		c->cnr.len = 1;
+		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+		c->cnr.stat[0].svalue = snr;
+	} else {
+		c->cnr.len = 1;
+		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		dev_dbg(&priv->spi->dev, "%s: read_snr %d\n", __func__, result);
+	}
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_pre_bit_err_t(&priv->tnrdmd, &pre_bit_err,
+					&pre_bit_count);
+	mutex_unlock(priv->spi_mutex);
+	if (ret == CXD2880_RESULT_OK) {
+		c->pre_bit_error.len = 1;
+		c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+		c->pre_bit_error.stat[0].uvalue = pre_bit_err;
+		c->pre_bit_count.len = 1;
+		c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+		c->pre_bit_count.stat[0].uvalue = pre_bit_count;
+	} else {
+		c->pre_bit_error.len = 1;
+		c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		c->pre_bit_count.len = 1;
+		c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		dev_dbg(&priv->spi->dev,
+			"%s: pre_bit_error_t failed %d\n",
+			__func__, ret);
+	}
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_post_bit_err_t(&priv->tnrdmd,
+				&post_bit_err, &post_bit_count);
+	mutex_unlock(priv->spi_mutex);
+	if (ret == CXD2880_RESULT_OK) {
+		c->post_bit_error.len = 1;
+		c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+		c->post_bit_error.stat[0].uvalue = post_bit_err;
+		c->post_bit_count.len = 1;
+		c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+		c->post_bit_count.stat[0].uvalue = post_bit_count;
+	} else {
+		c->post_bit_error.len = 1;
+		c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		c->post_bit_count.len = 1;
+		c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		dev_dbg(&priv->spi->dev,
+			"%s: post_bit_err_t %d\n", __func__, ret);
+	}
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_read_block_err_t(&priv->tnrdmd,
+					&block_err, &block_count);
+	mutex_unlock(priv->spi_mutex);
+	if (ret == CXD2880_RESULT_OK) {
+		c->block_error.len = 1;
+		c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+		c->block_error.stat[0].uvalue = block_err;
+		c->block_count.len = 1;
+		c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+		c->block_count.stat[0].uvalue = block_count;
+	} else {
+		c->block_error.len = 1;
+		c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		c->block_count.len = 1;
+		c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		dev_dbg(&priv->spi->dev,
+			"%s: read_block_err_t  %d\n", __func__, ret);
+	}
+
+	return 0;
+}
+
+static int cxd2880_get_frontend_t2(struct dvb_frontend *fe,
+				struct dtv_frontend_properties *c)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	int result = 0;
+	struct cxd2880_priv *priv = NULL;
+	struct cxd2880_dvbt2_l1pre l1pre;
+	enum cxd2880_dvbt2_plp_code_rate coderate;
+	enum cxd2880_dvbt2_plp_constell qam;
+	enum cxd2880_tnrdmd_spectrum_sense sense;
+	u16 snr = 0;
+	int strength = 0;
+	u32 pre_bit_err = 0, pre_bit_count = 0;
+	u32 post_bit_err = 0, post_bit_count = 0;
+	u32 block_err = 0, block_count = 0;
+
+	if ((!fe) || (!c)) {
+		pr_err("%s: invalid arg.\n", __func__);
+		return -EINVAL;
+	}
+
+	priv = (struct cxd2880_priv *)fe->demodulator_priv;
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_dvbt2_mon_l1_pre(&priv->tnrdmd, &l1pre);
+	mutex_unlock(priv->spi_mutex);
+	if (ret == CXD2880_RESULT_OK) {
+		switch (l1pre.fft_mode) {
+		case CXD2880_DVBT2_M2K:
+			c->transmission_mode = TRANSMISSION_MODE_2K;
+			break;
+		case CXD2880_DVBT2_M8K:
+			c->transmission_mode = TRANSMISSION_MODE_8K;
+			break;
+		case CXD2880_DVBT2_M4K:
+			c->transmission_mode = TRANSMISSION_MODE_4K;
+			break;
+		case CXD2880_DVBT2_M1K:
+			c->transmission_mode = TRANSMISSION_MODE_1K;
+			break;
+		case CXD2880_DVBT2_M16K:
+			c->transmission_mode = TRANSMISSION_MODE_16K;
+			break;
+		case CXD2880_DVBT2_M32K:
+			c->transmission_mode = TRANSMISSION_MODE_32K;
+			break;
+		default:
+			c->transmission_mode = TRANSMISSION_MODE_2K;
+			dev_err(&priv->spi->dev,
+				"%s: L1Pre fft_mode invalid %d\n",
+				__func__, l1pre.fft_mode);
+			break;
+		}
+		switch (l1pre.gi) {
+		case CXD2880_DVBT2_G1_32:
+			c->guard_interval = GUARD_INTERVAL_1_32;
+			break;
+		case CXD2880_DVBT2_G1_16:
+			c->guard_interval = GUARD_INTERVAL_1_16;
+			break;
+		case CXD2880_DVBT2_G1_8:
+			c->guard_interval = GUARD_INTERVAL_1_8;
+			break;
+		case CXD2880_DVBT2_G1_4:
+			c->guard_interval = GUARD_INTERVAL_1_4;
+			break;
+		case CXD2880_DVBT2_G1_128:
+			c->guard_interval = GUARD_INTERVAL_1_128;
+			break;
+		case CXD2880_DVBT2_G19_128:
+			c->guard_interval = GUARD_INTERVAL_19_128;
+			break;
+		case CXD2880_DVBT2_G19_256:
+			c->guard_interval = GUARD_INTERVAL_19_256;
+			break;
+		default:
+			c->guard_interval = GUARD_INTERVAL_1_32;
+			dev_err(&priv->spi->dev,
+				"%s: L1Pre gi invalid %d\n",
+				__func__, l1pre.gi);
+			break;
+		}
+	} else {
+		c->transmission_mode = TRANSMISSION_MODE_2K;
+		c->guard_interval = GUARD_INTERVAL_1_32;
+		dev_dbg(&priv->spi->dev,
+			"%s: L1Pre err %d\n", __func__, ret);
+	}
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_dvbt2_mon_code_rate(&priv->tnrdmd,
+						CXD2880_DVBT2_PLP_DATA,
+						&coderate);
+	mutex_unlock(priv->spi_mutex);
+	if (ret == CXD2880_RESULT_OK) {
+		switch (coderate) {
+		case CXD2880_DVBT2_R1_2:
+			c->fec_inner = FEC_1_2;
+			break;
+		case CXD2880_DVBT2_R3_5:
+			c->fec_inner = FEC_3_5;
+			break;
+		case CXD2880_DVBT2_R2_3:
+			c->fec_inner = FEC_2_3;
+			break;
+		case CXD2880_DVBT2_R3_4:
+			c->fec_inner = FEC_3_4;
+			break;
+		case CXD2880_DVBT2_R4_5:
+			c->fec_inner = FEC_4_5;
+			break;
+		case CXD2880_DVBT2_R5_6:
+			c->fec_inner = FEC_5_6;
+			break;
+		default:
+			c->fec_inner = FEC_NONE;
+			dev_err(&priv->spi->dev,
+				"%s: CodeRate invalid %d\n",
+				__func__, coderate);
+			break;
+		}
+	} else {
+		c->fec_inner = FEC_NONE;
+		dev_dbg(&priv->spi->dev, "%s: CodeRate %d\n", __func__, ret);
+	}
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_dvbt2_mon_qam(&priv->tnrdmd,
+					CXD2880_DVBT2_PLP_DATA,
+					&qam);
+	mutex_unlock(priv->spi_mutex);
+	if (ret == CXD2880_RESULT_OK) {
+		switch (qam) {
+		case CXD2880_DVBT2_QPSK:
+			c->modulation = QPSK;
+			break;
+		case CXD2880_DVBT2_QAM16:
+			c->modulation = QAM_16;
+			break;
+		case CXD2880_DVBT2_QAM64:
+			c->modulation = QAM_64;
+			break;
+		case CXD2880_DVBT2_QAM256:
+			c->modulation = QAM_256;
+			break;
+		default:
+			c->modulation = QPSK;
+			dev_err(&priv->spi->dev,
+				"%s: QAM invalid %d\n",
+				__func__, qam);
+			break;
+		}
+	} else {
+		c->modulation = QPSK;
+		dev_dbg(&priv->spi->dev, "%s: QAM %d\n", __func__, ret);
+	}
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(&priv->tnrdmd, &sense);
+	mutex_unlock(priv->spi_mutex);
+	if (ret == CXD2880_RESULT_OK) {
+		switch (sense) {
+		case CXD2880_TNRDMD_SPECTRUM_NORMAL:
+			c->inversion = INVERSION_OFF;
+			break;
+		case CXD2880_TNRDMD_SPECTRUM_INV:
+			c->inversion = INVERSION_ON;
+			break;
+		default:
+			c->inversion = INVERSION_OFF;
+			dev_err(&priv->spi->dev,
+				"%s: spectrum sense invalid %d\n",
+				__func__, sense);
+			break;
+		}
+	} else {
+		c->inversion = INVERSION_OFF;
+		dev_dbg(&priv->spi->dev,
+			"%s: SpectrumSense %d\n", __func__, ret);
+	}
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &strength);
+	mutex_unlock(priv->spi_mutex);
+	if (ret == CXD2880_RESULT_OK) {
+		c->strength.len = 1;
+		c->strength.stat[0].scale = FE_SCALE_DECIBEL;
+		c->strength.stat[0].svalue = strength;
+	} else {
+		c->strength.len = 1;
+		c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		dev_dbg(&priv->spi->dev,
+			"%s: mon_rf_lvl %d\n", __func__, ret);
+	}
+
+	result = cxd2880_read_snr(fe, &snr);
+	if (!result) {
+		c->cnr.len = 1;
+		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+		c->cnr.stat[0].svalue = snr;
+	} else {
+		c->cnr.len = 1;
+		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		dev_dbg(&priv->spi->dev, "%s: read_snr %d\n", __func__, result);
+	}
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_pre_bit_err_t2(&priv->tnrdmd,
+				&pre_bit_err,
+				&pre_bit_count);
+	mutex_unlock(priv->spi_mutex);
+	if (ret == CXD2880_RESULT_OK) {
+		c->pre_bit_error.len = 1;
+		c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+		c->pre_bit_error.stat[0].uvalue = pre_bit_err;
+		c->pre_bit_count.len = 1;
+		c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+		c->pre_bit_count.stat[0].uvalue = pre_bit_count;
+	} else {
+		c->pre_bit_error.len = 1;
+		c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		c->pre_bit_count.len = 1;
+		c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		dev_dbg(&priv->spi->dev,
+			"%s: read_bit_err_t2 %d\n", __func__, ret);
+	}
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_post_bit_err_t2(&priv->tnrdmd,
+				&post_bit_err, &post_bit_count);
+	mutex_unlock(priv->spi_mutex);
+	if (ret == CXD2880_RESULT_OK) {
+		c->post_bit_error.len = 1;
+		c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+		c->post_bit_error.stat[0].uvalue = post_bit_err;
+		c->post_bit_count.len = 1;
+		c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+		c->post_bit_count.stat[0].uvalue = post_bit_count;
+	} else {
+		c->post_bit_error.len = 1;
+		c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		c->post_bit_count.len = 1;
+		c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		dev_dbg(&priv->spi->dev,
+			"%s: post_bit_err_t2 %d\n", __func__, ret);
+	}
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_read_block_err_t2(&priv->tnrdmd,
+					&block_err, &block_count);
+	mutex_unlock(priv->spi_mutex);
+	if (ret == CXD2880_RESULT_OK) {
+		c->block_error.len = 1;
+		c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+		c->block_error.stat[0].uvalue = block_err;
+		c->block_count.len = 1;
+		c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+		c->block_count.stat[0].uvalue = block_count;
+	} else {
+		c->block_error.len = 1;
+		c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		c->block_count.len = 1;
+		c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		dev_dbg(&priv->spi->dev,
+			"%s: read_block_err_t2 %d\n", __func__, ret);
+	}
+
+	return 0;
+}
+
+static int cxd2880_get_frontend(struct dvb_frontend *fe,
+				struct dtv_frontend_properties *props)
+{
+	struct cxd2880_priv *priv = NULL;
+	int result = 0;
+
+	if ((!fe) || (!props)) {
+		pr_err("%s: invalid arg.", __func__);
+		return -EINVAL;
+	}
+
+	priv = (struct cxd2880_priv *)fe->demodulator_priv;
+
+	dev_dbg(&priv->spi->dev, "%s: system=%d\n", __func__,
+		fe->dtv_property_cache.delivery_system);
+	switch (fe->dtv_property_cache.delivery_system) {
+	case SYS_DVBT:
+		result = cxd2880_get_frontend_t(fe, props);
+		break;
+	case SYS_DVBT2:
+		result = cxd2880_get_frontend_t2(fe, props);
+		break;
+	default:
+		result = -EINVAL;
+		break;
+	}
+
+	return result;
+}
+
+static enum dvbfe_algo cxd2880_get_frontend_algo(struct dvb_frontend *fe)
+{
+	return DVBFE_ALGO_HW;
+}
+
+static struct dvb_frontend_ops cxd2880_dvbt_t2_ops;
+
+struct dvb_frontend *cxd2880_attach(struct dvb_frontend *fe,
+				struct cxd2880_config *cfg)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	enum cxd2880_tnrdmd_chip_id chipid =
+					CXD2880_TNRDMD_CHIP_ID_UNKNOWN;
+	static struct cxd2880_priv *priv;
+	u8 data = 0;
+
+	if (!fe) {
+		pr_err("%s: invalid arg.\n", __func__);
+		return NULL;
+	}
+
+	priv = kzalloc(sizeof(struct cxd2880_priv), GFP_KERNEL);
+	if (!priv)
+		return NULL;
+
+	priv->spi = cfg->spi;
+	priv->spi_mutex = cfg->spi_mutex;
+	priv->spi_device.spi = cfg->spi;
+
+	memcpy(&fe->ops, &cxd2880_dvbt_t2_ops,
+			sizeof(struct dvb_frontend_ops));
+
+	ret = cxd2880_spi_device_initialize(&priv->spi_device,
+						CXD2880_SPI_MODE_0,
+						55000000);
+	if (ret != CXD2880_RESULT_OK) {
+		dev_err(&priv->spi->dev,
+			"%s: spi_device_initialize failed. %d\n",
+			__func__, ret);
+		kfree(priv);
+		return NULL;
+	}
+
+	ret = cxd2880_spi_device_create_spi(&priv->cxd2880_spi,
+					&priv->spi_device);
+	if (ret != CXD2880_RESULT_OK) {
+		dev_err(&priv->spi->dev,
+			"%s: spi_device_create_spi failed. %d\n",
+			__func__, ret);
+		kfree(priv);
+		return NULL;
+	}
+
+	ret = cxd2880_io_spi_create(&priv->regio, &priv->cxd2880_spi, 0);
+	if (ret != CXD2880_RESULT_OK) {
+		dev_err(&priv->spi->dev,
+			"%s: io_spi_create failed. %d\n", __func__, ret);
+		kfree(priv);
+		return NULL;
+	}
+	if (priv->regio.write_reg(&priv->regio, CXD2880_IO_TGT_SYS, 0x00, 0x00)
+		!= CXD2880_RESULT_OK) {
+		dev_err(&priv->spi->dev,
+			"%s: set bank to 0x00 failed.\n", __func__);
+		kfree(priv);
+		return NULL;
+	}
+	if (priv->regio.read_regs(&priv->regio,
+					CXD2880_IO_TGT_SYS, 0xFD, &data, 1)
+					!= CXD2880_RESULT_OK) {
+		dev_err(&priv->spi->dev,
+			"%s: read chip id failed.\n", __func__);
+		kfree(priv);
+		return NULL;
+	}
+
+	chipid = (enum cxd2880_tnrdmd_chip_id)data;
+	if ((chipid != CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) &&
+		(chipid != CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11)) {
+		dev_err(&priv->spi->dev,
+			"%s: chip id invalid.\n", __func__);
+		kfree(priv);
+		return NULL;
+	}
+
+	fe->demodulator_priv = priv;
+	dev_info(&priv->spi->dev,
+		"CXD2880 driver version: Ver %s\n",
+		CXD2880_TNRDMD_DRIVER_VERSION);
+
+	return fe;
+}
+EXPORT_SYMBOL(cxd2880_attach);
+
+static struct dvb_frontend_ops cxd2880_dvbt_t2_ops = {
+	.info = {
+		.name = "Sony CXD2880",
+		.frequency_min =  174000000,
+		.frequency_max = 862000000,
+		.frequency_stepsize = 1000,
+		.caps = FE_CAN_INVERSION_AUTO |
+				FE_CAN_FEC_1_2 |
+				FE_CAN_FEC_2_3 |
+				FE_CAN_FEC_3_4 |
+				FE_CAN_FEC_4_5 |
+				FE_CAN_FEC_5_6	|
+				FE_CAN_FEC_7_8	|
+				FE_CAN_FEC_AUTO |
+				FE_CAN_QPSK |
+				FE_CAN_QAM_16 |
+				FE_CAN_QAM_32 |
+				FE_CAN_QAM_64 |
+				FE_CAN_QAM_128 |
+				FE_CAN_QAM_256 |
+				FE_CAN_QAM_AUTO |
+				FE_CAN_TRANSMISSION_MODE_AUTO |
+				FE_CAN_GUARD_INTERVAL_AUTO |
+				FE_CAN_2G_MODULATION |
+				FE_CAN_RECOVER |
+				FE_CAN_MUTE_TS,
+	},
+	.delsys = { SYS_DVBT, SYS_DVBT2 },
+
+	.release = cxd2880_release,
+	.init = cxd2880_init,
+	.sleep = cxd2880_sleep,
+	.tune = cxd2880_tune,
+	.set_frontend = cxd2880_set_frontend,
+	.get_frontend = cxd2880_get_frontend,
+	.read_status = cxd2880_read_status,
+	.read_ber = cxd2880_read_ber,
+	.read_signal_strength = cxd2880_read_signal_strength,
+	.read_snr = cxd2880_read_snr,
+	.read_ucblocks = cxd2880_read_ucblocks,
+	.get_frontend_algo = cxd2880_get_frontend_algo,
+};
+
+MODULE_DESCRIPTION(
+"Sony CXD2880 DVB-T2/T tuner + demodulator drvier");
+MODULE_AUTHOR("Sony Semiconductor Solutions Corporation");
+MODULE_LICENSE("GPL v2");
-- 
2.11.0

^ permalink raw reply related

* [PATCH v2 07/15] [media] cxd2880: Add integration layer for the driver
From: Yasunari.Takiguchi @ 2017-04-14  2:29 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-media
  Cc: tbird20d, frowand.list, Yasunari Takiguchi, Masayuki Yamamoto,
	Hideki Nozawa, Kota Yonezawa, Toshihiko Matsumoto,
	Satoshi Watanabe
In-Reply-To: <20170414015043.16731-1-Yasunari.Takiguchi@sony.com>

From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

These functions monitor the driver and watch for task completion.
This is part of the Sony CXD2880 DVB-T2/T tuner + demodulator driver.

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
---
 .../media/dvb-frontends/cxd2880/cxd2880_integ.c    | 99 ++++++++++++++++++++++
 .../media/dvb-frontends/cxd2880/cxd2880_integ.h    | 44 ++++++++++
 2 files changed, 143 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h

diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c
new file mode 100644
index 000000000000..5ad6685e2a1d
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c
@@ -0,0 +1,99 @@
+/*
+ * cxd2880_integ.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * integration layer common functions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_tnrdmd.h"
+#include "cxd2880_tnrdmd_mon.h"
+#include "cxd2880_integ.h"
+
+enum cxd2880_ret cxd2880_integ_init(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	struct cxd2880_stopwatch timer;
+	u32 elapsed_time = 0;
+	u8 cpu_task_completed = 0;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	ret = cxd2880_tnrdmd_init1(tnr_dmd);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	ret = cxd2880_stopwatch_start(&timer);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	while (1) {
+		ret = cxd2880_stopwatch_elapsed(&timer, &elapsed_time);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		ret =
+		    cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd,
+						     &cpu_task_completed);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		if (cpu_task_completed)
+			break;
+
+		if (elapsed_time > CXD2880_TNRDMD_WAIT_INIT_TIMEOUT)
+			return CXD2880_RESULT_ERROR_TIMEOUT;
+		ret =
+		    cxd2880_stopwatch_sleep(&timer,
+					    CXD2880_TNRDMD_WAIT_INIT_INTVL);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	}
+
+	ret = cxd2880_tnrdmd_init2(tnr_dmd);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_integ_cancel(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	cxd2880_atomic_set(&tnr_dmd->cancel, 1);
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_integ_check_cancellation(struct cxd2880_tnrdmd
+						  *tnr_dmd)
+{
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (cxd2880_atomic_read(&tnr_dmd->cancel) != 0)
+		return CXD2880_RESULT_ERROR_CANCEL;
+
+	return CXD2880_RESULT_OK;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h
new file mode 100644
index 000000000000..9cfc52dbf9d4
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h
@@ -0,0 +1,44 @@
+/*
+ * cxd2880_integ.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * integration layer common interface
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_INTEG_H
+#define CXD2880_INTEG_H
+
+#include "cxd2880_tnrdmd.h"
+
+#define CXD2880_TNRDMD_WAIT_INIT_TIMEOUT	500
+#define CXD2880_TNRDMD_WAIT_INIT_INTVL	10
+
+#define CXD2880_TNRDMD_WAIT_AGC_STABLE		100
+
+enum cxd2880_ret cxd2880_integ_init(struct cxd2880_tnrdmd *tnr_dmd);
+
+enum cxd2880_ret cxd2880_integ_cancel(struct cxd2880_tnrdmd *tnr_dmd);
+
+enum cxd2880_ret cxd2880_integ_check_cancellation(struct cxd2880_tnrdmd
+						  *tnr_dmd);
+
+#endif
-- 
2.11.0

^ permalink raw reply related

* [PATCH v2 06/15] [media] cxd2880: Add tuner part of the driver
From: Yasunari.Takiguchi-7U/KSKJipcs @ 2017-04-14  2:26 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA
  Cc: tbird20d-Re5JQEeQqe8AvxtiuMwx3w,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w, Yasunari Takiguchi,
	Masayuki Yamamoto, Hideki Nozawa, Kota Yonezawa,
	Toshihiko Matsumoto, Satoshi Watanabe
In-Reply-To: <20170414015043.16731-1-Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>

From: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>

This part of the driver has the main routines to handle
the tuner and demodulator functionality.  The tnrdmd_mon.* files
have monitor functions for the driver.
This is part of the Sony CXD2880 DVB-T2/T tuner + demodulator driver.

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe-7U/KSKJipcs@public.gmane.org>
---
 drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h  |   50 +
 .../media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c   | 3925 ++++++++++++++++++++
 .../media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h   |  395 ++
 .../cxd2880/cxd2880_tnrdmd_driver_version.h        |   29 +
 .../dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c     |  207 ++
 .../dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h     |   52 +
 6 files changed, 4658 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h

diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
new file mode 100644
index 000000000000..7de098d556fe
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
@@ -0,0 +1,50 @@
+/*
+ * cxd2880_dtv.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * DTV related definitions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_DTV_H
+#define CXD2880_DTV_H
+
+enum cxd2880_dtv_sys {
+	CXD2880_DTV_SYS_UNKNOWN,
+	CXD2880_DTV_SYS_DVBT,
+	CXD2880_DTV_SYS_DVBT2,
+	CXD2880_DTV_SYS_ISDBT,
+	CXD2880_DTV_SYS_ISDBTSB,
+	CXD2880_DTV_SYS_ISDBTMM_A,
+	CXD2880_DTV_SYS_ISDBTMM_B,
+	CXD2880_DTV_SYS_ANY
+};
+
+enum cxd2880_dtv_bandwidth {
+	CXD2880_DTV_BW_UNKNOWN = 0,
+	CXD2880_DTV_BW_1_7_MHZ = 1,
+	CXD2880_DTV_BW_5_MHZ = 5,
+	CXD2880_DTV_BW_6_MHZ = 6,
+	CXD2880_DTV_BW_7_MHZ = 7,
+	CXD2880_DTV_BW_8_MHZ = 8
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
new file mode 100644
index 000000000000..286384ae0124
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
@@ -0,0 +1,3925 @@
+/*
+ * cxd2880_tnrdmd.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * common control functions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_common.h"
+#include "cxd2880_stdlib.h"
+#include "cxd2880_tnrdmd.h"
+#include "cxd2880_tnrdmd_mon.h"
+#include "cxd2880_tnrdmd_dvbt.h"
+#include "cxd2880_tnrdmd_dvbt2.h"
+
+static enum cxd2880_ret p_init1(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	u8 data = 0;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if ((tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) ||
+	    (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)) {
+		switch (tnr_dmd->create_param.ts_output_if) {
+		case CXD2880_TNRDMD_TSOUT_IF_TS:
+			data = 0x00;
+			break;
+		case CXD2880_TNRDMD_TSOUT_IF_SPI:
+			data = 0x01;
+			break;
+		case CXD2880_TNRDMD_TSOUT_IF_SDIO:
+			data = 0x02;
+			break;
+		default:
+			return CXD2880_RESULT_ERROR_ARG;
+		}
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_SYS, 0x10,
+					   data) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x11,
+				   0x16) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x10) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	switch (tnr_dmd->chip_id) {
+	case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X:
+		data = 0x1A;
+		break;
+	case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11:
+		data = 0x16;
+		break;
+	default:
+		return CXD2880_RESULT_ERROR_NOSUPPORT;
+	}
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x10,
+				   data) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->create_param.en_internal_ldo)
+		data = 0x01;
+	else
+		data = 0x00;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x11,
+				   data) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x13,
+				   data) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x12,
+				   data) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x10) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	switch (tnr_dmd->chip_id) {
+	case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X:
+		data = 0x01;
+		break;
+	case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11:
+		data = 0x00;
+		break;
+	default:
+		return CXD2880_RESULT_ERROR_NOSUPPORT;
+	}
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x69,
+				   data) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	return CXD2880_RESULT_OK;
+}
+
+static enum cxd2880_ret p_init2(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	u8 data[6] = { 0 };
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	data[0] = tnr_dmd->create_param.xosc_cap;
+	data[1] = tnr_dmd->create_param.xosc_i;
+	switch (tnr_dmd->create_param.xtal_share_type) {
+	case CXD2880_TNRDMD_XTAL_SHARE_NONE:
+		data[2] = 0x01;
+		data[3] = 0x00;
+		break;
+	case CXD2880_TNRDMD_XTAL_SHARE_EXTREF:
+		data[2] = 0x00;
+		data[3] = 0x00;
+		break;
+	case CXD2880_TNRDMD_XTAL_SHARE_MASTER:
+		data[2] = 0x01;
+		data[3] = 0x01;
+		break;
+	case CXD2880_TNRDMD_XTAL_SHARE_SLAVE:
+		data[2] = 0x00;
+		data[3] = 0x01;
+		break;
+	default:
+		return CXD2880_RESULT_ERROR_ARG;
+	}
+	data[4] = 0x06;
+	data[5] = 0x00;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0x13, data,
+				    6) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	return CXD2880_RESULT_OK;
+}
+
+static enum cxd2880_ret p_init3(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	u8 data[2] = { 0 };
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	switch (tnr_dmd->diver_mode) {
+	case CXD2880_TNRDMD_DIVERMODE_SINGLE:
+		data[0] = 0x00;
+		break;
+	case CXD2880_TNRDMD_DIVERMODE_MAIN:
+		data[0] = 0x03;
+		break;
+	case CXD2880_TNRDMD_DIVERMODE_SUB:
+		data[0] = 0x02;
+		break;
+	default:
+		return CXD2880_RESULT_ERROR_ARG;
+	}
+
+	data[1] = 0x01;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0x1F, data,
+				    2) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	return CXD2880_RESULT_OK;
+}
+
+static enum cxd2880_ret rf_init1(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	u8 data[80] = { 0 };
+	u8 addr = 0;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	data[0] = 0x01;
+	data[1] = 0x00;
+	data[2] = 0x01;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0x21, data,
+				    3) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x10) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	data[0] = 0x01;
+	data[1] = 0x01;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0x17, data,
+				    2) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->create_param.stationary_use) {
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_SYS, 0x1A,
+					   0x06) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x4F,
+				   0x18) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x61,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x71,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x9D,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x7D,
+				   0x02) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x8F,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x8B,
+				   0xC6) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x9A,
+				   0x03) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x1C,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	data[0] = 0x00;
+	if ((tnr_dmd->create_param.is_cxd2881gg) &&
+	    (tnr_dmd->create_param.xtal_share_type ==
+		CXD2880_TNRDMD_XTAL_SHARE_SLAVE))
+		data[1] = 0x00;
+	else
+		data[1] = 0x1F;
+	data[2] = 0x0A;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0xB5, data,
+				    3) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0xB9,
+				   0x07) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x33,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0xC1,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0xC4,
+				   0x1E) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->chip_id == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) {
+		data[0] = 0x34;
+		data[1] = 0x2C;
+	} else {
+		data[0] = 0x2F;
+		data[1] = 0x25;
+	}
+	data[2] = 0x15;
+	data[3] = 0x19;
+	data[4] = 0x1B;
+	data[5] = 0x15;
+	data[6] = 0x19;
+	data[7] = 0x1B;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0xD9, data,
+				    8) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x11) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	data[0] = 0x6C;
+	data[1] = 0x10;
+	data[2] = 0xA6;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0x44, data,
+				    3) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	data[0] = 0x16;
+	data[1] = 0xA8;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0x50, data,
+				    2) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	data[0] = 0x00;
+	data[1] = 0x22;
+	data[2] = 0x00;
+	data[3] = 0x88;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0x62, data,
+				    4) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x74,
+				   0x75) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	data[0] = 0x05;
+	data[1] = 0x05;
+	data[2] = 0x05;
+	data[3] = 0x05;
+	data[4] = 0x05;
+	data[5] = 0x05;
+	data[6] = 0x05;
+	data[7] = 0x05;
+	data[8] = 0x05;
+	data[9] = 0x04;
+	data[10] = 0x04;
+	data[11] = 0x04;
+	data[12] = 0x03;
+	data[13] = 0x03;
+	data[14] = 0x03;
+	data[15] = 0x04;
+	data[16] = 0x04;
+	data[17] = 0x05;
+	data[18] = 0x05;
+	data[19] = 0x05;
+	data[20] = 0x02;
+	data[21] = 0x02;
+	data[22] = 0x02;
+	data[23] = 0x02;
+	data[24] = 0x02;
+	data[25] = 0x02;
+	data[26] = 0x02;
+	data[27] = 0x02;
+	data[28] = 0x02;
+	data[29] = 0x03;
+	data[30] = 0x02;
+	data[31] = 0x01;
+	data[32] = 0x01;
+	data[33] = 0x01;
+	data[34] = 0x02;
+	data[35] = 0x02;
+	data[36] = 0x03;
+	data[37] = 0x04;
+	data[38] = 0x04;
+	data[39] = 0x04;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0x7F, data,
+				    40) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x16) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	data[0] = 0x00;
+	data[1] = 0x71;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0x10, data,
+				    2) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x23,
+				   0x89) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	data[0] = 0xFF;
+	data[1] = 0x00;
+	data[2] = 0x00;
+	data[3] = 0x00;
+	data[4] = 0x00;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0x27, data,
+				    5) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	data[0] = 0x00;
+	data[1] = 0x00;
+	data[2] = 0x00;
+	data[3] = 0x00;
+	data[4] = 0x00;
+	data[5] = 0x01;
+	data[6] = 0x00;
+	data[7] = 0x01;
+	data[8] = 0x00;
+	data[9] = 0x02;
+	data[10] = 0x00;
+	data[11] = 0x63;
+	data[12] = 0x00;
+	data[13] = 0x00;
+	data[14] = 0x00;
+	data[15] = 0x03;
+	data[16] = 0x00;
+	data[17] = 0x04;
+	data[18] = 0x00;
+	data[19] = 0x04;
+	data[20] = 0x00;
+	data[21] = 0x06;
+	data[22] = 0x00;
+	data[23] = 0x06;
+	data[24] = 0x00;
+	data[25] = 0x08;
+	data[26] = 0x00;
+	data[27] = 0x09;
+	data[28] = 0x00;
+	data[29] = 0x0B;
+	data[30] = 0x00;
+	data[31] = 0x0B;
+	data[32] = 0x00;
+	data[33] = 0x0D;
+	data[34] = 0x00;
+	data[35] = 0x0D;
+	data[36] = 0x00;
+	data[37] = 0x0F;
+	data[38] = 0x00;
+	data[39] = 0x0F;
+	data[40] = 0x00;
+	data[41] = 0x0F;
+	data[42] = 0x00;
+	data[43] = 0x10;
+	data[44] = 0x00;
+	data[45] = 0x79;
+	data[46] = 0x00;
+	data[47] = 0x00;
+	data[48] = 0x00;
+	data[49] = 0x02;
+	data[50] = 0x00;
+	data[51] = 0x00;
+	data[52] = 0x00;
+	data[53] = 0x03;
+	data[54] = 0x00;
+	data[55] = 0x01;
+	data[56] = 0x00;
+	data[57] = 0x03;
+	data[58] = 0x00;
+	data[59] = 0x03;
+	data[60] = 0x00;
+	data[61] = 0x03;
+	data[62] = 0x00;
+	data[63] = 0x04;
+	data[64] = 0x00;
+	data[65] = 0x04;
+	data[66] = 0x00;
+	data[67] = 0x06;
+	data[68] = 0x00;
+	data[69] = 0x05;
+	data[70] = 0x00;
+	data[71] = 0x07;
+	data[72] = 0x00;
+	data[73] = 0x07;
+	data[74] = 0x00;
+	data[75] = 0x08;
+	data[76] = 0x00;
+	data[77] = 0x0A;
+	data[78] = 0x03;
+	data[79] = 0xE0;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0x3A, data,
+				    80) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	data[0] = 0x03;
+	data[1] = 0xE0;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0xBC, data,
+				    2) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x10) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x51,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0xC5,
+				   0x07) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x11) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x70,
+				   0xE9) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x76,
+				   0x0A) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x78,
+				   0x32) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x7A,
+				   0x46) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x7C,
+				   0x86) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x7E,
+				   0xA4) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x10) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0xE1,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->create_param.stationary_use) {
+		data[0] = 0x06;
+		data[1] = 0x07;
+		data[2] = 0x1A;
+	} else {
+		data[0] = 0x00;
+		data[1] = 0x08;
+		data[2] = 0x19;
+	}
+	data[3] = 0x0E;
+	data[4] = 0x09;
+	data[5] = 0x0E;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x12) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	for (addr = 0x10; addr < 0x9F; addr += 6) {
+		if (tnr_dmd->lna_thrs_tbl_air) {
+			u8 idx = 0;
+
+			idx = (addr - 0x10) / 6;
+			data[0] =
+			    tnr_dmd->lna_thrs_tbl_air->thrs[idx].off_on;
+			data[1] =
+			    tnr_dmd->lna_thrs_tbl_air->thrs[idx].on_off;
+		}
+		if (tnr_dmd->io->write_regs(tnr_dmd->io,
+					    CXD2880_IO_TGT_SYS, addr,
+					    data,
+					    6) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	}
+
+	data[0] = 0x00;
+	data[1] = 0x08;
+	if (tnr_dmd->create_param.stationary_use)
+		data[2] = 0x1A;
+	else
+		data[2] = 0x19;
+	data[3] = 0x0E;
+	data[4] = 0x09;
+	data[5] = 0x0E;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x13) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	for (addr = 0x10; addr < 0xCF; addr += 6) {
+		if (tnr_dmd->lna_thrs_tbl_cable) {
+			u8 idx = 0;
+
+			idx = (addr - 0x10) / 6;
+			data[0] =
+			    tnr_dmd->lna_thrs_tbl_cable->thrs[idx].off_on;
+			data[1] =
+			    tnr_dmd->lna_thrs_tbl_cable->thrs[idx].on_off;
+		}
+		if (tnr_dmd->io->write_regs(tnr_dmd->io,
+					    CXD2880_IO_TGT_SYS, addr,
+					    data,
+					    6) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x11) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	data[0] = 0x08;
+	data[1] = 0x09;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0xBD, data,
+				    2) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	data[0] = 0x08;
+	data[1] = 0x09;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0xC4, data,
+				    2) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	data[0] = 0x20;
+	data[1] = 0x20;
+	data[2] = 0x30;
+	data[3] = 0x41;
+	data[4] = 0x50;
+	data[5] = 0x5F;
+	data[6] = 0x6F;
+	data[7] = 0x80;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0xC9, data,
+				    8) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x14) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	data[0] = 0x15;
+	data[1] = 0x18;
+	data[2] = 0x00;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0x10, data,
+				    3) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x15,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x16) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	data[0] = 0x00;
+	data[1] = 0x09;
+	data[2] = 0x00;
+	data[3] = 0x08;
+	data[4] = 0x00;
+	data[5] = 0x07;
+	data[6] = 0x00;
+	data[7] = 0x06;
+	data[8] = 0x00;
+	data[9] = 0x05;
+	data[10] = 0x00;
+	data[11] = 0x03;
+	data[12] = 0x00;
+	data[13] = 0x02;
+	data[14] = 0x00;
+	data[15] = 0x00;
+	data[16] = 0x00;
+	data[17] = 0x78;
+	data[18] = 0x00;
+	data[19] = 0x00;
+	data[20] = 0x00;
+	data[21] = 0x06;
+	data[22] = 0x00;
+	data[23] = 0x08;
+	data[24] = 0x00;
+	data[25] = 0x08;
+	data[26] = 0x00;
+	data[27] = 0x0C;
+	data[28] = 0x00;
+	data[29] = 0x0C;
+	data[30] = 0x00;
+	data[31] = 0x0D;
+	data[32] = 0x00;
+	data[33] = 0x0F;
+	data[34] = 0x00;
+	data[35] = 0x0E;
+	data[36] = 0x00;
+	data[37] = 0x0E;
+	data[38] = 0x00;
+	data[39] = 0x10;
+	data[40] = 0x00;
+	data[41] = 0x0F;
+	data[42] = 0x00;
+	data[43] = 0x0E;
+	data[44] = 0x00;
+	data[45] = 0x10;
+	data[46] = 0x00;
+	data[47] = 0x0F;
+	data[48] = 0x00;
+	data[49] = 0x0E;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0x12, data,
+				    50) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	CXD2880_SLEEP(1);
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x0A) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x10, data,
+				   1) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if ((data[0] & 0x01) == 0x00)
+		return CXD2880_RESULT_ERROR_HW_STATE;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x25,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	CXD2880_SLEEP(1);
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x0A) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x11, data,
+				   1) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if ((data[0] & 0x01) == 0x00)
+		return CXD2880_RESULT_ERROR_HW_STATE;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x02,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x21,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0xE1) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x8F,
+				   0x16) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x67,
+				   0x60) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x6A,
+				   0x0F) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x6C,
+				   0x17) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	data[0] = 0x00;
+	data[1] = 0xFE;
+	data[2] = 0xEE;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_DMD, 0x6E, data,
+				    3) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	data[0] = 0xA1;
+	data[1] = 0x8B;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_DMD, 0x8D, data,
+				    2) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	data[0] = 0x08;
+	data[1] = 0x09;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_DMD, 0x77, data,
+				    2) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->create_param.stationary_use) {
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x80,
+					   0xAA) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0xE2) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x41,
+				   0xA0) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x4B,
+				   0x68) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x21,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x10,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x10) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x25,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	CXD2880_SLEEP(1);
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x1A) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x10, data,
+				   1) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if ((data[0] & 0x01) == 0x00)
+		return CXD2880_RESULT_ERROR_HW_STATE;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x10) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x14,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x26,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	return CXD2880_RESULT_OK;
+}
+
+static enum cxd2880_ret rf_init2(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	u8 data[5] = { 0 };
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x10) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	data[0] = 0x40;
+	data[1] = 0x40;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0xEA, data,
+				    2) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	CXD2880_SLEEP(1);
+
+	data[0] = 0x00;
+	if (tnr_dmd->chip_id == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X)
+		data[1] = 0x00;
+	else
+		data[1] = 0x01;
+	data[2] = 0x01;
+	data[3] = 0x03;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0x30, data,
+				    4) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x14) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x1B,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x21,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0xE1) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0xD3,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x21,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	return CXD2880_RESULT_OK;
+}
+
+static enum cxd2880_ret x_tune1(struct cxd2880_tnrdmd *tnr_dmd,
+				enum cxd2880_dtv_sys sys, u32 freq_khz,
+				enum cxd2880_dtv_bandwidth bandwidth,
+				u8 is_cable, int shift_frequency_khz)
+{
+	u8 data[11] = { 0 };
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x10,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x10) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	data[0] = 0x00;
+	data[1] = 0x00;
+	data[2] = 0x0E;
+	data[3] = 0x00;
+	data[4] = 0x03;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0xE7, data,
+				    5) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	data[0] = 0x1F;
+	data[1] = 0x80;
+	data[2] = 0x18;
+	data[3] = 0x00;
+	data[4] = 0x07;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0xE7, data,
+				    5) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	CXD2880_SLEEP(1);
+
+	data[0] = 0x72;
+	data[1] = 0x81;
+	data[3] = 0x1D;
+	data[4] = 0x6F;
+	data[5] = 0x7E;
+	data[7] = 0x1C;
+	switch (sys) {
+	case CXD2880_DTV_SYS_DVBT:
+	case CXD2880_DTV_SYS_ISDBT:
+	case CXD2880_DTV_SYS_ISDBTSB:
+	case CXD2880_DTV_SYS_ISDBTMM_A:
+	case CXD2880_DTV_SYS_ISDBTMM_B:
+		data[2] = 0x94;
+		data[6] = 0x91;
+		break;
+	case CXD2880_DTV_SYS_DVBT2:
+		data[2] = 0x96;
+		data[6] = 0x93;
+		break;
+	default:
+		return CXD2880_RESULT_ERROR_ARG;
+	}
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0x44, data,
+				    8) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x62,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x15) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	data[0] = 0x03;
+	data[1] = 0xE2;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0x1E, data,
+				    2) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x10) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	data[0] = (u8)(is_cable ? 0x01 : 0x00);
+	data[1] = 0x00;
+	data[2] = 0x6B;
+	data[3] = 0x4D;
+
+	switch (bandwidth) {
+	case CXD2880_DTV_BW_1_7_MHZ:
+		data[4] = 0x03;
+		break;
+	case CXD2880_DTV_BW_5_MHZ:
+	case CXD2880_DTV_BW_6_MHZ:
+		data[4] = 0x00;
+		break;
+	case CXD2880_DTV_BW_7_MHZ:
+		data[4] = 0x01;
+		break;
+	case CXD2880_DTV_BW_8_MHZ:
+		data[4] = 0x02;
+		break;
+	default:
+		return CXD2880_RESULT_ERROR_ARG;
+	}
+
+	data[5] = 0x00;
+
+	freq_khz += shift_frequency_khz;
+
+	data[6] = (u8)((freq_khz >> 16) & 0x0F);
+	data[7] = (u8)((freq_khz >> 8) & 0xFF);
+	data[8] = (u8)(freq_khz & 0xFF);
+	data[9] = 0xFF;
+	data[10] = 0xFE;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0x52, data,
+				    11) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	return CXD2880_RESULT_OK;
+}
+
+static enum cxd2880_ret x_tune2(struct cxd2880_tnrdmd *tnr_dmd,
+				enum cxd2880_dtv_bandwidth bandwidth,
+				enum cxd2880_tnrdmd_clockmode clk_mode,
+				int shift_frequency_khz)
+{
+	u8 data[3] = { 0 };
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x11) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	data[0] = 0x01;
+	data[1] = 0x0E;
+	data[2] = 0x01;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0x2D, data,
+				    3) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x1A) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x29,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x2C, data,
+				   1) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x10) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x60,
+				   data[0]) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x62,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x11) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x2D,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x2F,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x10,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x21,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (shift_frequency_khz != 0) {
+		int shift_freq = 0;
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0xE1) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x60, data,
+					   2) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		shift_freq = shift_frequency_khz * 1000;
+
+		switch (clk_mode) {
+		case CXD2880_TNRDMD_CLOCKMODE_A:
+		case CXD2880_TNRDMD_CLOCKMODE_C:
+		default:
+			if (shift_freq >= 0)
+				shift_freq = (shift_freq + 183 / 2) / 183;
+			else
+				shift_freq = (shift_freq - 183 / 2) / 183;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_B:
+			if (shift_freq >= 0)
+				shift_freq = (shift_freq + 178 / 2) / 178;
+			else
+				shift_freq = (shift_freq - 178 / 2) / 178;
+			break;
+		}
+
+		shift_freq +=
+		    cxd2880_convert2s_complement((data[0] << 8) | data[1], 16);
+
+		if (shift_freq > 32767)
+			shift_freq = 32767;
+		else if (shift_freq < -32768)
+			shift_freq = -32768;
+
+		data[0] = (u8)(((u32)shift_freq >> 8) & 0xFF);
+		data[1] = (u8)((u32)shift_freq & 0xFF);
+
+		if (tnr_dmd->io->write_regs(tnr_dmd->io,
+					    CXD2880_IO_TGT_DMD, 0x60, data,
+					    2) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x69, data,
+					   1) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		shift_freq = -shift_frequency_khz;
+
+		if (bandwidth == CXD2880_DTV_BW_1_7_MHZ) {
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+			default:
+				if (shift_freq >= 0)
+					shift_freq =
+					    (shift_freq * 1000 +
+					     17578 / 2) / 17578;
+				else
+					shift_freq =
+					    (shift_freq * 1000 -
+					     17578 / 2) / 17578;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				if (shift_freq >= 0)
+					shift_freq =
+					    (shift_freq * 1000 +
+					     17090 / 2) / 17090;
+				else
+					shift_freq =
+					    (shift_freq * 1000 -
+					     17090 / 2) / 17090;
+				break;
+			}
+		} else {
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+			default:
+				if (shift_freq >= 0)
+					shift_freq =
+					    (shift_freq * 1000 +
+					     35156 / 2) / 35156;
+				else
+					shift_freq =
+					    (shift_freq * 1000 -
+					     35156 / 2) / 35156;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				if (shift_freq >= 0)
+					shift_freq =
+					    (shift_freq * 1000 +
+					     34180 / 2) / 34180;
+				else
+					shift_freq =
+					    (shift_freq * 1000 -
+					     34180 / 2) / 34180;
+				break;
+			}
+		}
+
+		shift_freq += cxd2880_convert2s_complement(data[0], 8);
+
+		if (shift_freq > 127)
+			shift_freq = 127;
+		else if (shift_freq < -128)
+			shift_freq = -128;
+
+		data[0] = (u8)((u32)shift_freq & 0xFF);
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x69,
+					   data[0]) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (tnr_dmd->create_param.stationary_use) {
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x00,
+					   0xE1) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x8A,
+					   0x87) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x21,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	return CXD2880_RESULT_OK;
+}
+
+static enum cxd2880_ret x_tune3(struct cxd2880_tnrdmd *tnr_dmd,
+				enum cxd2880_dtv_sys sys,
+				u8 en_fef_intmtnt_ctrl)
+{
+	u8 data[6] = { 0 };
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x21,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0xE2) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x41,
+				   0xA0) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x21,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0xFE,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x10) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if ((sys == CXD2880_DTV_SYS_DVBT2) && en_fef_intmtnt_ctrl) {
+		data[0] = 0x01;
+		data[1] = 0x01;
+		data[2] = 0x01;
+		data[3] = 0x01;
+		data[4] = 0x01;
+		data[5] = 0x01;
+	} else {
+		data[0] = 0x00;
+		data[1] = 0x00;
+		data[2] = 0x00;
+		data[3] = 0x00;
+		data[4] = 0x00;
+		data[5] = 0x00;
+	}
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0xEF, data,
+				    6) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x2D) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if ((sys == CXD2880_DTV_SYS_DVBT2) && en_fef_intmtnt_ctrl)
+		data[0] = 0x00;
+	else
+		data[0] = 0x01;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0xB1,
+				   data[0]) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	return CXD2880_RESULT_OK;
+}
+
+static enum cxd2880_ret x_tune4(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	u8 data[2] = { 0 };
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	{
+		if (tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
+						      CXD2880_IO_TGT_SYS, 0x00,
+						      0x00) !=
+		    CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+		data[0] = 0x14;
+		data[1] = 0x00;
+		if (tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io,
+						       CXD2880_IO_TGT_SYS, 0x55,
+						       data,
+						       2) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	}
+
+	{
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_SYS, 0x00,
+					   0x00) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+		data[0] = 0x0B;
+		data[1] = 0xFF;
+		if (tnr_dmd->io->write_regs(tnr_dmd->io,
+					    CXD2880_IO_TGT_SYS, 0x53, data,
+					    2) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_SYS, 0x57,
+					   0x01) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+		data[0] = 0x0B;
+		data[1] = 0xFF;
+		if (tnr_dmd->io->write_regs(tnr_dmd->io,
+					    CXD2880_IO_TGT_SYS, 0x55, data,
+					    2) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	}
+
+	{
+		if (tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
+						      CXD2880_IO_TGT_SYS, 0x00,
+						      0x00) !=
+		    CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+		data[0] = 0x14;
+		data[1] = 0x00;
+		if (tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io,
+						       CXD2880_IO_TGT_SYS, 0x53,
+						       data,
+						       2) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+		if (tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
+						      CXD2880_IO_TGT_SYS, 0x57,
+						      0x02) !=
+		    CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	}
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0xFE,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
+					      CXD2880_IO_TGT_DMD, 0x00,
+					      0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
+					      CXD2880_IO_TGT_DMD, 0xFE,
+					      0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	return CXD2880_RESULT_OK;
+}
+
+static enum cxd2880_ret x_sleep1(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	u8 data[3] = { 0 };
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	{
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_SYS, 0x00,
+					   0x00) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_SYS, 0x57,
+					   0x03) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+		data[0] = 0x00;
+		data[1] = 0x00;
+		if (tnr_dmd->io->write_regs(tnr_dmd->io,
+					    CXD2880_IO_TGT_SYS, 0x53, data,
+					    2) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	}
+
+	{
+		if (tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
+						      CXD2880_IO_TGT_SYS, 0x00,
+						      0x00) !=
+		    CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+		data[0] = 0x1F;
+		data[1] = 0xFF;
+		data[2] = 0x03;
+		if (tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io,
+						       CXD2880_IO_TGT_SYS, 0x55,
+						       data,
+						       3) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+		data[0] = 0x00;
+		data[1] = 0x00;
+		if (tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io,
+						       CXD2880_IO_TGT_SYS, 0x53,
+						       data,
+						       2) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	}
+
+	{
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_SYS, 0x00,
+					   0x00) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+		data[0] = 0x1F;
+		data[1] = 0xFF;
+		if (tnr_dmd->io->write_regs(tnr_dmd->io,
+					    CXD2880_IO_TGT_SYS, 0x55, data,
+					    2) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	}
+
+	return CXD2880_RESULT_OK;
+}
+
+static enum cxd2880_ret x_sleep2(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	u8 data = 0;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x2D) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0xB1,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	CXD2880_SLEEP(1);
+
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0xB2, &data,
+				   1) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if ((data & 0x01) == 0x00)
+		return CXD2880_RESULT_ERROR_HW_STATE;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x10) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0xF4,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0xF3,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0xF2,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0xF1,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0xF0,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0xEF,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	return CXD2880_RESULT_OK;
+}
+
+static enum cxd2880_ret x_sleep3(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0xFD,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	return CXD2880_RESULT_OK;
+}
+
+static enum cxd2880_ret x_sleep4(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x21,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0xE2) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x41,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x21,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	return CXD2880_RESULT_OK;
+}
+
+static enum cxd2880_ret spll_reset(struct cxd2880_tnrdmd *tnr_dmd,
+				   enum cxd2880_tnrdmd_clockmode clockmode)
+{
+	u8 data[4] = { 0 };
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x10) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x29,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x28,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x27,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x26,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x10,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x27,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x22,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	switch (clockmode) {
+	case CXD2880_TNRDMD_CLOCKMODE_A:
+		data[0] = 0x00;
+		break;
+
+	case CXD2880_TNRDMD_CLOCKMODE_B:
+		data[0] = 0x01;
+		break;
+
+	case CXD2880_TNRDMD_CLOCKMODE_C:
+		data[0] = 0x02;
+		break;
+
+	default:
+		return CXD2880_RESULT_ERROR_ARG;
+	}
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x30,
+				   data[0]) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x22,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	CXD2880_SLEEP(2);
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x0A) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x10, data,
+				   1) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if ((data[0] & 0x01) == 0x00)
+		return CXD2880_RESULT_ERROR_HW_STATE;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x27,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	CXD2880_SLEEP(1);
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x10,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x10) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	data[0] = 0x00;
+	data[1] = 0x00;
+	data[2] = 0x00;
+	data[3] = 0x00;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0x26, data,
+				    4) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	return CXD2880_RESULT_OK;
+}
+
+static enum cxd2880_ret t_power_x(struct cxd2880_tnrdmd *tnr_dmd, u8 on)
+{
+	u8 data[3] = { 0 };
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x10) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x29,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x28,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x27,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x10,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x27,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x25,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (on) {
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_SYS, 0x2B,
+					   0x01) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		CXD2880_SLEEP(1);
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_SYS, 0x00,
+					   0x0A) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_SYS, 0x12, data,
+					   1) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+		if ((data[0] & 0x01) == 0)
+			return CXD2880_RESULT_ERROR_HW_STATE;
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_SYS, 0x00,
+					   0x00) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_SYS, 0x2A,
+					   0x00) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	} else {
+		data[0] = 0x03;
+		data[1] = 0x00;
+		if (tnr_dmd->io->write_regs(tnr_dmd->io,
+					    CXD2880_IO_TGT_SYS, 0x2A, data,
+					    2) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		CXD2880_SLEEP(1);
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_SYS, 0x00,
+					   0x0A) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_SYS, 0x13, data,
+					   1) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+		if ((data[0] & 0x01) == 0)
+			return CXD2880_RESULT_ERROR_HW_STATE;
+	}
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x25,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	CXD2880_SLEEP(1);
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x0A) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x11, data,
+				   1) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if ((data[0] & 0x01) == 0)
+		return CXD2880_RESULT_ERROR_HW_STATE;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x27,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	CXD2880_SLEEP(1);
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x10,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x10) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	data[0] = 0x00;
+	data[1] = 0x00;
+	data[2] = 0x00;
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0x27, data,
+				    3) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	return CXD2880_RESULT_OK;
+}
+
+struct cxd2880_tnrdmd_ts_clk_cfg {
+	u8 srl_clk_mode;
+	u8 srl_duty_mode;
+	u8 ts_clk_period;
+};
+
+static enum cxd2880_ret set_ts_clk_mode_and_freq(struct cxd2880_tnrdmd *tnr_dmd,
+						 enum cxd2880_dtv_sys sys)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	u8 backwards_compatible = 0;
+	struct cxd2880_tnrdmd_ts_clk_cfg ts_clk_cfg;
+
+	const struct cxd2880_tnrdmd_ts_clk_cfg srl_ts_clk_stgs[2][2] = {
+	{
+		{3, 1, 8,},
+		{0, 2, 16,}
+	},
+	{
+		{1, 1, 8,},
+		{2, 2, 16,}
+	}
+	};
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	{
+		u8 ts_rate_ctrl_off = 0;
+		u8 ts_in_off = 0;
+		u8 ts_clk_manaul_on = 0;
+
+		if ((sys == CXD2880_DTV_SYS_ISDBT) ||
+		    (sys == CXD2880_DTV_SYS_ISDBTSB) ||
+		    (sys == CXD2880_DTV_SYS_ISDBTMM_A) ||
+		    (sys == CXD2880_DTV_SYS_ISDBTMM_B)) {
+			backwards_compatible = 0;
+			ts_rate_ctrl_off = 1;
+			ts_in_off = 0;
+		} else if (tnr_dmd->is_ts_backwards_compatible_mode) {
+			backwards_compatible = 1;
+			ts_rate_ctrl_off = 1;
+			ts_in_off = 1;
+		} else {
+			backwards_compatible = 0;
+			ts_rate_ctrl_off = 0;
+			ts_in_off = 0;
+		}
+
+		if (tnr_dmd->ts_byte_clk_manual_setting) {
+			ts_clk_manaul_on = 1;
+			ts_rate_ctrl_off = 0;
+		}
+
+		ret =
+		    cxd2880_io_set_reg_bits(tnr_dmd->io, CXD2880_IO_TGT_DMD,
+					    0xD3, ts_rate_ctrl_off, 0x01);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		ret =
+		    cxd2880_io_set_reg_bits(tnr_dmd->io, CXD2880_IO_TGT_DMD,
+					    0xDE, ts_in_off, 0x01);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		ret =
+		    cxd2880_io_set_reg_bits(tnr_dmd->io, CXD2880_IO_TGT_DMD,
+					    0xDA, ts_clk_manaul_on, 0x01);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	}
+
+	ts_clk_cfg =
+	    srl_ts_clk_stgs[tnr_dmd->srl_ts_clk_mod_cnts]
+			[(u8)tnr_dmd->srl_ts_clk_frq];
+
+	if (tnr_dmd->ts_byte_clk_manual_setting)
+		ts_clk_cfg.ts_clk_period = tnr_dmd->ts_byte_clk_manual_setting;
+
+	ret =
+	    cxd2880_io_set_reg_bits(tnr_dmd->io, CXD2880_IO_TGT_DMD, 0xC4,
+				    ts_clk_cfg.srl_clk_mode, 0x03);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	ret =
+	    cxd2880_io_set_reg_bits(tnr_dmd->io, CXD2880_IO_TGT_DMD, 0xD1,
+				    ts_clk_cfg.srl_duty_mode, 0x03);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD, 0xD9,
+				     ts_clk_cfg.ts_clk_period);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	{
+		u8 data = (u8)(backwards_compatible ? 0x00 : 0x01);
+
+		if (sys == CXD2880_DTV_SYS_DVBT) {
+			if (tnr_dmd->io->write_reg(tnr_dmd->io,
+						   CXD2880_IO_TGT_DMD, 0x00,
+						   0x10) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+
+			ret =
+			    cxd2880_io_set_reg_bits(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD, 0x66,
+						    data, 0x01);
+			if (ret != CXD2880_RESULT_OK)
+				return ret;
+		}
+	}
+
+	return ret;
+}
+
+static enum cxd2880_ret pid_ftr_setting(struct cxd2880_tnrdmd *tnr_dmd,
+					struct cxd2880_tnrdmd_pid_ftr_cfg
+					*pid_ftr_cfg)
+{
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (!pid_ftr_cfg) {
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_DMD, 0x50,
+					   0x02) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	} else {
+		u8 data[65];
+
+		data[0] = (u8)(pid_ftr_cfg->is_negative ? 0x01 : 0x00);
+		{
+			int i = 0;
+
+			for (i = 0; i < 32; i++) {
+				if (pid_ftr_cfg->pid_cfg[i].is_en) {
+					data[1 + (i * 2)] =
+					    (u8)((u8)
+					    (pid_ftr_cfg->pid_cfg[i].pid
+					     >> 8) | 0x20);
+					data[2 + (i * 2)] =
+					    (u8)(pid_ftr_cfg->pid_cfg[i].pid
+					     & 0xFF);
+				} else {
+					data[1 + (i * 2)] = 0x00;
+					data[2 + (i * 2)] = 0x00;
+				}
+			}
+		}
+		if (tnr_dmd->io->write_regs(tnr_dmd->io,
+					    CXD2880_IO_TGT_DMD, 0x50, data,
+					    65) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	}
+
+	return CXD2880_RESULT_OK;
+}
+
+static enum cxd2880_ret load_cfg_mem(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	u8 i;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	for (i = 0; i < tnr_dmd->cfg_mem_last_entry; i++) {
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     tnr_dmd->cfg_mem[i].tgt,
+					     0x00, tnr_dmd->cfg_mem[i].bank);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
+					      tnr_dmd->cfg_mem[i].tgt,
+					      tnr_dmd->cfg_mem[i].address,
+					      tnr_dmd->cfg_mem[i].value,
+					      tnr_dmd->cfg_mem[i].bit_mask);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	}
+
+	return ret;
+}
+
+static enum cxd2880_ret set_cfg_mem(struct cxd2880_tnrdmd *tnr_dmd,
+				    enum cxd2880_io_tgt tgt,
+				    u8 bank, u8 address, u8 value, u8 bit_mask)
+{
+	u8 i;
+	u8 value_stored = 0;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	for (i = 0; i < tnr_dmd->cfg_mem_last_entry; i++) {
+		if ((value_stored == 0) &&
+		    (tnr_dmd->cfg_mem[i].tgt == tgt) &&
+		    (tnr_dmd->cfg_mem[i].bank == bank) &&
+		    (tnr_dmd->cfg_mem[i].address == address)) {
+			tnr_dmd->cfg_mem[i].value &= ~bit_mask;
+			tnr_dmd->cfg_mem[i].value |= (value & bit_mask);
+
+			tnr_dmd->cfg_mem[i].bit_mask |= bit_mask;
+
+			value_stored = 1;
+		}
+	}
+
+	if (value_stored == 0) {
+		if (tnr_dmd->cfg_mem_last_entry <
+		    CXD2880_TNRDMD_MAX_CFG_MEM_COUNT) {
+			tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].tgt = tgt;
+			tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].bank =
+			    bank;
+			tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].address =
+			    address;
+			tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].value =
+			    (value & bit_mask);
+			tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].bit_mask =
+			    bit_mask;
+			tnr_dmd->cfg_mem_last_entry++;
+		} else {
+			return CXD2880_RESULT_ERROR_OVERFLOW;
+		}
+	}
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_create(struct cxd2880_tnrdmd *tnr_dmd,
+				       struct cxd2880_io *io,
+				       struct cxd2880_tnrdmd_create_param
+				       *create_param)
+{
+	if ((!tnr_dmd) || (!io) || (!create_param))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	cxd2880_memset(tnr_dmd, 0, sizeof(struct cxd2880_tnrdmd));
+
+	tnr_dmd->io = io;
+	tnr_dmd->create_param = *create_param;
+
+	tnr_dmd->diver_mode = CXD2880_TNRDMD_DIVERMODE_SINGLE;
+	tnr_dmd->diver_sub = NULL;
+
+	tnr_dmd->srl_ts_clk_mod_cnts = 1;
+	tnr_dmd->en_fef_intmtnt_base = 1;
+	tnr_dmd->en_fef_intmtnt_lite = 1;
+	tnr_dmd->rf_lvl_cmpstn = NULL;
+	tnr_dmd->lna_thrs_tbl_air = NULL;
+	tnr_dmd->lna_thrs_tbl_cable = NULL;
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_diver_create(struct cxd2880_tnrdmd
+					     *tnr_dmd_main,
+					     struct cxd2880_io *io_main,
+					     struct cxd2880_tnrdmd *tnr_dmd_sub,
+					     struct cxd2880_io *io_sub,
+					     struct
+					     cxd2880_tnrdmd_diver_create_param
+					     *create_param)
+{
+	if ((!tnr_dmd_main) || (!io_main) || (!tnr_dmd_sub) || (!io_sub) ||
+	    (!create_param))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	cxd2880_memset(tnr_dmd_main, 0, sizeof(struct cxd2880_tnrdmd));
+	cxd2880_memset(tnr_dmd_sub, 0, sizeof(struct cxd2880_tnrdmd));
+
+	tnr_dmd_main->io = io_main;
+	tnr_dmd_main->diver_mode = CXD2880_TNRDMD_DIVERMODE_MAIN;
+	tnr_dmd_main->diver_sub = tnr_dmd_sub;
+	tnr_dmd_main->create_param.en_internal_ldo =
+	    create_param->en_internal_ldo;
+	tnr_dmd_main->create_param.ts_output_if = create_param->ts_output_if;
+	tnr_dmd_main->create_param.xtal_share_type =
+	    CXD2880_TNRDMD_XTAL_SHARE_MASTER;
+	tnr_dmd_main->create_param.xosc_cap = create_param->xosc_cap_main;
+	tnr_dmd_main->create_param.xosc_i = create_param->xosc_i_main;
+	tnr_dmd_main->create_param.is_cxd2881gg = create_param->is_cxd2881gg;
+	tnr_dmd_main->create_param.stationary_use =
+	    create_param->stationary_use;
+
+	tnr_dmd_sub->io = io_sub;
+	tnr_dmd_sub->diver_mode = CXD2880_TNRDMD_DIVERMODE_SUB;
+	tnr_dmd_sub->diver_sub = NULL;
+	tnr_dmd_sub->create_param.en_internal_ldo =
+	    create_param->en_internal_ldo;
+	tnr_dmd_sub->create_param.ts_output_if = create_param->ts_output_if;
+	tnr_dmd_sub->create_param.xtal_share_type =
+	    CXD2880_TNRDMD_XTAL_SHARE_SLAVE;
+	tnr_dmd_sub->create_param.xosc_cap = 0;
+	tnr_dmd_sub->create_param.xosc_i = create_param->xosc_i_sub;
+	tnr_dmd_sub->create_param.is_cxd2881gg = create_param->is_cxd2881gg;
+	tnr_dmd_sub->create_param.stationary_use = create_param->stationary_use;
+
+	tnr_dmd_main->srl_ts_clk_mod_cnts = 1;
+	tnr_dmd_main->en_fef_intmtnt_base = 1;
+	tnr_dmd_main->en_fef_intmtnt_lite = 1;
+	tnr_dmd_main->rf_lvl_cmpstn = NULL;
+	tnr_dmd_main->lna_thrs_tbl_air = NULL;
+	tnr_dmd_main->lna_thrs_tbl_cable = NULL;
+
+	tnr_dmd_sub->srl_ts_clk_mod_cnts = 1;
+	tnr_dmd_sub->en_fef_intmtnt_base = 1;
+	tnr_dmd_sub->en_fef_intmtnt_lite = 1;
+	tnr_dmd_sub->rf_lvl_cmpstn = NULL;
+	tnr_dmd_sub->lna_thrs_tbl_air = NULL;
+	tnr_dmd_sub->lna_thrs_tbl_cable = NULL;
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_init1(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	tnr_dmd->chip_id = CXD2880_TNRDMD_CHIP_ID_UNKNOWN;
+	tnr_dmd->state = CXD2880_TNRDMD_STATE_UNKNOWN;
+	tnr_dmd->clk_mode = CXD2880_TNRDMD_CLOCKMODE_UNKNOWN;
+	tnr_dmd->frequency_khz = 0;
+	tnr_dmd->sys = CXD2880_DTV_SYS_UNKNOWN;
+	tnr_dmd->bandwidth = CXD2880_DTV_BW_UNKNOWN;
+	tnr_dmd->scan_mode = 0;
+	cxd2880_atomic_set(&tnr_dmd->cancel, 0);
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		tnr_dmd->diver_sub->chip_id = CXD2880_TNRDMD_CHIP_ID_UNKNOWN;
+		tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_UNKNOWN;
+		tnr_dmd->diver_sub->clk_mode = CXD2880_TNRDMD_CLOCKMODE_UNKNOWN;
+		tnr_dmd->diver_sub->frequency_khz = 0;
+		tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_UNKNOWN;
+		tnr_dmd->diver_sub->bandwidth = CXD2880_DTV_BW_UNKNOWN;
+		tnr_dmd->diver_sub->scan_mode = 0;
+		cxd2880_atomic_set(&tnr_dmd->diver_sub->cancel, 0);
+	}
+
+	ret = cxd2880_tnrdmd_chip_id(tnr_dmd, &tnr_dmd->chip_id);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if (!CXD2880_TNRDMD_CHIP_ID_VALID(tnr_dmd->chip_id))
+		return CXD2880_RESULT_ERROR_NOSUPPORT;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret =
+		    cxd2880_tnrdmd_chip_id(tnr_dmd->diver_sub,
+					   &tnr_dmd->diver_sub->chip_id);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		if (!CXD2880_TNRDMD_CHIP_ID_VALID(tnr_dmd->diver_sub->chip_id))
+			return CXD2880_RESULT_ERROR_NOSUPPORT;
+	}
+
+	ret = p_init1(tnr_dmd);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = p_init1(tnr_dmd->diver_sub);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	}
+
+	CXD2880_SLEEP(1);
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = p_init2(tnr_dmd->diver_sub);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	}
+
+	ret = p_init2(tnr_dmd);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	CXD2880_SLEEP(5);
+
+	ret = p_init3(tnr_dmd);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = p_init3(tnr_dmd->diver_sub);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	}
+
+	ret = rf_init1(tnr_dmd);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = rf_init1(tnr_dmd->diver_sub);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	}
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_init2(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	{
+		u8 cpu_task_completed = 0;
+
+		ret =
+		    cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd,
+						     &cpu_task_completed);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		if (!cpu_task_completed)
+			return CXD2880_RESULT_ERROR_HW_STATE;
+	}
+
+	ret = rf_init2(tnr_dmd);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = rf_init2(tnr_dmd->diver_sub);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	}
+
+	ret = load_cfg_mem(tnr_dmd);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = load_cfg_mem(tnr_dmd->diver_sub);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	}
+
+	tnr_dmd->state = CXD2880_TNRDMD_STATE_SLEEP;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
+		tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_SLEEP;
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd
+							  *tnr_dmd,
+							  u8 *task_completed)
+{
+	u16 cpu_status = 0;
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!task_completed))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	ret = cxd2880_tnrdmd_mon_internal_cpu_status(tnr_dmd, &cpu_status);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
+		if (cpu_status == 0)
+			*task_completed = 1;
+		else
+			*task_completed = 0;
+
+		return ret;
+	}
+	if (cpu_status != 0) {
+		*task_completed = 0;
+		return ret;
+	}
+
+	ret = cxd2880_tnrdmd_mon_internal_cpu_status_sub(tnr_dmd, &cpu_status);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if (cpu_status == 0)
+		*task_completed = 1;
+	else
+		*task_completed = 0;
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_common_tune_setting1(struct cxd2880_tnrdmd
+						     *tnr_dmd,
+						     enum cxd2880_dtv_sys sys,
+						     u32 frequency_khz,
+						     enum cxd2880_dtv_bandwidth
+						     bandwidth, u8 one_seg_opt,
+						     u8 one_seg_opt_shft_dir)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (frequency_khz < 4000)
+		return CXD2880_RESULT_ERROR_RANGE;
+
+	ret = cxd2880_tnrdmd_sleep(tnr_dmd);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	{
+		u8 data = 0;
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_SYS, 0x00,
+					   0x00) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_SYS, 0x2B, &data,
+					   1) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		switch (sys) {
+		case CXD2880_DTV_SYS_DVBT:
+		case CXD2880_DTV_SYS_ISDBT:
+		case CXD2880_DTV_SYS_ISDBTSB:
+		case CXD2880_DTV_SYS_ISDBTMM_A:
+		case CXD2880_DTV_SYS_ISDBTMM_B:
+			if (data == 0x00) {
+				ret = t_power_x(tnr_dmd, 1);
+				if (ret != CXD2880_RESULT_OK)
+					return ret;
+
+				if (tnr_dmd->diver_mode ==
+				    CXD2880_TNRDMD_DIVERMODE_MAIN) {
+					ret = t_power_x(tnr_dmd->diver_sub, 1);
+					if (ret != CXD2880_RESULT_OK)
+						return ret;
+				}
+			}
+			break;
+
+		case CXD2880_DTV_SYS_DVBT2:
+			if (data == 0x01) {
+				ret = t_power_x(tnr_dmd, 0);
+				if (ret != CXD2880_RESULT_OK)
+					return ret;
+
+				if (tnr_dmd->diver_mode ==
+				    CXD2880_TNRDMD_DIVERMODE_MAIN) {
+					ret = t_power_x(tnr_dmd->diver_sub, 0);
+					if (ret != CXD2880_RESULT_OK)
+						return ret;
+				}
+			}
+			break;
+
+		default:
+			return CXD2880_RESULT_ERROR_ARG;
+		}
+	}
+
+	{
+		enum cxd2880_tnrdmd_clockmode new_clk_mode =
+		    CXD2880_TNRDMD_CLOCKMODE_A;
+
+		ret = spll_reset(tnr_dmd, new_clk_mode);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		tnr_dmd->clk_mode = new_clk_mode;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			ret = spll_reset(tnr_dmd->diver_sub, new_clk_mode);
+			if (ret != CXD2880_RESULT_OK)
+				return ret;
+
+			tnr_dmd->diver_sub->clk_mode = new_clk_mode;
+		}
+
+		ret = load_cfg_mem(tnr_dmd);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			ret = load_cfg_mem(tnr_dmd->diver_sub);
+			if (ret != CXD2880_RESULT_OK)
+				return ret;
+		}
+	}
+
+	{
+		int shift_frequency_khz = 0;
+
+		if (one_seg_opt) {
+			if (tnr_dmd->diver_mode ==
+			    CXD2880_TNRDMD_DIVERMODE_MAIN) {
+				shift_frequency_khz = 350;
+			} else {
+				if (one_seg_opt_shft_dir)
+					shift_frequency_khz = 350;
+				else
+					shift_frequency_khz = -350;
+
+				if (tnr_dmd->create_param.xtal_share_type ==
+				    CXD2880_TNRDMD_XTAL_SHARE_SLAVE)
+					shift_frequency_khz *= -1;
+			}
+		} else {
+			if (tnr_dmd->diver_mode ==
+			    CXD2880_TNRDMD_DIVERMODE_MAIN) {
+				shift_frequency_khz = 150;
+			} else {
+				switch (tnr_dmd->create_param.xtal_share_type) {
+				case CXD2880_TNRDMD_XTAL_SHARE_NONE:
+				case CXD2880_TNRDMD_XTAL_SHARE_EXTREF:
+				default:
+					shift_frequency_khz = 0;
+					break;
+				case CXD2880_TNRDMD_XTAL_SHARE_MASTER:
+					shift_frequency_khz = 150;
+					break;
+				case CXD2880_TNRDMD_XTAL_SHARE_SLAVE:
+					shift_frequency_khz = -150;
+					break;
+				}
+			}
+		}
+
+		ret =
+		    x_tune1(tnr_dmd, sys, frequency_khz, bandwidth,
+			    tnr_dmd->is_cable_input, shift_frequency_khz);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			ret =
+			    x_tune1(tnr_dmd->diver_sub, sys, frequency_khz,
+				    bandwidth, tnr_dmd->is_cable_input,
+				    -shift_frequency_khz);
+			if (ret != CXD2880_RESULT_OK)
+				return ret;
+		}
+
+		CXD2880_SLEEP(10);
+
+		{
+			u8 cpu_task_completed = 0;
+
+			ret =
+			    cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd,
+						     &cpu_task_completed);
+			if (ret != CXD2880_RESULT_OK)
+				return ret;
+
+			if (!cpu_task_completed)
+				return CXD2880_RESULT_ERROR_HW_STATE;
+		}
+
+		ret =
+		    x_tune2(tnr_dmd, bandwidth, tnr_dmd->clk_mode,
+			    shift_frequency_khz);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			ret =
+			    x_tune2(tnr_dmd->diver_sub, bandwidth,
+				    tnr_dmd->diver_sub->clk_mode,
+				    -shift_frequency_khz);
+			if (ret != CXD2880_RESULT_OK)
+				return ret;
+		}
+	}
+
+	if (tnr_dmd->create_param.ts_output_if == CXD2880_TNRDMD_TSOUT_IF_TS) {
+		ret = set_ts_clk_mode_and_freq(tnr_dmd, sys);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	} else {
+		struct cxd2880_tnrdmd_pid_ftr_cfg *pid_ftr_cfg;
+
+		if (tnr_dmd->pid_ftr_cfg_en)
+			pid_ftr_cfg = &tnr_dmd->pid_ftr_cfg;
+		else
+			pid_ftr_cfg = NULL;
+
+		ret = pid_ftr_setting(tnr_dmd, pid_ftr_cfg);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	}
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_common_tune_setting2(struct cxd2880_tnrdmd
+						     *tnr_dmd,
+						     enum cxd2880_dtv_sys sys,
+						     u8 en_fef_intmtnt_ctrl)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	ret = x_tune3(tnr_dmd, sys, en_fef_intmtnt_ctrl);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = x_tune3(tnr_dmd->diver_sub, sys, en_fef_intmtnt_ctrl);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	}
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = x_tune4(tnr_dmd);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	}
+
+	ret = cxd2880_tnrdmd_set_ts_output(tnr_dmd, 1);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_sleep(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state == CXD2880_TNRDMD_STATE_SLEEP) {
+	} else if (tnr_dmd->state == CXD2880_TNRDMD_STATE_ACTIVE) {
+		ret = cxd2880_tnrdmd_set_ts_output(tnr_dmd, 0);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			ret = x_sleep1(tnr_dmd);
+			if (ret != CXD2880_RESULT_OK)
+				return ret;
+		}
+
+		ret = x_sleep2(tnr_dmd);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			ret = x_sleep2(tnr_dmd->diver_sub);
+			if (ret != CXD2880_RESULT_OK)
+				return ret;
+		}
+
+		switch (tnr_dmd->sys) {
+		case CXD2880_DTV_SYS_DVBT:
+			ret = cxd2880_tnrdmd_dvbt_sleep_setting(tnr_dmd);
+			if (ret != CXD2880_RESULT_OK)
+				return ret;
+			break;
+
+		case CXD2880_DTV_SYS_DVBT2:
+			ret = cxd2880_tnrdmd_dvbt2_sleep_setting(tnr_dmd);
+			if (ret != CXD2880_RESULT_OK)
+				return ret;
+			break;
+
+		default:
+			return CXD2880_RESULT_ERROR_SW_STATE;
+		}
+
+		ret = x_sleep3(tnr_dmd);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			ret = x_sleep3(tnr_dmd->diver_sub);
+			if (ret != CXD2880_RESULT_OK)
+				return ret;
+		}
+
+		ret = x_sleep4(tnr_dmd);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			ret = x_sleep4(tnr_dmd->diver_sub);
+			if (ret != CXD2880_RESULT_OK)
+				return ret;
+		}
+
+		tnr_dmd->state = CXD2880_TNRDMD_STATE_SLEEP;
+		tnr_dmd->frequency_khz = 0;
+		tnr_dmd->sys = CXD2880_DTV_SYS_UNKNOWN;
+		tnr_dmd->bandwidth = CXD2880_DTV_BW_UNKNOWN;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_SLEEP;
+			tnr_dmd->diver_sub->frequency_khz = 0;
+			tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_UNKNOWN;
+			tnr_dmd->diver_sub->bandwidth = CXD2880_DTV_BW_UNKNOWN;
+		}
+	} else {
+		return CXD2880_RESULT_ERROR_SW_STATE;
+	}
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_set_cfg(struct cxd2880_tnrdmd *tnr_dmd,
+					enum cxd2880_tnrdmd_cfg_id id,
+					int value)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	u8 data[2] = { 0 };
+	u8 need_sub_setting = 0;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	switch (id) {
+	case CXD2880_TNRDMD_CFG_OUTPUT_SEL_MSB:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return CXD2880_RESULT_ERROR_SW_STATE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0xC4,
+							 (u8)(value ? 0x00 :
+							       0x10), 0x10);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSVALID_ACTIVE_HI:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return CXD2880_RESULT_ERROR_SW_STATE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0xC5,
+							 (u8)(value ? 0x00 :
+							       0x02), 0x02);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSSYNC_ACTIVE_HI:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return CXD2880_RESULT_ERROR_SW_STATE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0xC5,
+							 (u8)(value ? 0x00 :
+							       0x04), 0x04);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSERR_ACTIVE_HI:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return CXD2880_RESULT_ERROR_SW_STATE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0xCB,
+							 (u8)(value ? 0x00 :
+							       0x01), 0x01);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_LATCH_ON_POSEDGE:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return CXD2880_RESULT_ERROR_SW_STATE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0xC5,
+							 (u8)(value ? 0x01 :
+							       0x00), 0x01);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSCLK_CONT:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return CXD2880_RESULT_ERROR_SW_STATE;
+
+		tnr_dmd->srl_ts_clk_mod_cnts = (u8)(value ? 0x01 : 0x00);
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSCLK_MASK:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return CXD2880_RESULT_ERROR_SW_STATE;
+
+		if ((value < 0) || (value > 0x1F))
+			return CXD2880_RESULT_ERROR_RANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0xC6, (u8)value,
+							 0x1F);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSVALID_MASK:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return CXD2880_RESULT_ERROR_SW_STATE;
+
+		if ((value < 0) || (value > 0x1F))
+			return CXD2880_RESULT_ERROR_RANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0xC8, (u8)value,
+							 0x1F);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSERR_MASK:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return CXD2880_RESULT_ERROR_SW_STATE;
+
+		if ((value < 0) || (value > 0x1F))
+			return CXD2880_RESULT_ERROR_RANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0xC9, (u8)value,
+							 0x1F);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSERR_VALID_DIS:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return CXD2880_RESULT_ERROR_SW_STATE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x91,
+							 (u8)(value ? 0x01 :
+							       0x00), 0x01);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSPIN_CURRENT:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return CXD2880_RESULT_ERROR_SW_STATE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_SYS,
+							 0x00, 0x51, (u8)value,
+							 0x3F);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSPIN_PULLUP_MANUAL:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return CXD2880_RESULT_ERROR_SW_STATE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_SYS,
+							 0x00, 0x50,
+							 (u8)(value ? 0x80 :
+							       0x00), 0x80);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSPIN_PULLUP:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return CXD2880_RESULT_ERROR_SW_STATE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_SYS,
+							 0x00, 0x50, (u8)value,
+							 0x3F);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSCLK_FREQ:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return CXD2880_RESULT_ERROR_SW_STATE;
+
+		if ((value < 0) || (value > 1))
+			return CXD2880_RESULT_ERROR_RANGE;
+
+		tnr_dmd->srl_ts_clk_frq =
+		    (enum cxd2880_tnrdmd_serial_ts_clk)value;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSBYTECLK_MANUAL:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return CXD2880_RESULT_ERROR_SW_STATE;
+
+		if ((value < 0) || (value > 0xFF))
+			return CXD2880_RESULT_ERROR_RANGE;
+
+		tnr_dmd->ts_byte_clk_manual_setting = (u8)value;
+
+		break;
+
+	case CXD2880_TNRDMD_CFG_TS_PACKET_GAP:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return CXD2880_RESULT_ERROR_SW_STATE;
+
+		if ((value < 0) || (value > 7))
+			return CXD2880_RESULT_ERROR_RANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0xD6, (u8)value,
+							 0x07);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		break;
+
+	case CXD2880_TNRDMD_CFG_TS_BACKWARDS_COMPATIBLE:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return CXD2880_RESULT_ERROR_SW_STATE;
+
+		tnr_dmd->is_ts_backwards_compatible_mode = (u8)(value ? 1 : 0);
+
+		break;
+
+	case CXD2880_TNRDMD_CFG_PWM_VALUE:
+		if ((value < 0) || (value > 0x1000))
+			return CXD2880_RESULT_ERROR_RANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x22,
+							 (u8)(value ? 0x01 :
+							       0x00), 0x01);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		{
+			u8 data[2];
+
+			data[0] = (u8)(((u16)value >> 8) & 0x1F);
+			data[1] = (u8)((u16)value & 0xFF);
+
+			ret =
+			    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x23,
+							 data[0], 0x1F);
+			if (ret != CXD2880_RESULT_OK)
+				return ret;
+
+			ret =
+			    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x24,
+							 data[1], 0xFF);
+			if (ret != CXD2880_RESULT_OK)
+				return ret;
+		}
+
+		break;
+
+	case CXD2880_TNRDMD_CFG_INTERRUPT:
+		data[0] = (u8)((value >> 8) & 0xFF);
+		data[1] = (u8)(value & 0xFF);
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_SYS,
+							 0x00, 0x48, data[0],
+							 0xFF);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_SYS,
+							 0x00, 0x49, data[1],
+							 0xFF);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_INTERRUPT_LOCK_SEL:
+		data[0] = (u8)(value & 0x07);
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_SYS,
+							 0x00, 0x4A, data[0],
+							 0x07);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_INTERRUPT_INV_LOCK_SEL:
+		data[0] = (u8)((value & 0x07) << 3);
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_SYS,
+							 0x00, 0x4A, data[0],
+							 0x38);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_FIXED_CLOCKMODE:
+		if ((value < (int)CXD2880_TNRDMD_CLOCKMODE_UNKNOWN) ||
+		    (value > (int)CXD2880_TNRDMD_CLOCKMODE_C))
+			return CXD2880_RESULT_ERROR_RANGE;
+		tnr_dmd->fixed_clk_mode = (enum cxd2880_tnrdmd_clockmode)value;
+		break;
+
+	case CXD2880_TNRDMD_CFG_CABLE_INPUT:
+		tnr_dmd->is_cable_input = (u8)(value ? 1 : 0);
+		break;
+
+	case CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_BASE:
+		tnr_dmd->en_fef_intmtnt_base = (u8)(value ? 1 : 0);
+		break;
+
+	case CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_LITE:
+		tnr_dmd->en_fef_intmtnt_lite = (u8)(value ? 1 : 0);
+		break;
+
+	case CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_EMPTY_THRS:
+		data[0] = (u8)((value >> 8) & 0x07);
+		data[1] = (u8)(value & 0xFF);
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x99, data[0],
+							 0x07);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x9A, data[1],
+							 0xFF);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_FULL_THRS:
+		data[0] = (u8)((value >> 8) & 0x07);
+		data[1] = (u8)(value & 0xFF);
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x9B, data[0],
+							 0x07);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x9C, data[1],
+							 0xFF);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TS_BUF_RRDY_THRS:
+		data[0] = (u8)((value >> 8) & 0x07);
+		data[1] = (u8)(value & 0xFF);
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x9D, data[0],
+							 0x07);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x9E, data[1],
+							 0xFF);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_BLINDTUNE_DVBT2_FIRST:
+		tnr_dmd->blind_tune_dvbt2_first = (u8)(value ? 1 : 0);
+		break;
+
+	case CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD:
+		if ((value < 0) || (value > 31))
+			return CXD2880_RESULT_ERROR_RANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x10, 0x60,
+							 (u8)(value & 0x1F),
+							 0x1F);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD:
+		if ((value < 0) || (value > 7))
+			return CXD2880_RESULT_ERROR_RANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x10, 0x6F,
+							 (u8)(value & 0x07),
+							 0x07);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_DVBT2_BBER_MES:
+		if ((value < 0) || (value > 15))
+			return CXD2880_RESULT_ERROR_RANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x20, 0x72,
+							 (u8)(value & 0x0F),
+							 0x0F);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_DVBT2_LBER_MES:
+		if ((value < 0) || (value > 15))
+			return CXD2880_RESULT_ERROR_RANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x20, 0x6F,
+							 (u8)(value & 0x0F),
+							 0x0F);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_DVBT_PER_MES:
+		if ((value < 0) || (value > 15))
+			return CXD2880_RESULT_ERROR_RANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x10, 0x5C,
+							 (u8)(value & 0x0F),
+							 0x0F);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_DVBT2_PER_MES:
+		if ((value < 0) || (value > 15))
+			return CXD2880_RESULT_ERROR_RANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x24, 0xDC,
+							 (u8)(value & 0x0F),
+							 0x0F);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_ISDBT_BERPER_PERIOD:
+		{
+			u8 data[2];
+
+			data[0] = (u8)((value & 0x00007F00) >> 8);
+			data[1] = (u8)(value & 0x000000FF);
+
+			ret =
+			    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x60, 0x5B,
+							 data[0], 0x7F);
+			if (ret != CXD2880_RESULT_OK)
+				return ret;
+			ret =
+			    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x60, 0x5C,
+							 data[1], 0xFF);
+			if (ret != CXD2880_RESULT_OK)
+				return ret;
+		}
+		break;
+
+	default:
+		return CXD2880_RESULT_ERROR_ARG;
+	}
+
+	if (need_sub_setting &&
+	    (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)) {
+		ret = cxd2880_tnrdmd_set_cfg(tnr_dmd->diver_sub, id, value);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	}
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_gpio_set_cfg(struct cxd2880_tnrdmd *tnr_dmd,
+					     u8 id,
+					     u8 en,
+					     enum cxd2880_tnrdmd_gpio_mode mode,
+					     u8 open_drain, u8 invert)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (id > 2)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (mode > CXD2880_TNRDMD_GPIO_MODE_EEW)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	ret =
+	    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS,
+						 0x00, 0x40 + id, (u8)mode,
+						 0x0F);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	ret =
+	    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS,
+						 0x00, 0x43,
+						 (u8)(open_drain ? (1 << id) :
+						       0), (u8)(1 << id));
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	ret =
+	    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS,
+						 0x00, 0x44,
+						 (u8)(invert ? (1 << id) : 0),
+						 (u8)(1 << id));
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	ret =
+	    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS,
+						 0x00, 0x45,
+						 (u8)(en ? 0 : (1 << id)),
+						 (u8)(1 << id));
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_gpio_set_cfg_sub(struct cxd2880_tnrdmd *tnr_dmd,
+						 u8 id,
+						 u8 en,
+						 enum cxd2880_tnrdmd_gpio_mode
+						 mode, u8 open_drain, u8 invert)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	ret =
+	    cxd2880_tnrdmd_gpio_set_cfg(tnr_dmd->diver_sub, id, en, mode,
+					open_drain, invert);
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_gpio_read(struct cxd2880_tnrdmd *tnr_dmd,
+					  u8 id, u8 *value)
+{
+	u8 data = 0;
+
+	if ((!tnr_dmd) || (!value))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (id > 2)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x0A) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x20, &data,
+				   1) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	*value = (u8)((data >> id) & 0x01);
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_gpio_read_sub(struct cxd2880_tnrdmd *tnr_dmd,
+					      u8 id, u8 *value)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	ret = cxd2880_tnrdmd_gpio_read(tnr_dmd->diver_sub, id, value);
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_gpio_write(struct cxd2880_tnrdmd *tnr_dmd,
+					   u8 id, u8 value)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (id > 2)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	ret =
+	    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS,
+						 0x00, 0x46,
+						 (u8)(value ? (1 << id) : 0),
+						 (u8)(1 << id));
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_gpio_write_sub(struct cxd2880_tnrdmd *tnr_dmd,
+					       u8 id, u8 value)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	ret = cxd2880_tnrdmd_gpio_write(tnr_dmd->diver_sub, id, value);
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_interrupt_read(struct cxd2880_tnrdmd *tnr_dmd,
+					       u16 *value)
+{
+	u8 data[2] = { 0 };
+
+	if ((!tnr_dmd) || (!value))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x0A) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x15, data,
+				   2) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	*value = (u16)(((u16)data[0] << 8) | (data[1]));
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_interrupt_clear(struct cxd2880_tnrdmd *tnr_dmd,
+						u16 value)
+{
+	u8 data[2] = { 0 };
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	data[0] = (u8)((value >> 8) & 0xFF);
+	data[1] = (u8)(value & 0xFF);
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_SYS, 0x3C, data,
+				    2) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_ts_buf_clear(struct cxd2880_tnrdmd *tnr_dmd,
+					     u8 clear_overflow_flag,
+					     u8 clear_underflow_flag,
+					     u8 clear_buf)
+{
+	u8 data[2] = { 0 };
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	data[0] = (u8)(clear_overflow_flag ? 0x02 : 0x00);
+	data[0] |= (u8)(clear_underflow_flag ? 0x01 : 0x00);
+	data[1] = (u8)(clear_buf ? 0x01 : 0x00);
+	if (tnr_dmd->io->write_regs(tnr_dmd->io,
+				    CXD2880_IO_TGT_DMD, 0x9F, data,
+				    2) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_chip_id(struct cxd2880_tnrdmd *tnr_dmd,
+					enum cxd2880_tnrdmd_chip_id *chip_id)
+{
+	u8 data = 0;
+
+	if ((!tnr_dmd) || (!chip_id))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0xFD, &data,
+				   1) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	*chip_id = (enum cxd2880_tnrdmd_chip_id)data;
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_set_and_save_reg_bits(struct cxd2880_tnrdmd
+						      *tnr_dmd,
+						      enum cxd2880_io_tgt tgt,
+						      u8 bank, u8 address,
+						      u8 value, u8 bit_mask)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   tgt, 0x00, bank) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (cxd2880_io_set_reg_bits(tnr_dmd->io, tgt, address, value, bit_mask)
+	    != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	ret = set_cfg_mem(tnr_dmd, tgt, bank, address, value, bit_mask);
+	if (ret != CXD2880_RESULT_OK)
+		return ret;
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_set_scan_mode(struct cxd2880_tnrdmd *tnr_dmd,
+					      enum cxd2880_dtv_sys sys,
+					      u8 scan_mode_end)
+{
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	CXD2880_ARG_UNUSED(sys);
+
+	tnr_dmd->scan_mode = scan_mode_end;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+		ret =
+		    cxd2880_tnrdmd_set_scan_mode(tnr_dmd->diver_sub, sys,
+						 scan_mode_end);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	}
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_set_pid_ftr(struct cxd2880_tnrdmd *tnr_dmd,
+					    struct cxd2880_tnrdmd_pid_ftr_cfg
+					    *pid_ftr_cfg)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->create_param.ts_output_if == CXD2880_TNRDMD_TSOUT_IF_TS)
+		return CXD2880_RESULT_ERROR_NOSUPPORT;
+
+	if (pid_ftr_cfg) {
+		tnr_dmd->pid_ftr_cfg = *pid_ftr_cfg;
+		tnr_dmd->pid_ftr_cfg_en = 1;
+	} else {
+		tnr_dmd->pid_ftr_cfg_en = 0;
+	}
+
+	if (tnr_dmd->state == CXD2880_TNRDMD_STATE_ACTIVE) {
+		ret = pid_ftr_setting(tnr_dmd, pid_ftr_cfg);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	}
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_set_rf_lvl_cmpstn(struct cxd2880_tnrdmd
+					  *tnr_dmd,
+					  enum
+					  cxd2880_ret(*rf_lvl_cmpstn)
+					  (struct cxd2880_tnrdmd *,
+					   int *))
+{
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	tnr_dmd->rf_lvl_cmpstn = rf_lvl_cmpstn;
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_set_rf_lvl_cmpstn_sub(struct cxd2880_tnrdmd
+						      *tnr_dmd,
+						      enum
+						      cxd2880_ret
+						      (*rf_lvl_cmpstn)(struct
+								cxd2880_tnrdmd
+								*,
+								int *))
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	ret =
+	    cxd2880_tnrdmd_set_rf_lvl_cmpstn(tnr_dmd->diver_sub, rf_lvl_cmpstn);
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_set_lna_thrs(struct cxd2880_tnrdmd *tnr_dmd,
+					     struct
+					     cxd2880_tnrdmd_lna_thrs_tbl_air
+					     *tbl_air,
+					     struct
+					     cxd2880_tnrdmd_lna_thrs_tbl_cable
+					     *tbl_cable)
+{
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	tnr_dmd->lna_thrs_tbl_air = tbl_air;
+	tnr_dmd->lna_thrs_tbl_cable = tbl_cable;
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_set_lna_thrs_sub(struct cxd2880_tnrdmd *tnr_dmd,
+					 struct
+					 cxd2880_tnrdmd_lna_thrs_tbl_air
+					 *tbl_air,
+					 struct
+					 cxd2880_tnrdmd_lna_thrs_tbl_cable
+					 *tbl_cable)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	ret =
+	    cxd2880_tnrdmd_set_lna_thrs(tnr_dmd->diver_sub, tbl_air, tbl_cable);
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_set_ts_pin_high_low(struct cxd2880_tnrdmd
+						    *tnr_dmd, u8 en, u8 value)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->create_param.ts_output_if != CXD2880_TNRDMD_TSOUT_IF_TS)
+		return CXD2880_RESULT_ERROR_NOSUPPORT;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (en) {
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_SYS, 0x50,
+					   ((value & 0x1F) | 0x80)) !=
+		    CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_SYS, 0x52,
+					   (value & 0x1F)) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	} else {
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS, 0x50, 0x3F);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		if (tnr_dmd->io->write_reg(tnr_dmd->io,
+					   CXD2880_IO_TGT_SYS, 0x52,
+					   0x1F) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		ret = load_cfg_mem(tnr_dmd);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	}
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_set_ts_output(struct cxd2880_tnrdmd *tnr_dmd,
+					      u8 en)
+{
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	switch (tnr_dmd->create_param.ts_output_if) {
+	case CXD2880_TNRDMD_TSOUT_IF_TS:
+		if (en) {
+			if (tnr_dmd->io->write_reg(tnr_dmd->io,
+						   CXD2880_IO_TGT_SYS, 0x00,
+						   0x00) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+			if (tnr_dmd->io->write_reg(tnr_dmd->io,
+						   CXD2880_IO_TGT_SYS, 0x52,
+						   0x00) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+			if (tnr_dmd->io->write_reg(tnr_dmd->io,
+						   CXD2880_IO_TGT_DMD, 0x00,
+						   0x00) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+			if (tnr_dmd->io->write_reg(tnr_dmd->io,
+						   CXD2880_IO_TGT_DMD, 0xC3,
+						   0x00) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		} else {
+			if (tnr_dmd->io->write_reg(tnr_dmd->io,
+						   CXD2880_IO_TGT_DMD, 0x00,
+						   0x00) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+			if (tnr_dmd->io->write_reg(tnr_dmd->io,
+						   CXD2880_IO_TGT_DMD, 0xC3,
+						   0x01) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+			if (tnr_dmd->io->write_reg(tnr_dmd->io,
+						   CXD2880_IO_TGT_SYS, 0x00,
+						   0x00) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+			if (tnr_dmd->io->write_reg(tnr_dmd->io,
+						   CXD2880_IO_TGT_SYS, 0x52,
+						   0x1F) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+		break;
+
+	case CXD2880_TNRDMD_TSOUT_IF_SPI:
+		break;
+
+	case CXD2880_TNRDMD_TSOUT_IF_SDIO:
+		break;
+
+	default:
+		return CXD2880_RESULT_ERROR_SW_STATE;
+	}
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret slvt_freeze_reg(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if (!tnr_dmd)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	switch (tnr_dmd->create_param.ts_output_if) {
+	case CXD2880_TNRDMD_TSOUT_IF_SPI:
+	case CXD2880_TNRDMD_TSOUT_IF_SDIO:
+		{
+			u8 data = 0;
+
+			if (tnr_dmd->io->read_regs(tnr_dmd->io,
+						   CXD2880_IO_TGT_DMD, 0x00,
+						   &data,
+						   1) != CXD2880_RESULT_OK)
+				return CXD2880_RESULT_ERROR_IO;
+		}
+		break;
+	case CXD2880_TNRDMD_TSOUT_IF_TS:
+	default:
+		break;
+	}
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x01,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	return ret;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
new file mode 100644
index 000000000000..26e29b3b9f6b
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
@@ -0,0 +1,395 @@
+/*
+ * cxd2880_tnrdmd.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * common control interface
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_TNRDMD_H
+#define CXD2880_TNRDMD_H
+
+#include "cxd2880_common.h"
+#include "cxd2880_io.h"
+#include "cxd2880_dtv.h"
+#include "cxd2880_dvbt.h"
+#include "cxd2880_dvbt2.h"
+
+#define CXD2880_TNRDMD_MAX_CFG_MEM_COUNT 100
+
+#define slvt_unfreeze_reg(tnr_dmd) ((void)((tnr_dmd)->io->write_reg\
+((tnr_dmd)->io, CXD2880_IO_TGT_DMD, 0x01, 0x00)))
+
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_UNDERFLOW     0x0001
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_OVERFLOW      0x0002
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_ALMOST_EMPTY  0x0004
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_ALMOST_FULL   0x0008
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_RRDY	  0x0010
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_ILLEGAL_COMMAND      0x0020
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_ILLEGAL_ACCESS       0x0040
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_CPU_ERROR	    0x0100
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_LOCK		 0x0200
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_INV_LOCK	     0x0400
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_NOOFDM	       0x0800
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_EWS		  0x1000
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_EEW		  0x2000
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_FEC_FAIL	     0x4000
+
+#define CXD2880_TNRDMD_INTERRUPT_LOCK_SEL_L1POST_OK	0x01
+#define CXD2880_TNRDMD_INTERRUPT_LOCK_SEL_DMD_LOCK	 0x02
+#define CXD2880_TNRDMD_INTERRUPT_LOCK_SEL_TS_LOCK	  0x04
+
+enum cxd2880_tnrdmd_chip_id {
+	CXD2880_TNRDMD_CHIP_ID_UNKNOWN = 0x00,
+	CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X = 0x62,
+	CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11 = 0x6A
+};
+
+#define CXD2880_TNRDMD_CHIP_ID_VALID(chip_id) (((chip_id) == \
+CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) || \
+((chip_id) == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11))
+
+enum cxd2880_tnrdmd_state {
+	CXD2880_TNRDMD_STATE_UNKNOWN,
+	CXD2880_TNRDMD_STATE_SLEEP,
+	CXD2880_TNRDMD_STATE_ACTIVE,
+	CXD2880_TNRDMD_STATE_INVALID
+};
+
+enum cxd2880_tnrdmd_divermode {
+	CXD2880_TNRDMD_DIVERMODE_SINGLE,
+	CXD2880_TNRDMD_DIVERMODE_MAIN,
+	CXD2880_TNRDMD_DIVERMODE_SUB
+};
+
+enum cxd2880_tnrdmd_clockmode {
+	CXD2880_TNRDMD_CLOCKMODE_UNKNOWN,
+	CXD2880_TNRDMD_CLOCKMODE_A,
+	CXD2880_TNRDMD_CLOCKMODE_B,
+	CXD2880_TNRDMD_CLOCKMODE_C
+};
+
+enum cxd2880_tnrdmd_tsout_if {
+	CXD2880_TNRDMD_TSOUT_IF_TS,
+	CXD2880_TNRDMD_TSOUT_IF_SPI,
+	CXD2880_TNRDMD_TSOUT_IF_SDIO
+};
+
+enum cxd2880_tnrdmd_xtal_share {
+	CXD2880_TNRDMD_XTAL_SHARE_NONE,
+	CXD2880_TNRDMD_XTAL_SHARE_EXTREF,
+	CXD2880_TNRDMD_XTAL_SHARE_MASTER,
+	CXD2880_TNRDMD_XTAL_SHARE_SLAVE
+};
+
+enum cxd2880_tnrdmd_spectrum_sense {
+	CXD2880_TNRDMD_SPECTRUM_NORMAL,
+	CXD2880_TNRDMD_SPECTRUM_INV
+};
+
+enum cxd2880_tnrdmd_cfg_id {
+	CXD2880_TNRDMD_CFG_OUTPUT_SEL_MSB,
+	CXD2880_TNRDMD_CFG_TSVALID_ACTIVE_HI,
+	CXD2880_TNRDMD_CFG_TSSYNC_ACTIVE_HI,
+	CXD2880_TNRDMD_CFG_TSERR_ACTIVE_HI,
+	CXD2880_TNRDMD_CFG_LATCH_ON_POSEDGE,
+	CXD2880_TNRDMD_CFG_TSCLK_CONT,
+	CXD2880_TNRDMD_CFG_TSCLK_MASK,
+	CXD2880_TNRDMD_CFG_TSVALID_MASK,
+	CXD2880_TNRDMD_CFG_TSERR_MASK,
+	CXD2880_TNRDMD_CFG_TSERR_VALID_DIS,
+	CXD2880_TNRDMD_CFG_TSPIN_CURRENT,
+	CXD2880_TNRDMD_CFG_TSPIN_PULLUP_MANUAL,
+	CXD2880_TNRDMD_CFG_TSPIN_PULLUP,
+	CXD2880_TNRDMD_CFG_TSCLK_FREQ,
+	CXD2880_TNRDMD_CFG_TSBYTECLK_MANUAL,
+	CXD2880_TNRDMD_CFG_TS_PACKET_GAP,
+	CXD2880_TNRDMD_CFG_TS_BACKWARDS_COMPATIBLE,
+	CXD2880_TNRDMD_CFG_PWM_VALUE,
+	CXD2880_TNRDMD_CFG_INTERRUPT,
+	CXD2880_TNRDMD_CFG_INTERRUPT_LOCK_SEL,
+	CXD2880_TNRDMD_CFG_INTERRUPT_INV_LOCK_SEL,
+	CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_EMPTY_THRS,
+	CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_FULL_THRS,
+	CXD2880_TNRDMD_CFG_TS_BUF_RRDY_THRS,
+	CXD2880_TNRDMD_CFG_FIXED_CLOCKMODE,
+	CXD2880_TNRDMD_CFG_CABLE_INPUT,
+	CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_BASE,
+	CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_LITE,
+	CXD2880_TNRDMD_CFG_BLINDTUNE_DVBT2_FIRST,
+	CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD,
+	CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD,
+	CXD2880_TNRDMD_CFG_DVBT_PER_MES,
+	CXD2880_TNRDMD_CFG_DVBT2_BBER_MES,
+	CXD2880_TNRDMD_CFG_DVBT2_LBER_MES,
+	CXD2880_TNRDMD_CFG_DVBT2_PER_MES,
+	CXD2880_TNRDMD_CFG_ISDBT_BERPER_PERIOD
+};
+
+enum cxd2880_tnrdmd_lock_result {
+	CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT,
+	CXD2880_TNRDMD_LOCK_RESULT_LOCKED,
+	CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED
+};
+
+enum cxd2880_tnrdmd_gpio_mode {
+	CXD2880_TNRDMD_GPIO_MODE_OUTPUT = 0x00,
+	CXD2880_TNRDMD_GPIO_MODE_INPUT = 0x01,
+	CXD2880_TNRDMD_GPIO_MODE_INT = 0x02,
+	CXD2880_TNRDMD_GPIO_MODE_FEC_FAIL = 0x03,
+	CXD2880_TNRDMD_GPIO_MODE_PWM = 0x04,
+	CXD2880_TNRDMD_GPIO_MODE_EWS = 0x05,
+	CXD2880_TNRDMD_GPIO_MODE_EEW = 0x06
+};
+
+enum cxd2880_tnrdmd_serial_ts_clk {
+	CXD2880_TNRDMD_SERIAL_TS_CLK_FULL,
+	CXD2880_TNRDMD_SERIAL_TS_CLK_HALF
+};
+
+struct cxd2880_tnrdmd_cfg_mem {
+	enum cxd2880_io_tgt tgt;
+	u8 bank;
+	u8 address;
+	u8 value;
+	u8 bit_mask;
+};
+
+struct cxd2880_tnrdmd_pid_cfg {
+	u8 is_en;
+	u16 pid;
+};
+
+struct cxd2880_tnrdmd_pid_ftr_cfg {
+	u8 is_negative;
+	struct cxd2880_tnrdmd_pid_cfg pid_cfg[32];
+};
+
+struct cxd2880_tnrdmd_ts_buf_info {
+	u8 read_ready;
+	u8 almost_full;
+	u8 almost_empty;
+	u8 overflow;
+	u8 underflow;
+	u16 packet_num;
+};
+
+struct cxd2880_tnrdmd_lna_thrs {
+	u8 off_on;
+	u8 on_off;
+};
+
+struct cxd2880_tnrdmd_lna_thrs_tbl_air {
+	struct cxd2880_tnrdmd_lna_thrs thrs[24];
+};
+
+struct cxd2880_tnrdmd_lna_thrs_tbl_cable {
+	struct cxd2880_tnrdmd_lna_thrs thrs[32];
+};
+
+struct cxd2880_tnrdmd_create_param {
+	enum cxd2880_tnrdmd_tsout_if ts_output_if;
+	u8 en_internal_ldo;
+	enum cxd2880_tnrdmd_xtal_share xtal_share_type;
+	u8 xosc_cap;
+	u8 xosc_i;
+	u8 is_cxd2881gg;
+	u8 stationary_use;
+};
+
+struct cxd2880_tnrdmd_diver_create_param {
+	enum cxd2880_tnrdmd_tsout_if ts_output_if;
+	u8 en_internal_ldo;
+	u8 xosc_cap_main;
+	u8 xosc_i_main;
+	u8 xosc_i_sub;
+	u8 is_cxd2881gg;
+	u8 stationary_use;
+};
+
+struct cxd2880_tnrdmd {
+	struct cxd2880_tnrdmd *diver_sub;
+	struct cxd2880_io *io;
+	struct cxd2880_tnrdmd_create_param create_param;
+	enum cxd2880_tnrdmd_divermode diver_mode;
+	enum cxd2880_tnrdmd_clockmode fixed_clk_mode;
+	u8 is_cable_input;
+	u8 en_fef_intmtnt_base;
+	u8 en_fef_intmtnt_lite;
+	u8 blind_tune_dvbt2_first;
+	enum cxd2880_ret (*rf_lvl_cmpstn)(struct cxd2880_tnrdmd *tnr_dmd,
+					   int *rf_lvl_db);
+	struct cxd2880_tnrdmd_lna_thrs_tbl_air *lna_thrs_tbl_air;
+	struct cxd2880_tnrdmd_lna_thrs_tbl_cable *lna_thrs_tbl_cable;
+	u8 srl_ts_clk_mod_cnts;
+	enum cxd2880_tnrdmd_serial_ts_clk srl_ts_clk_frq;
+	u8 ts_byte_clk_manual_setting;
+	u8 is_ts_backwards_compatible_mode;
+	struct cxd2880_tnrdmd_cfg_mem cfg_mem[CXD2880_TNRDMD_MAX_CFG_MEM_COUNT];
+	u8 cfg_mem_last_entry;
+	struct cxd2880_tnrdmd_pid_ftr_cfg pid_ftr_cfg;
+	u8 pid_ftr_cfg_en;
+	void *user;
+	enum cxd2880_tnrdmd_chip_id chip_id;
+	enum cxd2880_tnrdmd_state state;
+	enum cxd2880_tnrdmd_clockmode clk_mode;
+	u32 frequency_khz;
+	enum cxd2880_dtv_sys sys;
+	enum cxd2880_dtv_bandwidth bandwidth;
+	u8 scan_mode;
+	struct cxd2880_atomic cancel;
+};
+
+enum cxd2880_ret cxd2880_tnrdmd_create(struct cxd2880_tnrdmd *tnr_dmd,
+				       struct cxd2880_io *io,
+				       struct cxd2880_tnrdmd_create_param
+				       *create_param);
+
+enum cxd2880_ret cxd2880_tnrdmd_diver_create(struct cxd2880_tnrdmd
+					     *tnr_dmd_main,
+					     struct cxd2880_io *io_main,
+					     struct cxd2880_tnrdmd *tnr_dmd_sub,
+					     struct cxd2880_io *io_sub,
+					     struct
+					     cxd2880_tnrdmd_diver_create_param
+					     *create_param);
+
+enum cxd2880_ret cxd2880_tnrdmd_init1(struct cxd2880_tnrdmd *tnr_dmd);
+
+enum cxd2880_ret cxd2880_tnrdmd_init2(struct cxd2880_tnrdmd *tnr_dmd);
+
+enum cxd2880_ret cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd
+							  *tnr_dmd,
+							  u8 *task_completed);
+
+enum cxd2880_ret cxd2880_tnrdmd_common_tune_setting1(struct cxd2880_tnrdmd
+						     *tnr_dmd,
+						     enum cxd2880_dtv_sys sys,
+						     u32 frequency_khz,
+						     enum cxd2880_dtv_bandwidth
+						     bandwidth, u8 one_seg_opt,
+						     u8 one_seg_opt_shft_dir);
+
+enum cxd2880_ret cxd2880_tnrdmd_common_tune_setting2(struct cxd2880_tnrdmd
+						     *tnr_dmd,
+						     enum cxd2880_dtv_sys sys,
+						     u8 en_fef_intmtnt_ctrl);
+
+enum cxd2880_ret cxd2880_tnrdmd_sleep(struct cxd2880_tnrdmd *tnr_dmd);
+
+enum cxd2880_ret cxd2880_tnrdmd_set_cfg(struct cxd2880_tnrdmd *tnr_dmd,
+					enum cxd2880_tnrdmd_cfg_id id,
+					int value);
+
+enum cxd2880_ret cxd2880_tnrdmd_gpio_set_cfg(struct cxd2880_tnrdmd *tnr_dmd,
+					     u8 id,
+					     u8 en,
+					     enum cxd2880_tnrdmd_gpio_mode mode,
+					     u8 open_drain, u8 invert);
+
+enum cxd2880_ret cxd2880_tnrdmd_gpio_set_cfg_sub(struct cxd2880_tnrdmd *tnr_dmd,
+						 u8 id,
+						 u8 en,
+						 enum cxd2880_tnrdmd_gpio_mode
+						 mode, u8 open_drain,
+						 u8 invert);
+
+enum cxd2880_ret cxd2880_tnrdmd_gpio_read(struct cxd2880_tnrdmd *tnr_dmd,
+					  u8 id, u8 *value);
+
+enum cxd2880_ret cxd2880_tnrdmd_gpio_read_sub(struct cxd2880_tnrdmd *tnr_dmd,
+					      u8 id, u8 *value);
+
+enum cxd2880_ret cxd2880_tnrdmd_gpio_write(struct cxd2880_tnrdmd *tnr_dmd,
+					   u8 id, u8 value);
+
+enum cxd2880_ret cxd2880_tnrdmd_gpio_write_sub(struct cxd2880_tnrdmd *tnr_dmd,
+					       u8 id, u8 value);
+
+enum cxd2880_ret cxd2880_tnrdmd_interrupt_read(struct cxd2880_tnrdmd *tnr_dmd,
+					       u16 *value);
+
+enum cxd2880_ret cxd2880_tnrdmd_interrupt_clear(struct cxd2880_tnrdmd *tnr_dmd,
+						u16 value);
+
+enum cxd2880_ret cxd2880_tnrdmd_ts_buf_clear(struct cxd2880_tnrdmd *tnr_dmd,
+					     u8 clear_overflow_flag,
+					     u8 clear_underflow_flag,
+					     u8 clear_buf);
+
+enum cxd2880_ret cxd2880_tnrdmd_chip_id(struct cxd2880_tnrdmd *tnr_dmd,
+					enum cxd2880_tnrdmd_chip_id *chip_id);
+
+enum cxd2880_ret cxd2880_tnrdmd_set_and_save_reg_bits(struct cxd2880_tnrdmd
+						      *tnr_dmd,
+						      enum cxd2880_io_tgt tgt,
+						      u8 bank, u8 address,
+						      u8 value, u8 bit_mask);
+
+enum cxd2880_ret cxd2880_tnrdmd_set_scan_mode(struct cxd2880_tnrdmd *tnr_dmd,
+					      enum cxd2880_dtv_sys sys,
+					      u8 scan_mode_end);
+
+enum cxd2880_ret cxd2880_tnrdmd_set_pid_ftr(struct cxd2880_tnrdmd *tnr_dmd,
+					    struct cxd2880_tnrdmd_pid_ftr_cfg
+					    *pid_ftr_cfg);
+
+enum cxd2880_ret cxd2880_tnrdmd_set_rf_lvl_cmpstn(struct cxd2880_tnrdmd
+						  *tnr_dmd,
+						  enum
+						  cxd2880_ret(*rf_lvl_cmpstn)
+						  (struct cxd2880_tnrdmd *,
+						   int *));
+
+enum cxd2880_ret cxd2880_tnrdmd_set_rf_lvl_cmpstn_sub(struct cxd2880_tnrdmd
+						      *tnr_dmd,
+						      enum
+						      cxd2880_ret
+						      (*rf_lvl_cmpstn)(struct
+								cxd2880_tnrdmd
+								*,
+								int *));
+
+enum cxd2880_ret cxd2880_tnrdmd_set_lna_thrs(struct cxd2880_tnrdmd *tnr_dmd,
+					     struct
+					     cxd2880_tnrdmd_lna_thrs_tbl_air
+					     *tbl_air,
+					     struct
+					     cxd2880_tnrdmd_lna_thrs_tbl_cable
+					     *tbl_cable);
+
+enum cxd2880_ret cxd2880_tnrdmd_set_lna_thrs_sub(struct cxd2880_tnrdmd *tnr_dmd,
+					 struct
+					 cxd2880_tnrdmd_lna_thrs_tbl_air
+					 *tbl_air,
+					 struct
+					 cxd2880_tnrdmd_lna_thrs_tbl_cable
+					 *tbl_cable);
+
+enum cxd2880_ret cxd2880_tnrdmd_set_ts_pin_high_low(struct cxd2880_tnrdmd
+						    *tnr_dmd, u8 en, u8 value);
+
+enum cxd2880_ret cxd2880_tnrdmd_set_ts_output(struct cxd2880_tnrdmd *tnr_dmd,
+					      u8 en);
+
+enum cxd2880_ret slvt_freeze_reg(struct cxd2880_tnrdmd *tnr_dmd);
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
new file mode 100644
index 000000000000..68fb3af04bd4
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
@@ -0,0 +1,29 @@
+/*
+ * cxd2880_tnrdmd_driver_version.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * version information
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define CXD2880_TNRDMD_DRIVER_VERSION "1.4.1 - 1.0.1"
+
+#define CXD2880_TNRDMD_DRIVER_RELEASE_DATE "2017-04-13"
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
new file mode 100644
index 000000000000..0ac5b9bf3be8
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
@@ -0,0 +1,207 @@
+/*
+ * cxd2880_tnrdmd_mon.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * common monitor functions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_common.h"
+#include "cxd2880_tnrdmd_mon.h"
+
+enum cxd2880_ret cxd2880_tnrdmd_mon_rf_lvl(struct cxd2880_tnrdmd *tnr_dmd,
+					   int *rf_lvl_db)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!rf_lvl_db))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x10,
+				   0x01) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x10) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	{
+		u8 data[2] = { 0x80, 0x00 };
+
+		if (tnr_dmd->io->write_regs(tnr_dmd->io,
+					    CXD2880_IO_TGT_SYS, 0x5B, data,
+					    2) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+	}
+
+	CXD2880_SLEEP_IN_MON(2, tnr_dmd);
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x1A) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	{
+		u8 data[2];
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_SYS, 0x15, data,
+					   2) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		if ((data[0] != 0) || (data[1] != 0))
+			return CXD2880_RESULT_ERROR_OTHER;
+
+		if (tnr_dmd->io->read_regs(tnr_dmd->io,
+					   CXD2880_IO_TGT_SYS, 0x11, data,
+					   2) != CXD2880_RESULT_OK)
+			return CXD2880_RESULT_ERROR_IO;
+
+		*rf_lvl_db =
+		    cxd2880_convert2s_complement((data[0] << 3) |
+						 ((data[1] & 0xE0) >> 5), 11);
+	}
+
+	*rf_lvl_db *= 125;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x10,
+				   0x00) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	if (tnr_dmd->rf_lvl_cmpstn) {
+		ret = tnr_dmd->rf_lvl_cmpstn(tnr_dmd, rf_lvl_db);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+	}
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_mon_rf_lvl_sub(struct cxd2880_tnrdmd *tnr_dmd,
+					       int *rf_lvl_db)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!rf_lvl_db))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, rf_lvl_db);
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_mon_internal_cpu_status(struct cxd2880_tnrdmd
+							*tnr_dmd, u16 *status)
+{
+	u8 data[2] = { 0 };
+
+	if ((!tnr_dmd) || (!status))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x00,
+				   0x1A) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_SYS, 0x15, data,
+				   2) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	*status = (u16)(((u16)data[0] << 8) | data[1]);
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_mon_internal_cpu_status_sub(struct
+							    cxd2880_tnrdmd
+							    *tnr_dmd,
+							    u16 *status)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!status))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	ret =
+	    cxd2880_tnrdmd_mon_internal_cpu_status(tnr_dmd->diver_sub, status);
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_tnrdmd_mon_ts_buf_info(struct cxd2880_tnrdmd *tnr_dmd,
+						struct
+						cxd2880_tnrdmd_ts_buf_info
+						*info)
+{
+	u8 data[3] = { 0 };
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if ((!tnr_dmd) || (!info))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return CXD2880_RESULT_ERROR_SW_STATE;
+
+	if (tnr_dmd->io->write_reg(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x00,
+				   0x0A) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+	if (tnr_dmd->io->read_regs(tnr_dmd->io,
+				   CXD2880_IO_TGT_DMD, 0x50, data,
+				   3) != CXD2880_RESULT_OK)
+		return CXD2880_RESULT_ERROR_IO;
+
+	info->read_ready = (u8)((data[0] & 0x10) ? 0x01 : 0x00);
+	info->almost_full = (u8)((data[0] & 0x08) ? 0x01 : 0x00);
+	info->almost_empty = (u8)((data[0] & 0x04) ? 0x01 : 0x00);
+	info->overflow = (u8)((data[0] & 0x02) ? 0x01 : 0x00);
+	info->underflow = (u8)((data[0] & 0x01) ? 0x01 : 0x00);
+
+	info->packet_num = (u16)(((u32)(data[1] & 0x07) << 8) | data[2]);
+
+	return ret;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h
new file mode 100644
index 000000000000..506bd559668f
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h
@@ -0,0 +1,52 @@
+/*
+ * cxd2880_tnrdmd_mon.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * common monitor interface
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_TNRDMD_MON_H
+#define CXD2880_TNRDMD_MON_H
+
+#include "cxd2880_common.h"
+#include "cxd2880_tnrdmd.h"
+
+enum cxd2880_ret cxd2880_tnrdmd_mon_rf_lvl(struct cxd2880_tnrdmd *tnr_dmd,
+					   int *rf_lvl_db);
+
+enum cxd2880_ret cxd2880_tnrdmd_mon_rf_lvl_sub(struct cxd2880_tnrdmd *tnr_dmd,
+					       int *rf_lvl_db);
+
+enum cxd2880_ret cxd2880_tnrdmd_mon_internal_cpu_status(struct cxd2880_tnrdmd
+							*tnr_dmd, u16 *status);
+
+enum cxd2880_ret cxd2880_tnrdmd_mon_internal_cpu_status_sub(struct
+							    cxd2880_tnrdmd
+							    *tnr_dmd,
+							    u16 *status);
+
+enum cxd2880_ret cxd2880_tnrdmd_mon_ts_buf_info(struct cxd2880_tnrdmd *tnr_dmd,
+						struct
+						cxd2880_tnrdmd_ts_buf_info
+						*info);
+
+#endif
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v2 05/15] [media] cxd2880: Add spi device IO routines
From: Yasunari.Takiguchi @ 2017-04-14  2:25 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-media
  Cc: tbird20d, frowand.list, Yasunari Takiguchi, Masayuki Yamamoto,
	Hideki Nozawa, Kota Yonezawa, Toshihiko Matsumoto,
	Satoshi Watanabe
In-Reply-To: <20170414015043.16731-1-Yasunari.Takiguchi@sony.com>

From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

Add functions for initializing, reading and writing to the SPI
device for the Sony CXD2880 DVB-T2/T tuner + demodulator.

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
---
 .../dvb-frontends/cxd2880/cxd2880_devio_spi.c      | 147 +++++++++++++++++++++
 .../dvb-frontends/cxd2880/cxd2880_devio_spi.h      |  40 ++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h  |  51 +++++++
 .../dvb-frontends/cxd2880/cxd2880_spi_device.c     | 130 ++++++++++++++++++
 .../dvb-frontends/cxd2880/cxd2880_spi_device.h     |  45 +++++++
 5 files changed, 413 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h

diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c
new file mode 100644
index 000000000000..516efade6bf5
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c
@@ -0,0 +1,147 @@
+/*
+ * cxd2880_devio_spi.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * I/O interface via SPI
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_devio_spi.h"
+#include "cxd2880_stdlib.h"
+
+#define BURST_WRITE_MAX 128
+
+static enum cxd2880_ret cxd2880_io_spi_read_reg(struct cxd2880_io *io,
+						enum cxd2880_io_tgt tgt,
+						u8 sub_address, u8 *data,
+						u32 size)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	struct cxd2880_spi *spi = NULL;
+	u8 send_data[6];
+	u8 *read_data_top = data;
+
+	if ((!io) || (!io->if_object) || (!data))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (sub_address + size > 0x100)
+		return CXD2880_RESULT_ERROR_RANGE;
+
+	spi = (struct cxd2880_spi *)(io->if_object);
+
+	if (tgt == CXD2880_IO_TGT_SYS)
+		send_data[0] = 0x0B;
+	else
+		send_data[0] = 0x0A;
+
+	send_data[3] = 0;
+	send_data[4] = 0;
+	send_data[5] = 0;
+
+	while (size > 0) {
+		send_data[1] = sub_address;
+		if (size > 255)
+			send_data[2] = 255;
+		else
+			send_data[2] = (u8)size;
+
+		ret =
+		    spi->write_read(spi, send_data, sizeof(send_data),
+				    read_data_top, send_data[2]);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		sub_address += send_data[2];
+		read_data_top += send_data[2];
+		size -= send_data[2];
+	}
+
+	return ret;
+}
+
+static enum cxd2880_ret cxd2880_io_spi_write_reg(struct cxd2880_io *io,
+						 enum cxd2880_io_tgt tgt,
+						 u8 sub_address,
+						 const u8 *data, u32 size)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+	struct cxd2880_spi *spi = NULL;
+	u8 send_data[BURST_WRITE_MAX + 4];
+	const u8 *write_data_top = data;
+
+	if ((!io) || (!io->if_object) || (!data))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (size > BURST_WRITE_MAX)
+		return CXD2880_RESULT_ERROR_OVERFLOW;
+
+	if (sub_address + size > 0x100)
+		return CXD2880_RESULT_ERROR_RANGE;
+
+	spi = (struct cxd2880_spi *)(io->if_object);
+
+	if (tgt == CXD2880_IO_TGT_SYS)
+		send_data[0] = 0x0F;
+	else
+		send_data[0] = 0x0E;
+
+	while (size > 0) {
+		send_data[1] = sub_address;
+		if (size > 255)
+			send_data[2] = 255;
+		else
+			send_data[2] = (u8)size;
+
+		cxd2880_memcpy(&send_data[3], write_data_top, send_data[2]);
+
+		if (tgt == CXD2880_IO_TGT_SYS) {
+			send_data[3 + send_data[2]] = 0x00;
+			ret = spi->write(spi, send_data, send_data[2] + 4);
+		} else {
+			ret = spi->write(spi, send_data, send_data[2] + 3);
+		}
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		sub_address += send_data[2];
+		write_data_top += send_data[2];
+		size -= send_data[2];
+	}
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_io_spi_create(struct cxd2880_io *io,
+				       struct cxd2880_spi *spi, u8 slave_select)
+{
+	if ((!io) || (!spi))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	io->read_regs = cxd2880_io_spi_read_reg;
+	io->write_regs = cxd2880_io_spi_write_reg;
+	io->write_reg = cxd2880_io_common_write_one_reg;
+	io->if_object = spi;
+	io->i2c_address_sys = 0;
+	io->i2c_address_demod = 0;
+	io->slave_select = slave_select;
+
+	return CXD2880_RESULT_OK;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h
new file mode 100644
index 000000000000..15934bf11935
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h
@@ -0,0 +1,40 @@
+/*
+ * cxd2880_devio_spi.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * I/O interface via SPI
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_DEVIO_SPI_H
+#define CXD2880_DEVIO_SPI_H
+
+#include "cxd2880_common.h"
+#include "cxd2880_io.h"
+#include "cxd2880_spi.h"
+
+#include "cxd2880_tnrdmd.h"
+
+enum cxd2880_ret cxd2880_io_spi_create(struct cxd2880_io *io,
+				       struct cxd2880_spi *spi,
+				       u8 slave_select);
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h
new file mode 100644
index 000000000000..81e5be747962
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h
@@ -0,0 +1,51 @@
+/*
+ * cxd2880_spi.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * SPI access definitions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_SPI_H
+#define CXD2880_SPI_H
+
+#include "cxd2880_common.h"
+
+enum cxd2880_spi_mode {
+	CXD2880_SPI_MODE_0,
+	CXD2880_SPI_MODE_1,
+	CXD2880_SPI_MODE_2,
+	CXD2880_SPI_MODE_3
+};
+
+struct cxd2880_spi {
+	enum cxd2880_ret (*read)(struct cxd2880_spi *spi, u8 *data,
+				  u32 size);
+	enum cxd2880_ret (*write)(struct cxd2880_spi *spi, const u8 *data,
+				   u32 size);
+	enum cxd2880_ret (*write_read)(struct cxd2880_spi *spi,
+					const u8 *tx_data, u32 tx_size,
+					u8 *rx_data, u32 rx_size);
+	u32 flags;
+	void *user;
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c
new file mode 100644
index 000000000000..af9ed40c900b
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c
@@ -0,0 +1,130 @@
+/*
+ * cxd2880_spi_device.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * SPI access functions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/spi/spi.h>
+
+#include "cxd2880_spi_device.h"
+
+static enum cxd2880_ret cxd2880_spi_device_write(struct cxd2880_spi *spi,
+						const u8 *data, u32 size)
+{
+	struct cxd2880_spi_device *spi_device = NULL;
+	struct spi_message msg;
+	struct spi_transfer tx;
+	int result = 0;
+
+	if ((!spi) || (!spi->user) || (!data) || (size == 0))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	spi_device = (struct cxd2880_spi_device *)(spi->user);
+
+	memset(&tx, 0, sizeof(tx));
+	tx.tx_buf = data;
+	tx.len = size;
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&tx, &msg);
+	result = spi_sync(spi_device->spi, &msg);
+
+	if (result < 0)
+		return CXD2880_RESULT_ERROR_IO;
+
+	return CXD2880_RESULT_OK;
+}
+
+static enum cxd2880_ret cxd2880_spi_device_write_read(struct cxd2880_spi *spi,
+							const u8 *tx_data,
+							u32 tx_size,
+							u8 *rx_data,
+							u32 rx_size)
+{
+	struct cxd2880_spi_device *spi_device = NULL;
+	int result = 0;
+
+	if ((!spi) || (!spi->user) || (!tx_data) ||
+		 (tx_size == 0) || (!rx_data) || (rx_size == 0))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	spi_device = (struct cxd2880_spi_device *)(spi->user);
+
+	result = spi_write_then_read(spi_device->spi, tx_data,
+					tx_size, rx_data, rx_size);
+	if (result < 0)
+		return CXD2880_RESULT_ERROR_IO;
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret
+cxd2880_spi_device_initialize(struct cxd2880_spi_device *spi_device,
+				enum cxd2880_spi_mode mode,
+				u32 speed_hz)
+{
+	int result = 0;
+	struct spi_device *spi = spi_device->spi;
+
+	switch (mode) {
+	case CXD2880_SPI_MODE_0:
+		spi->mode = SPI_MODE_0;
+		break;
+	case CXD2880_SPI_MODE_1:
+		spi->mode = SPI_MODE_1;
+		break;
+	case CXD2880_SPI_MODE_2:
+		spi->mode = SPI_MODE_2;
+		break;
+	case CXD2880_SPI_MODE_3:
+		spi->mode = SPI_MODE_3;
+		break;
+	default:
+		return CXD2880_RESULT_ERROR_ARG;
+	}
+
+	spi->max_speed_hz = speed_hz;
+	spi->bits_per_word = 8;
+	result = spi_setup(spi);
+	if (result != 0) {
+		pr_err("spi_setup failed %d\n", result);
+		return CXD2880_RESULT_ERROR_ARG;
+	}
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_spi_device_create_spi(struct cxd2880_spi *spi,
+					struct cxd2880_spi_device *spi_device)
+{
+	if ((!spi) || (!spi_device))
+		return CXD2880_RESULT_ERROR_ARG;
+
+	spi->read = NULL;
+	spi->write = cxd2880_spi_device_write;
+	spi->write_read = cxd2880_spi_device_write_read;
+	spi->flags = 0;
+	spi->user = spi_device;
+
+	return CXD2880_RESULT_OK;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h
new file mode 100644
index 000000000000..343d9161d537
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h
@@ -0,0 +1,45 @@
+/*
+ * cxd2880_spi_device.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * SPI access interface
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_SPI_DEVICE_H
+#define CXD2880_SPI_DEVICE_H
+
+#include "cxd2880_spi.h"
+
+struct cxd2880_spi_device {
+	struct spi_device *spi;
+};
+
+enum cxd2880_ret
+cxd2880_spi_device_initialize(struct cxd2880_spi_device *spi_device,
+				enum cxd2880_spi_mode mode,
+				u32 speedHz);
+
+enum cxd2880_ret
+cxd2880_spi_device_create_spi(struct cxd2880_spi *spi,
+				struct cxd2880_spi_device *spi_device);
+
+#endif /* CXD2880_SPI_DEVICE_H */
-- 
2.11.0

^ permalink raw reply related

* [PATCH v2 04/15] [media] cxd2880: Add math functions for the driver
From: Yasunari.Takiguchi-7U/KSKJipcs @ 2017-04-14  2:22 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA
  Cc: tbird20d-Re5JQEeQqe8AvxtiuMwx3w,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w, Yasunari Takiguchi,
	Masayuki Yamamoto, Hideki Nozawa, Kota Yonezawa,
	Toshihiko Matsumoto, Satoshi Watanabe
In-Reply-To: <20170414015043.16731-1-Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>

From: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>

Provide some math support functions (fixed-point log functions)
for the Sony CXD2880 DVB-T2/T tuner + demodulator driver.

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe-7U/KSKJipcs@public.gmane.org>
---
 drivers/media/dvb-frontends/cxd2880/cxd2880_math.c | 89 ++++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_math.h | 40 ++++++++++
 2 files changed, 129 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_math.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_math.h

diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_math.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_math.c
new file mode 100644
index 000000000000..434c827898ff
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_math.c
@@ -0,0 +1,89 @@
+/*
+ * cxd2880_math.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * mathmatics functions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_math.h"
+
+#define MAX_BIT_PRECISION	  5
+#define FRAC_BITMASK	    0x1F
+#define LOG2_10_100X	     332
+#define LOG2_E_100X	      144
+
+static const u8 log2_look_up[] = {
+	0, 4,
+	9, 13,
+	17, 21,
+	25, 29,
+	32, 36,
+	39, 43,
+	46, 49,
+	52, 55,
+	58, 61,
+	64, 67,
+	70, 73,
+	75, 78,
+	81, 83,
+	86, 88,
+	91, 93,
+	95, 98
+};
+
+u32 cxd2880_math_log2(u32 x)
+{
+	u8 count = 0;
+	u8 index = 0;
+	u32 xval = x;
+
+	for (x >>= 1; x > 0; x >>= 1)
+		count++;
+
+	x = count * 100;
+
+	if (count > 0) {
+		if (count <= MAX_BIT_PRECISION) {
+			index =
+			    (u8)(xval << (MAX_BIT_PRECISION - count)) &
+			    FRAC_BITMASK;
+			x += log2_look_up[index];
+		} else {
+			index =
+			    (u8)(xval >> (count - MAX_BIT_PRECISION)) &
+			    FRAC_BITMASK;
+			x += log2_look_up[index];
+		}
+	}
+
+	return x;
+}
+
+u32 cxd2880_math_log10(u32 x)
+{
+	return ((100 * cxd2880_math_log2(x) + LOG2_10_100X / 2) / LOG2_10_100X);
+}
+
+u32 cxd2880_math_log(u32 x)
+{
+	return ((100 * cxd2880_math_log2(x) + LOG2_E_100X / 2) / LOG2_E_100X);
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_math.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_math.h
new file mode 100644
index 000000000000..94211835a4ad
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_math.h
@@ -0,0 +1,40 @@
+/*
+ * cxd2880_math.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * mathmatics definitions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_MATH_H_
+#define CXD2880_MATH_H_
+
+#include "cxd2880_common.h"
+
+u32 cxd2880_math_log2(u32 x);
+u32 cxd2880_math_log10(u32 x);
+u32 cxd2880_math_log(u32 x);
+
+#ifndef min
+#define min(a, b)	    (((a) < (b)) ? (a) : (b))
+#endif
+
+#endif
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v2 03/15] [media] cxd2880: Add common files for the driver
From: Yasunari.Takiguchi-7U/KSKJipcs @ 2017-04-14  2:17 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA
  Cc: tbird20d-Re5JQEeQqe8AvxtiuMwx3w,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w, Yasunari Takiguchi,
	Masayuki Yamamoto, Hideki Nozawa, Kota Yonezawa,
	Toshihiko Matsumoto, Satoshi Watanabe
In-Reply-To: <20170414015043.16731-1-Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>

From: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>

These are common files for the driver for the
Sony CXD2880 DVB-T2/T tuner + demodulator.
These contains helper functions for the driver.

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe-7U/KSKJipcs@public.gmane.org>
---
 drivers/media/dvb-frontends/cxd2880/cxd2880.h      | 46 ++++++++++++
 .../media/dvb-frontends/cxd2880/cxd2880_common.c   | 84 +++++++++++++++++++++
 .../media/dvb-frontends/cxd2880/cxd2880_common.h   | 86 ++++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_io.c   | 68 +++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_io.h   | 62 ++++++++++++++++
 .../media/dvb-frontends/cxd2880/cxd2880_stdlib.h   | 35 +++++++++
 .../dvb-frontends/cxd2880/cxd2880_stopwatch_port.c | 71 ++++++++++++++++++
 7 files changed, 452 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_common.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_common.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_io.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_io.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_stdlib.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c

diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880.h b/drivers/media/dvb-frontends/cxd2880/cxd2880.h
new file mode 100644
index 000000000000..281f9a784eb5
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880.h
@@ -0,0 +1,46 @@
+/*
+ * cxd2880.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver public definitions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_H
+#define CXD2880_H
+
+struct cxd2880_config {
+	struct spi_device *spi;
+	struct mutex *spi_mutex; /* For SPI access exclusive control */
+};
+
+#if IS_REACHABLE(CONFIG_DVB_CXD2880)
+extern struct dvb_frontend *cxd2880_attach(struct dvb_frontend *fe,
+					struct cxd2880_config *cfg);
+#else
+static inline struct dvb_frontend *cxd2880_attach(struct dvb_frontend *fe,
+					struct cxd2880_config *cfg)
+{
+	pr_warn("%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_CXD2880 */
+
+#endif /* CXD2880_H */
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_common.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.c
new file mode 100644
index 000000000000..850f3a76b2c7
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.c
@@ -0,0 +1,84 @@
+/*
+ * cxd2880_common.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * common functions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_common.h"
+
+#define MASKUPPER(n) (((n) == 0) ? 0 : (0xFFFFFFFFU << (32 - (n))))
+#define MASKLOWER(n) (((n) == 0) ? 0 : (0xFFFFFFFFU >> (32 - (n))))
+
+int cxd2880_convert2s_complement(u32 value, u32 bitlen)
+{
+	if ((bitlen == 0) || (bitlen >= 32))
+		return (int)value;
+
+	if (value & (u32)(1 << (bitlen - 1)))
+		return (int)(MASKUPPER(32 - bitlen) | value);
+	else
+		return (int)(MASKLOWER(bitlen) & value);
+}
+
+u32 cxd2880_bit_split_from_byte_array(u8 *array, u32 start_bit, u32 bit_num)
+{
+	u32 value = 0;
+	u8 *array_read;
+	u8 bit_read;
+	u32 len_remain;
+
+	if (!array)
+		return 0;
+	if ((bit_num == 0) || (bit_num > 32))
+		return 0;
+
+	array_read = array + (start_bit / 8);
+	bit_read = (u8)(start_bit % 8);
+	len_remain = bit_num;
+
+	if (bit_read != 0) {
+		if (((int)len_remain) <= 8 - bit_read) {
+			value = (*array_read) >> ((8 - bit_read) - len_remain);
+			len_remain = 0;
+		} else {
+			value = *array_read++;
+			len_remain -= 8 - bit_read;
+		}
+	}
+
+	while (len_remain > 0) {
+		if (len_remain < 8) {
+			value <<= len_remain;
+			value |= (*array_read++ >> (8 - len_remain));
+			len_remain = 0;
+		} else {
+			value <<= 8;
+			value |= (u32)(*array_read++);
+			len_remain -= 8;
+		}
+	}
+
+	value &= MASKLOWER(bit_num);
+
+	return value;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_common.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.h
new file mode 100644
index 000000000000..b1ecb44bca10
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.h
@@ -0,0 +1,86 @@
+/*
+ * cxd2880_common.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver common definitions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_COMMON_H
+#define CXD2880_COMMON_H
+
+#include <linux/types.h>
+
+#ifndef NULL
+#ifdef __cplusplus
+#define NULL 0
+#else
+#define NULL ((void *)0)
+#endif
+#endif
+
+#include <linux/delay.h>
+#define CXD2880_SLEEP(n) msleep(n)
+#ifndef CXD2880_SLEEP_IN_MON
+#define CXD2880_SLEEP_IN_MON(n, obj) CXD2880_SLEEP(n)
+#endif
+
+#define CXD2880_ARG_UNUSED(arg) ((void)(arg))
+
+enum cxd2880_ret {
+	CXD2880_RESULT_OK,
+	CXD2880_RESULT_ERROR_ARG,
+	CXD2880_RESULT_ERROR_IO,
+	CXD2880_RESULT_ERROR_SW_STATE,
+	CXD2880_RESULT_ERROR_HW_STATE,
+	CXD2880_RESULT_ERROR_TIMEOUT,
+	CXD2880_RESULT_ERROR_UNLOCK,
+	CXD2880_RESULT_ERROR_RANGE,
+	CXD2880_RESULT_ERROR_NOSUPPORT,
+	CXD2880_RESULT_ERROR_CANCEL,
+	CXD2880_RESULT_ERROR_OTHER,
+	CXD2880_RESULT_ERROR_OVERFLOW,
+	CXD2880_RESULT_OK_CONFIRM
+};
+
+int cxd2880_convert2s_complement(u32 value, u32 bitlen);
+
+u32 cxd2880_bit_split_from_byte_array(u8 *array, u32 start_bit, u32 bit_num);
+
+struct cxd2880_atomic {
+	int counter;
+};
+
+#define cxd2880_atomic_set(a, i) ((a)->counter = i)
+#define cxd2880_atomic_read(a) ((a)->counter)
+
+struct cxd2880_stopwatch {
+	u32 start_time;
+};
+
+enum cxd2880_ret cxd2880_stopwatch_start(struct cxd2880_stopwatch *stopwatch);
+
+enum cxd2880_ret cxd2880_stopwatch_sleep(struct cxd2880_stopwatch *stopwatch,
+					 u32 ms);
+
+enum cxd2880_ret cxd2880_stopwatch_elapsed(struct cxd2880_stopwatch *stopwatch,
+					   u32 *elapsed);
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_io.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.c
new file mode 100644
index 000000000000..f0f82055a953
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.c
@@ -0,0 +1,68 @@
+/*
+ * cxd2880_io.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * register I/O interface functions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_io.h"
+
+enum cxd2880_ret cxd2880_io_common_write_one_reg(struct cxd2880_io *io,
+						 enum cxd2880_io_tgt tgt,
+						 u8 sub_address, u8 data)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if (!io)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	ret = io->write_regs(io, tgt, sub_address, &data, 1);
+
+	return ret;
+}
+
+enum cxd2880_ret cxd2880_io_set_reg_bits(struct cxd2880_io *io,
+					 enum cxd2880_io_tgt tgt,
+					 u8 sub_address, u8 data, u8 mask)
+{
+	enum cxd2880_ret ret = CXD2880_RESULT_OK;
+
+	if (!io)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	if (mask == 0x00)
+		return CXD2880_RESULT_OK;
+
+	if (mask != 0xFF) {
+		u8 rdata = 0x00;
+
+		ret = io->read_regs(io, tgt, sub_address, &rdata, 1);
+		if (ret != CXD2880_RESULT_OK)
+			return ret;
+
+		data = (u8)((data & mask) | (rdata & (mask ^ 0xFF)));
+	}
+
+	ret = io->write_reg(io, tgt, sub_address, data);
+
+	return ret;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_io.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.h
new file mode 100644
index 000000000000..4d6db13cf910
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.h
@@ -0,0 +1,62 @@
+/*
+ * cxd2880_io.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * register I/O interface definitions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_IO_H
+#define CXD2880_IO_H
+
+#include "cxd2880_common.h"
+
+enum cxd2880_io_tgt {
+	CXD2880_IO_TGT_SYS,
+	CXD2880_IO_TGT_DMD
+};
+
+struct cxd2880_io {
+	enum cxd2880_ret (*read_regs)(struct cxd2880_io *io,
+				       enum cxd2880_io_tgt tgt, u8 sub_address,
+				       u8 *data, u32 size);
+	enum cxd2880_ret (*write_regs)(struct cxd2880_io *io,
+					enum cxd2880_io_tgt tgt, u8 sub_address,
+					const u8 *data, u32 size);
+	enum cxd2880_ret (*write_reg)(struct cxd2880_io *io,
+				       enum cxd2880_io_tgt tgt, u8 sub_address,
+				       u8 data);
+	void *if_object;
+	u8 i2c_address_sys;
+	u8 i2c_address_demod;
+	u8 slave_select;
+	void *user;
+};
+
+enum cxd2880_ret cxd2880_io_common_write_one_reg(struct cxd2880_io *io,
+						 enum cxd2880_io_tgt tgt,
+						 u8 sub_address, u8 data);
+
+enum cxd2880_ret cxd2880_io_set_reg_bits(struct cxd2880_io *io,
+					 enum cxd2880_io_tgt tgt,
+					 u8 sub_address, u8 data, u8 mask);
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_stdlib.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_stdlib.h
new file mode 100644
index 000000000000..b9ca1b9df110
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_stdlib.h
@@ -0,0 +1,35 @@
+/*
+ * cxd2880_stdlib.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * standard lib function aliases
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_STDLIB_H
+#define CXD2880_STDLIB_H
+
+#include <linux/string.h>
+
+#define cxd2880_memcpy  memcpy
+#define cxd2880_memset  memset
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c
new file mode 100644
index 000000000000..14ad6aa6c4c0
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c
@@ -0,0 +1,71 @@
+/*
+ * cxd2880_stopwatch_port.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * time measurement functions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_common.h"
+
+#include <linux/ktime.h>
+#include <linux/time.h>
+#include <linux/timekeeping.h>
+
+static u32 get_time_count(void)
+{
+	struct timespec tp;
+
+	getnstimeofday(&tp);
+
+	return (u32)((tp.tv_sec * 1000) + (tp.tv_nsec / 1000000));
+}
+
+enum cxd2880_ret cxd2880_stopwatch_start(struct cxd2880_stopwatch *stopwatch)
+{
+	if (!stopwatch)
+		return CXD2880_RESULT_ERROR_ARG;
+
+	stopwatch->start_time = get_time_count();
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_stopwatch_sleep(struct cxd2880_stopwatch *stopwatch,
+					 u32 ms)
+{
+	if (!stopwatch)
+		return CXD2880_RESULT_ERROR_ARG;
+	CXD2880_ARG_UNUSED(*stopwatch);
+	CXD2880_SLEEP(ms);
+
+	return CXD2880_RESULT_OK;
+}
+
+enum cxd2880_ret cxd2880_stopwatch_elapsed(struct cxd2880_stopwatch *stopwatch,
+					   u32 *elapsed)
+{
+	if (!stopwatch || !elapsed)
+		return CXD2880_RESULT_ERROR_ARG;
+	*elapsed = get_time_count() - stopwatch->start_time;
+
+	return CXD2880_RESULT_OK;
+}
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v2 02/15] [media] cxd2880-spi: Add support for CXD2008 SPI interface
From: Yasunari.Takiguchi-7U/KSKJipcs @ 2017-04-14  2:08 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA
  Cc: tbird20d-Re5JQEeQqe8AvxtiuMwx3w,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w, Yasunari Takiguchi,
	Masayuki Yamamoto, Hideki Nozawa, Kota Yonezawa,
	Toshihiko Matsumoto, Satoshi Watanabe
In-Reply-To: <20170414015043.16731-1-Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>

From: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>

This is the SPI adapter part of the driver for the
Sony CXD2880 DVB-T2/T tuner + demodulator.

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe-7U/KSKJipcs@public.gmane.org>
---
 drivers/media/spi/cxd2880-spi.c | 728 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 728 insertions(+)
 create mode 100644 drivers/media/spi/cxd2880-spi.c

diff --git a/drivers/media/spi/cxd2880-spi.c b/drivers/media/spi/cxd2880-spi.c
new file mode 100644
index 000000000000..82e122349055
--- /dev/null
+++ b/drivers/media/spi/cxd2880-spi.c
@@ -0,0 +1,728 @@
+/*
+ * cxd2880-spi.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * SPI adapter
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * 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; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/spi/spi.h>
+
+#include "dvb_demux.h"
+#include "dmxdev.h"
+#include "dvb_frontend.h"
+#include "cxd2880.h"
+
+#define CXD2880_MAX_FILTER_SIZE 32
+#define BURST_WRITE_MAX 128
+#define MAX_TRANS_PACKET 300
+
+struct cxd2880_ts_buf_info {
+	u8 read_ready;
+	u8 almost_full;
+	u8 almost_empty;
+	u8 overflow;
+	u8 underflow;
+	u16 packet_num;
+};
+
+struct cxd2880_pid_config {
+	u8 is_enable;
+	u16 pid;
+};
+
+struct cxd2880_pid_filter_config {
+	u8 is_negative;
+	struct cxd2880_pid_config pid_config[CXD2880_MAX_FILTER_SIZE];
+};
+
+struct cxd2880_dvb_spi {
+	struct dvb_frontend dvb_fe;
+	struct dvb_adapter adapter;
+	struct dvb_demux demux;
+	struct dmxdev dmxdev;
+	struct dmx_frontend dmx_fe;
+	struct task_struct *cxd2880_ts_read_thread;
+	struct spi_device *spi;
+	struct mutex spi_mutex; /* For SPI access exclusive control */
+	int feed_count;
+	int all_pid_feed_count;
+	u8 *ts_buf;
+	struct cxd2880_pid_filter_config filter_config;
+};
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int cxd2880_write_spi(struct spi_device *spi, u8 *data, u32 size)
+{
+	struct spi_message msg;
+	struct spi_transfer tx;
+	int ret = 0;
+
+	if ((!spi) || (!data)) {
+		pr_err("%s: invalid arg\n", __func__);
+		return -EINVAL;
+	}
+
+	memset(&tx, 0, sizeof(tx));
+	tx.tx_buf = data;
+	tx.len = size;
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&tx, &msg);
+	ret = spi_sync(spi, &msg);
+
+	return ret;
+}
+
+static int cxd2880_write_reg(struct spi_device *spi,
+				u8 subAddress, const u8 *data, u32 size)
+{
+	u8 send_data[BURST_WRITE_MAX + 4];
+	const u8 *write_data_top = NULL;
+	int ret = 0;
+
+	if ((!spi) || (!data)) {
+		pr_err("%s: invalid arg\n", __func__);
+		return -EINVAL;
+	}
+	if (size > BURST_WRITE_MAX) {
+		pr_err("%s: data size > WRITE_MAX\n", __func__);
+		return -EINVAL;
+	}
+
+	if (subAddress + size > 0x100) {
+		pr_err("%s: out of range\n", __func__);
+		return -EINVAL;
+	}
+
+	send_data[0] = 0x0E;
+	write_data_top = data;
+
+	while (size > 0) {
+		send_data[1] = subAddress;
+		if (size > 255)
+			send_data[2] = 255;
+		else
+			send_data[2] = (u8)size;
+
+		memcpy(&send_data[3], write_data_top, send_data[2]);
+
+		ret = cxd2880_write_spi(spi, send_data, send_data[2] + 3);
+		if (ret) {
+			dev_err(&spi->dev, "%s: write spi failed %d\n",
+				__func__, ret);
+			break;
+		}
+		subAddress += send_data[2];
+		write_data_top += send_data[2];
+		size -= send_data[2];
+	}
+
+	return ret;
+}
+
+static int cxd2880_spi_read_ts(struct spi_device *spi,
+					u8 *read_data,
+					u32 packet_num)
+{
+	int ret = 0;
+	u8 data[3];
+	struct spi_message message;
+	struct spi_transfer transfer[2];
+
+	if ((!spi) || (!read_data) || (!packet_num)) {
+		pr_err("%s: invalid arg\n", __func__);
+		return -EINVAL;
+	}
+	if (packet_num > 0xFFFF) {
+		dev_err(&spi->dev, "%s: packet num > 0xFFFF\n", __func__);
+		return -EINVAL;
+	}
+
+	data[0] = 0x10;
+	data[1] = (u8)((packet_num >> 8) & 0xFF);
+	data[2] = (u8)(packet_num & 0xFF);
+
+	spi_message_init(&message);
+	memset(transfer, 0, sizeof(transfer));
+
+	transfer[0].len = 3;
+	transfer[0].tx_buf = data;
+	spi_message_add_tail(&transfer[0], &message);
+	transfer[1].len = packet_num * 188;
+	transfer[1].rx_buf = read_data;
+	spi_message_add_tail(&transfer[1], &message);
+
+	ret = spi_sync(spi, &message);
+	if (ret)
+		dev_err(&spi->dev, "%s: spi_write_then_read failed\n",
+			__func__);
+
+	return ret;
+}
+
+static int cxd2880_spi_read_ts_buffer_info(struct spi_device *spi,
+					struct cxd2880_ts_buf_info *info)
+{
+	u8 send_data = 0x20;
+	u8 recv_data[2];
+	int ret = 0;
+
+	if ((!spi) || (!info)) {
+		pr_err("%s: invalid arg\n", __func__);
+		return -EINVAL;
+	}
+
+	ret = spi_write_then_read(spi, &send_data, 1,
+			recv_data, sizeof(recv_data));
+	if (ret)
+		dev_err(&spi->dev,
+			"%s: spi_write_then_read failed\n", __func__);
+
+	info->read_ready = (u8)((recv_data[0] & 0x80) ? 1 : 0);
+	info->almost_full = (u8)((recv_data[0] & 0x40) ? 1 : 0);
+	info->almost_empty = (u8)((recv_data[0] & 0x20) ? 1 : 0);
+	info->overflow = (u8)((recv_data[0] & 0x10) ? 1 : 0);
+	info->underflow = (u8)((recv_data[0] & 0x08) ? 1 : 0);
+	info->packet_num = (u16)(((recv_data[0] & 0x07) << 8) | recv_data[1]);
+
+	return ret;
+}
+
+static int cxd2880_spi_clear_ts_buffer(struct spi_device *spi)
+{
+	u8 data = 0x03;
+	int ret = 0;
+
+	ret = cxd2880_write_spi(spi, &data, 1);
+
+	if (ret)
+		pr_err("%s: write spi failed\n", __func__);
+
+	return ret;
+}
+
+static int cxd2880_set_pid_filter(struct spi_device *spi,
+				struct cxd2880_pid_filter_config *cfg)
+{
+	u8 data[65];
+
+	if (!spi) {
+		pr_err("%s: ivnalid arg\n", __func__);
+		return -EINVAL;
+	}
+
+	data[0] = 0x00;
+	if (cxd2880_write_reg(spi, 0x00, &data[0], 1) != 0)
+		return -EIO;
+	if (!cfg) {
+		data[0] = 0x02;
+		if (cxd2880_write_reg(spi, 0x50, &data[0], 1) != 0)
+			return -EIO;
+	} else {
+		data[0] = (u8)(cfg->is_negative ? 0x01 : 0x00);
+		{
+			int i = 0;
+			u16 pid = 0;
+
+			for (i = 0; i < CXD2880_MAX_FILTER_SIZE; i++) {
+				pid = cfg->pid_config[i].pid;
+				if (cfg->pid_config[i].is_enable) {
+					data[1 + (i * 2)] =
+					    (u8)((u8)(pid >> 8) | 0x20);
+					data[2 + (i * 2)] =
+					    (u8)(pid & 0xFF);
+				} else {
+					data[1 + (i * 2)] = 0x00;
+					data[2 + (i * 2)] = 0x00;
+				}
+			}
+		}
+		if (cxd2880_write_reg(spi, 0x50, data, 65) != 0)
+			return -EIO;
+	}
+
+	return 0;
+}
+
+static int cxd2880_update_pid_filter(struct cxd2880_dvb_spi *dvb_spi,
+				struct cxd2880_pid_filter_config *cfg,
+				bool is_all_pid_filter)
+{
+	int ret = 0;
+
+	if ((!dvb_spi) || (!cfg)) {
+		pr_err("%s: invalid arg.\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&dvb_spi->spi_mutex);
+	if (is_all_pid_filter) {
+		struct cxd2880_pid_filter_config tmpcfg;
+
+		memset(&tmpcfg, 0, sizeof(tmpcfg));
+		tmpcfg.is_negative = 1;
+		tmpcfg.pid_config[0].is_enable = 1;
+		tmpcfg.pid_config[0].pid = 0x1FFF;
+
+		ret = cxd2880_set_pid_filter(dvb_spi->spi, &tmpcfg);
+	} else {
+		ret = cxd2880_set_pid_filter(dvb_spi->spi, cfg);
+	}
+	mutex_unlock(&dvb_spi->spi_mutex);
+
+	if (ret) {
+		dev_err(&dvb_spi->spi->dev,
+			"%s: set_pid_filter failed\n", __func__);
+	}
+
+	return ret;
+}
+
+static int cxd2880_ts_read(void *arg)
+{
+	struct cxd2880_dvb_spi *dvb_spi = NULL;
+	struct cxd2880_ts_buf_info info;
+	struct timespec ts;
+	long elapsed = 0;
+	long starttime = 0;
+	u32 i;
+	int ret;
+
+	dvb_spi = (struct cxd2880_dvb_spi *)arg;
+	if (!dvb_spi) {
+		pr_err("%s: invalid arg\n", __func__);
+		return -EINVAL;
+	}
+
+	ret = cxd2880_spi_clear_ts_buffer(dvb_spi->spi);
+	if (ret) {
+		dev_err(&dvb_spi->spi->dev,
+			"%s: set_clear_ts_buffer failed\n", __func__);
+		return ret;
+	}
+
+	getnstimeofday(&ts);
+	starttime = (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000);
+	while (!kthread_should_stop()) {
+		getnstimeofday(&ts);
+		elapsed =
+			((ts.tv_sec * 1000) + (ts.tv_nsec / 1000000))
+			- starttime;
+		ret = cxd2880_spi_read_ts_buffer_info(dvb_spi->spi,
+							&info);
+		if (ret) {
+			pr_err("%s: spi_read_ts_buffer_info error\n",
+				__func__);
+			return ret;
+		}
+
+		if (info.packet_num > MAX_TRANS_PACKET) {
+			for (i = 0; i < info.packet_num / MAX_TRANS_PACKET;
+				i++) {
+				cxd2880_spi_read_ts(dvb_spi->spi,
+							dvb_spi->ts_buf,
+							MAX_TRANS_PACKET);
+				dvb_dmx_swfilter(&dvb_spi->demux,
+						dvb_spi->ts_buf,
+						MAX_TRANS_PACKET * 188);
+			}
+			starttime = (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000);
+		} else if ((info.packet_num > 0) && (elapsed >= 500)) {
+			cxd2880_spi_read_ts(dvb_spi->spi,
+						dvb_spi->ts_buf,
+						info.packet_num);
+			dvb_dmx_swfilter(&dvb_spi->demux,
+					dvb_spi->ts_buf,
+					info.packet_num * 188);
+			starttime = (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000);
+		} else {
+			usleep_range(10000, 11000);
+		}
+	}
+
+	return 0;
+}
+
+static int cxd2880_start_feed(struct dvb_demux_feed *feed)
+{
+	int ret = 0;
+	int i = 0;
+	struct dvb_demux *demux = NULL;
+	struct cxd2880_dvb_spi *dvb_spi = NULL;
+
+	if (!feed) {
+		pr_err("%s: invalid arg\n", __func__);
+		return -EINVAL;
+	}
+
+	demux = feed->demux;
+	if (!demux) {
+		pr_err("%s: feed->demux is NULL\n", __func__);
+		return -EINVAL;
+	}
+	dvb_spi = (struct cxd2880_dvb_spi *)demux->priv;
+
+	if (dvb_spi->feed_count == CXD2880_MAX_FILTER_SIZE) {
+		dev_err(&dvb_spi->spi->dev,
+			"%s: Exceeded maximum PID count (32).", __func__);
+		dev_err(&dvb_spi->spi->dev,
+			"Selected PID cannot be enabled.\n");
+		return -EBUSY;
+	}
+
+	if (feed->pid == 0x2000) {
+		if (dvb_spi->all_pid_feed_count == 0) {
+			ret = cxd2880_update_pid_filter(dvb_spi,
+							&dvb_spi->filter_config,
+							true);
+			if (ret) {
+				dev_err(&dvb_spi->spi->dev,
+					"%s: update pid filter failed\n",
+					__func__);
+				return ret;
+			}
+		}
+		dvb_spi->all_pid_feed_count++;
+
+		dev_dbg(&dvb_spi->spi->dev,
+			"%s: all PID feed (count = %d)\n",
+			__func__, dvb_spi->all_pid_feed_count);
+	} else {
+		struct cxd2880_pid_filter_config cfgtmp;
+
+		cfgtmp = dvb_spi->filter_config;
+
+		for (i = 0; i < CXD2880_MAX_FILTER_SIZE; i++) {
+			if (cfgtmp.pid_config[i].is_enable == 0) {
+				cfgtmp.pid_config[i].is_enable = 1;
+				cfgtmp.pid_config[i].pid = feed->pid;
+				dev_dbg(&dvb_spi->spi->dev,
+				"%s: store PID %d to #%d\n",
+				__func__, feed->pid, i);
+				break;
+			}
+		}
+		if (i == CXD2880_MAX_FILTER_SIZE) {
+			dev_err(&dvb_spi->spi->dev,
+				"%s: PID filter is full. Assumed bug.\n",
+				__func__);
+			return -EBUSY;
+		}
+		if (!dvb_spi->all_pid_feed_count)
+			ret = cxd2880_update_pid_filter(dvb_spi,
+							&cfgtmp,
+							false);
+		if (ret)
+			return ret;
+
+		dvb_spi->filter_config = cfgtmp;
+	}
+
+	if (dvb_spi->feed_count == 0) {
+		dvb_spi->ts_buf =
+			kmalloc(sizeof(u8) * MAX_TRANS_PACKET * 188,
+				GFP_KERNEL | GFP_DMA);
+		if (!dvb_spi->ts_buf) {
+			dev_err(&dvb_spi->spi->dev,
+			"%s: ts buffer allocate failed\n", __func__);
+			memset(&dvb_spi->filter_config, 0,
+				sizeof(dvb_spi->filter_config));
+			dvb_spi->all_pid_feed_count = 0;
+			return -ENOMEM;
+		}
+		dvb_spi->cxd2880_ts_read_thread = kthread_run(cxd2880_ts_read,
+								dvb_spi,
+								"cxd2880_ts_read");
+		if (IS_ERR(dvb_spi->cxd2880_ts_read_thread)) {
+			dev_err(&dvb_spi->spi->dev,
+				"%s: kthread_run failed/\n",
+				__func__);
+			kfree(dvb_spi->ts_buf);
+			dvb_spi->ts_buf = NULL;
+			memset(&dvb_spi->filter_config, 0,
+				sizeof(dvb_spi->filter_config));
+			dvb_spi->all_pid_feed_count = 0;
+			return PTR_ERR(dvb_spi->cxd2880_ts_read_thread);
+		}
+	}
+
+	dvb_spi->feed_count++;
+
+	dev_dbg(&dvb_spi->spi->dev, "%s: start feed (count %d)\n",
+		__func__, dvb_spi->feed_count);
+	return 0;
+}
+
+static int cxd2880_stop_feed(struct dvb_demux_feed *feed)
+{
+	int i = 0;
+	int ret = 0;
+	struct dvb_demux *demux = NULL;
+	struct cxd2880_dvb_spi *dvb_spi = NULL;
+
+	if (!feed) {
+		pr_err("%s: invalid arg\n", __func__);
+		return -EINVAL;
+	}
+
+	demux = feed->demux;
+	if (!demux) {
+		pr_err("%s: feed->demux is NULL\n", __func__);
+		return -EINVAL;
+	}
+	dvb_spi = (struct cxd2880_dvb_spi *)demux->priv;
+
+	if (!dvb_spi->feed_count) {
+		dev_warn(&dvb_spi->spi->dev,
+			"%s: no feed is started\n", __func__);
+		return -EINVAL;
+	}
+
+	if (feed->pid == 0x2000) {
+		/*
+		 * Special PID case.
+		 * Number of 0x2000 feed request was stored
+		 * in dvb_spi->all_pid_feed_count.
+		 */
+		if (dvb_spi->all_pid_feed_count <= 0) {
+			dev_warn(&dvb_spi->spi->dev,
+				"%s: PID %d not found.\n",
+				__func__, feed->pid);
+			return -EINVAL;
+		}
+		dvb_spi->all_pid_feed_count--;
+	} else {
+		struct cxd2880_pid_filter_config cfgtmp;
+
+		cfgtmp = dvb_spi->filter_config;
+
+		for (i = 0; i < CXD2880_MAX_FILTER_SIZE; i++) {
+			if (feed->pid == cfgtmp.pid_config[i].pid &&
+				cfgtmp.pid_config[i].is_enable != 0) {
+				cfgtmp.pid_config[i].is_enable = 0;
+				cfgtmp.pid_config[i].pid = 0;
+				dev_dbg(&dvb_spi->spi->dev,
+					"%s: removed PID %d from #%d\n",
+					__func__, feed->pid, i);
+				break;
+			}
+		}
+		dvb_spi->filter_config = cfgtmp;
+
+		if (i == CXD2880_MAX_FILTER_SIZE) {
+			dev_warn(&dvb_spi->spi->dev, "%s: PID %d not found\n",
+				__func__, feed->pid);
+			return -EINVAL;
+		}
+	}
+
+	ret = cxd2880_update_pid_filter(dvb_spi,
+					&dvb_spi->filter_config,
+					dvb_spi->all_pid_feed_count > 0);
+	dvb_spi->feed_count--;
+
+	if (dvb_spi->feed_count == 0) {
+		int ret_stop = 0;
+
+		ret_stop = kthread_stop(dvb_spi->cxd2880_ts_read_thread);
+		if (ret_stop) {
+			dev_err(&dvb_spi->spi->dev,
+			"%s: cxd2880_ts_read thread didn't terminate normally\n",
+			__func__);
+			ret = ret_stop;
+		}
+		kfree(dvb_spi->ts_buf);
+		dvb_spi->ts_buf = NULL;
+	}
+
+	dev_dbg(&dvb_spi->spi->dev, "%s: stop feed ok.(count %d)\n",
+		__func__, dvb_spi->feed_count);
+
+	return ret;
+}
+
+static const struct of_device_id cxd2880_spi_of_match[] = {
+	{ .compatible = "sony,cxd2880" },
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, cxd2880_spi_of_match);
+
+static int
+cxd2880_spi_probe(struct spi_device *spi)
+{
+	int ret = 0;
+	struct cxd2880_dvb_spi *dvb_spi = NULL;
+	struct cxd2880_config config;
+
+	if (!spi) {
+		pr_err("%s: invalid arg.\n", __func__);
+		return -EINVAL;
+	}
+
+	dvb_spi = kzalloc(sizeof(struct cxd2880_dvb_spi), GFP_KERNEL);
+	if (!dvb_spi)
+		return -ENOMEM;
+
+	dvb_spi->spi = spi;
+	mutex_init(&dvb_spi->spi_mutex);
+	dev_set_drvdata(&spi->dev, dvb_spi);
+	config.spi = spi;
+	config.spi_mutex = &dvb_spi->spi_mutex;
+
+	ret = dvb_register_adapter(&dvb_spi->adapter,
+					"CXD2880",
+					THIS_MODULE,
+					&spi->dev,
+					adapter_nr);
+	if (ret < 0) {
+		dev_err(&spi->dev, "%s: dvb_register_adapter() failed\n",
+			__func__);
+		goto fail_adapter;
+	}
+
+	if (!dvb_attach(cxd2880_attach, &dvb_spi->dvb_fe, &config)) {
+		dev_err(&spi->dev, "%s: cxd2880_attach failed\n", __func__);
+		goto fail_attach;
+	}
+
+	ret = dvb_register_frontend(&dvb_spi->adapter,
+					&dvb_spi->dvb_fe);
+	if (ret < 0) {
+		dev_err(&spi->dev, "%s: dvb_register_frontend() failed\n",
+			__func__);
+		goto fail_frontend;
+	}
+
+	dvb_spi->demux.dmx.capabilities = DMX_TS_FILTERING;
+	dvb_spi->demux.priv = dvb_spi;
+	dvb_spi->demux.filternum = CXD2880_MAX_FILTER_SIZE;
+	dvb_spi->demux.feednum = CXD2880_MAX_FILTER_SIZE;
+	dvb_spi->demux.start_feed = cxd2880_start_feed;
+	dvb_spi->demux.stop_feed = cxd2880_stop_feed;
+
+	ret = dvb_dmx_init(&dvb_spi->demux);
+	if (ret < 0) {
+		dev_err(&spi->dev, "%s: dvb_dmx_init() failed\n", __func__);
+		goto fail_dmx;
+	}
+
+	dvb_spi->dmxdev.filternum = CXD2880_MAX_FILTER_SIZE;
+	dvb_spi->dmxdev.demux = &dvb_spi->demux.dmx;
+	dvb_spi->dmxdev.capabilities = 0;
+	ret = dvb_dmxdev_init(&dvb_spi->dmxdev,
+				&dvb_spi->adapter);
+	if (ret < 0) {
+		dev_err(&spi->dev, "%s: dvb_dmxdev_init() failed\n", __func__);
+		goto fail_dmxdev;
+	}
+
+	dvb_spi->dmx_fe.source = DMX_FRONTEND_0;
+	ret = dvb_spi->demux.dmx.add_frontend(&dvb_spi->demux.dmx,
+						&dvb_spi->dmx_fe);
+	if (ret < 0) {
+		dev_err(&spi->dev, "%s: add_frontend() failed\n", __func__);
+		goto fail_dmx_fe;
+	}
+
+	ret = dvb_spi->demux.dmx.connect_frontend(&dvb_spi->demux.dmx,
+						&dvb_spi->dmx_fe);
+	if (ret < 0) {
+		dev_err(&spi->dev, "%s: dvb_register_frontend() failed\n",
+			__func__);
+		goto fail_fe_conn;
+	}
+
+	dev_info(&spi->dev, "Sony CXD2880 has successfully attached.\n");
+
+	return 0;
+
+fail_fe_conn:
+	dvb_spi->demux.dmx.remove_frontend(&dvb_spi->demux.dmx,
+			&dvb_spi->dmx_fe);
+fail_dmx_fe:
+	dvb_dmxdev_release(&dvb_spi->dmxdev);
+fail_dmxdev:
+	dvb_dmx_release(&dvb_spi->demux);
+fail_dmx:
+	dvb_unregister_frontend(&dvb_spi->dvb_fe);
+fail_frontend:
+	dvb_frontend_detach(&dvb_spi->dvb_fe);
+fail_attach:
+	dvb_unregister_adapter(&dvb_spi->adapter);
+fail_adapter:
+	kfree(dvb_spi);
+	return ret;
+}
+
+static int
+cxd2880_spi_remove(struct spi_device *spi)
+{
+	struct cxd2880_dvb_spi *dvb_spi;
+
+	if (!spi) {
+		pr_err("%s: invalid arg\n", __func__);
+		return -EINVAL;
+	}
+
+	dvb_spi = (struct cxd2880_dvb_spi *)dev_get_drvdata(&spi->dev);
+
+	if (!dvb_spi) {
+		pr_err("%s: failed\n", __func__);
+		return -EINVAL;
+	}
+	dvb_spi->demux.dmx.remove_frontend(&dvb_spi->demux.dmx,
+					&dvb_spi->dmx_fe);
+	dvb_dmxdev_release(&dvb_spi->dmxdev);
+	dvb_dmx_release(&dvb_spi->demux);
+	dvb_unregister_frontend(&dvb_spi->dvb_fe);
+	dvb_frontend_detach(&dvb_spi->dvb_fe);
+	dvb_unregister_adapter(&dvb_spi->adapter);
+
+	kfree(dvb_spi);
+	dev_info(&spi->dev, "%s: cxd2880_spi remove ok.\n", __func__);
+
+	return 0;
+}
+
+static const struct spi_device_id cxd2880_spi_id[] = {
+	{ "cxd2880", 0 },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(spi, cxd2880_spi_id);
+
+static struct spi_driver cxd2880_spi_driver = {
+	.driver	= {
+		.name	= "cxd2880",
+		.of_match_table = cxd2880_spi_of_match,
+	},
+	.id_table = cxd2880_spi_id,
+	.probe    = cxd2880_spi_probe,
+	.remove   = cxd2880_spi_remove,
+};
+module_spi_driver(cxd2880_spi_driver);
+
+MODULE_DESCRIPTION(
+"Sony CXD2880 DVB-T2/T tuner + demodulator drvier SPI adapter");
+MODULE_AUTHOR("Sony Semiconductor Solutions Corporation");
+MODULE_LICENSE("GPL v2");
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v2 01/15] [dt-bindings] [media] Add document file for CXD2880 SPI I/F
From: Yasunari.Takiguchi-7U/KSKJipcs @ 2017-04-14  2:00 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA
  Cc: tbird20d-Re5JQEeQqe8AvxtiuMwx3w,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w, Yasunari Takiguchi,
	Masayuki Yamamoto, Hideki Nozawa, Kota Yonezawa,
	Toshihiko Matsumoto, Satoshi Watanabe
In-Reply-To: <20170414015043.16731-1-Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>

From: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>

This is the document file for Sony CXD2880 DVB-T2/T tuner + demodulator.
It contains the description of the SPI adapter binding.

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe-7U/KSKJipcs@public.gmane.org>
---
 .../devicetree/bindings/media/spi/sony-cxd2880.txt         | 14 ++++++++++++++
 1 file changed, 14 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/spi/sony-cxd2880.txt

diff --git a/Documentation/devicetree/bindings/media/spi/sony-cxd2880.txt b/Documentation/devicetree/bindings/media/spi/sony-cxd2880.txt
new file mode 100644
index 000000000000..fc5aa263abe5
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/spi/sony-cxd2880.txt
@@ -0,0 +1,14 @@
+Sony CXD2880 DVB-T2/T tuner + demodulator driver SPI adapter
+
+Required properties:
+- compatible: Should be "sony,cxd2880".
+- reg: SPI chip select number for the device.
+- spi-max-frequency: Maximum bus speed, should be set to <55000000> (55MHz).
+
+Example:
+
+cxd2880@0 {
+	compatible = "sony,cxd2880";
+	reg = <0>; /* CE0 */
+	spi-max-frequency = <55000000>; /* 55MHz */
+};
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v2 0/15] [dt-bindings] [media] Add document file and driver for Sony CXD2880 DVB-T2/T tuner + demodulator
From: Yasunari.Takiguchi @ 2017-04-14  1:50 UTC (permalink / raw)
  To: akpm, linux-kernel, devicetree, linux-media
  Cc: tbird20d, frowand.list, Yasunari Takiguchi

From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

Hi,

This is the patch series (version 2) of Sony CXD2880 DVB-T2/T tuner + demodulator driver.
The driver supports DVB-API and interfaces through SPI.

We have tested the driver on Raspberry Pi 3 and got picture and sound from a media player.

Thanks,
Takiguchi
---
 Documentation/devicetree/bindings/media/spi/sony-cxd2880.txt        |   14 ++++++++++++++
 drivers/media/spi/cxd2880-spi.c                                     | 728 ++++++++++++++++++++++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880.h                       |   46 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_common.c                |   84 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_common.h                |   86 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_io.c                    |   68 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_io.h                    |   62 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_stdlib.h                |   35 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c        |   71 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_math.c                  |   89 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_math.h                  |   40 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c             |  147 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h             |   40 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h                   |   51 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c            |  130 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h            |   45 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h                   |   50 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c                | 3925 ++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h                |  395 ++
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h |   29 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c            |  207 ++
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h            |   52 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c                 |   99 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h                 |   44 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_top.c                   | 1550 ++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h                  |   91 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c           | 1072 +++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h           |   62 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c            |  197 ++
 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h            |   58 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c       | 1190 +++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h       |  106 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h                 |  402 ++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c          | 1309 ++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h          |   82 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c           |  311 +++
 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h           |   64 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c      | 2523 ++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h      |  170 ++
 drivers/media/dvb-frontends/Makefile                                |    1 +
 drivers/media/dvb-frontends/cxd2880/Makefile                        |   21 +++++++++++++++++++++
 drivers/media/spi/Makefile                                          |    5 +++++
 drivers/media/dvb-frontends/Kconfig                                 |    2 ++
 drivers/media/dvb-frontends/cxd2880/Kconfig                         |    6 ++++++
 drivers/media/spi/Kconfig                                           |   14 ++++++++++++++
 MAINTAINERS                                                         |    9 +++++++++

 46 files changed, 15782 insertions(+)

 create mode 100644 Documentation/devicetree/bindings/media/spi/sony-cxd2880.txt
 create mode 100644 drivers/media/spi/cxd2880-spi.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_common.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_common.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_io.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_io.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_stdlib.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_math.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_math.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/Makefile
 create mode 100644 drivers/media/dvb-frontends/cxd2880/Kconfig
-- 
2.11.0

^ permalink raw reply

* Re: [RFC 2/2] mux: mmio-based syscon mux controller
From: Steve Longerbeam @ 2017-04-14  1:09 UTC (permalink / raw)
  To: Philipp Zabel, Peter Rosin
  Cc: Rob Herring, Mark Rutland, Sakari Ailus, devicetree, linux-kernel,
	kernel
In-Reply-To: <20170413154812.19597-2-p.zabel@pengutronix.de>



On 04/13/2017 08:48 AM, Philipp Zabel wrote:
> This adds a driver for mmio-based syscon multiplexers controlled by a
> single bitfield in a syscon register range.
>
> Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
> ---
>   drivers/mux/Kconfig      |  13 +++++
>   drivers/mux/Makefile     |   1 +
>   drivers/mux/mux-syscon.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++
>   3 files changed, 144 insertions(+)
>   create mode 100644 drivers/mux/mux-syscon.c
>
> diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
> index 86668b4d2fc52..a5e6a3b01ac24 100644
> --- a/drivers/mux/Kconfig
> +++ b/drivers/mux/Kconfig
> @@ -43,4 +43,17 @@ config MUX_GPIO
>   	  To compile the driver as a module, choose M here: the module will
>   	  be called mux-gpio.
>   
> +config MUX_SYSCON

my preference would be CONFIG_MUX_MMIO.

> +	tristate "MMIO bitfield-controlled Multiplexer"

"MMIO register bitfield-controlled Multiplexer"

The rest looks good to me.

Steve

> +	depends on OF && MFD_SYSCON
> +	help
> +	  MMIO bitfield-controlled Multiplexer controller.
> +
> +	  The driver builds a single multiplexer controller using a bitfield
> +	  in a syscon register. For N bit wide bitfields, there will be 2^N
> +	  possible multiplexer states.
> +
> +	  To compile the driver as a module, choose M here: the module will
> +	  be called mux-syscon.
> +
>   endif
> diff --git a/drivers/mux/Makefile b/drivers/mux/Makefile
> index b00a7d37d2fbe..234309f6655f7 100644
> --- a/drivers/mux/Makefile
> +++ b/drivers/mux/Makefile
> @@ -5,3 +5,4 @@
>   obj-$(CONFIG_MULTIPLEXER)	+= mux-core.o
>   obj-$(CONFIG_MUX_ADG792A)	+= mux-adg792a.o
>   obj-$(CONFIG_MUX_GPIO)		+= mux-gpio.o
> +obj-$(CONFIG_MUX_SYSCON)	+= mux-syscon.o
> diff --git a/drivers/mux/mux-syscon.c b/drivers/mux/mux-syscon.c
> new file mode 100644
> index 0000000000000..31cacc61f1439
> --- /dev/null
> +++ b/drivers/mux/mux-syscon.c
> @@ -0,0 +1,130 @@
> +/*
> + * syscon bitfield-controlled multiplexer driver
> + *
> + * Copyright (C) 2017 Pengutronix, Philipp Zabel <kernel@pengutronix.de>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/mux.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_device.h>
> +#include <linux/property.h>
> +#include <linux/regmap.h>
> +
> +struct mux_syscon {
> +	struct regmap_field *field;
> +};
> +
> +static int mux_syscon_set(struct mux_control *mux, int state)
> +{
> +	struct mux_syscon *mux_syscon = mux_chip_priv(mux->chip);
> +
> +	return regmap_field_write(mux_syscon->field, state);
> +}
> +
> +static const struct mux_control_ops mux_syscon_ops = {
> +	.set = mux_syscon_set,
> +};
> +
> +static const struct of_device_id mux_syscon_dt_ids[] = {
> +	{ .compatible = "mmio-mux", },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, mux_syscon_dt_ids);
> +
> +static int of_get_reg_field(struct device_node *node, struct reg_field *field)
> +{
> +	u32 bit_mask;
> +	int ret;
> +
> +	ret = of_property_read_u32(node, "reg", &field->reg);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = of_property_read_u32(node, "bit-mask", &bit_mask);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = of_property_read_u32(node, "bit-shift", &field->lsb);
> +	if (ret < 0)
> +		return ret;
> +
> +	field->msb = field->lsb + fls(bit_mask) - 1;
> +
> +	return 0;
> +}
> +
> +static int mux_syscon_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct mux_chip *mux_chip;
> +	struct mux_syscon *mux_syscon;
> +	struct regmap *regmap;
> +	struct reg_field field;
> +	int bits;
> +	s32 idle_state;
> +	int ret;
> +
> +	ret = of_get_reg_field(pdev->dev.of_node, &field);
> +	if (ret) {
> +		dev_err(&pdev->dev, "missing bit-field properties: %d\n", ret);
> +		return ret;
> +	}
> +
> +	regmap = syscon_node_to_regmap(pdev->dev.of_node->parent);
> +	if (IS_ERR(regmap)) {
> +		ret = PTR_ERR(regmap);
> +		dev_err(&pdev->dev, "failed to get syscon regmap: %d\n", ret);
> +		return ret;
> +	}
> +
> +	mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*mux_syscon));
> +	if (!mux_chip)
> +		return -ENOMEM;
> +
> +	mux_syscon = mux_chip_priv(mux_chip);
> +	mux_chip->ops = &mux_syscon_ops;
> +
> +	mux_syscon->field = devm_regmap_field_alloc(&pdev->dev, regmap, field);
> +	if (IS_ERR(mux_syscon->field)) {
> +		ret = PTR_ERR(mux_syscon->field);
> +		dev_err(&pdev->dev, "failed to regmap bit-field: %d\n", ret);
> +		return ret;
> +	}
> +	bits = 1 + field.msb - field.lsb;
> +
> +	mux_chip->mux->states = 1 << bits;
> +
> +	ret = device_property_read_u32(dev, "idle-state", (u32 *)&idle_state);
> +	if (ret >= 0 && idle_state != MUX_IDLE_AS_IS) {
> +		if (idle_state < 0 || idle_state >= mux_chip->mux->states) {
> +			dev_err(dev, "invalid idle-state %u\n", idle_state);
> +			return -EINVAL;
> +		}
> +
> +		mux_chip->mux->idle_state = idle_state;
> +	}
> +
> +	regmap_field_read(mux_syscon->field, &mux_chip->mux->cached_state);
> +
> +	return devm_mux_chip_register(dev, mux_chip);
> +}
> +
> +static struct platform_driver mux_syscon_driver = {
> +	.driver = {
> +		.name = "mmio-mux",
> +		.of_match_table	= of_match_ptr(mux_syscon_dt_ids),
> +	},
> +	.probe = mux_syscon_probe,
> +};
> +module_platform_driver(mux_syscon_driver);
> +
> +MODULE_DESCRIPTION("MMIO bitfield-controlled multiplexer driver");
> +MODULE_AUTHOR("Philipp Zabel <p.zabel@pengutronix.de>");
> +MODULE_LICENSE("GPL v2");

^ permalink raw reply

* [PATCH v3 21/21] powerpc/44x: Add generic compatible string for I2C EEPROM
From: Javier Martinez Canillas @ 2017-04-14  1:04 UTC (permalink / raw)
  To: linux-kernel
  Cc: Wolfram Sang, Javier Martinez Canillas, devicetree,
	Michael Ellerman, Benjamin Herrenschmidt, Paul Mackerras,
	Rob Herring, Mark Rutland, linuxppc-dev
In-Reply-To: <20170414010445.21727-1-javier@osg.samsung.com>

The at24 driver allows to register I2C EEPROM chips using different vendor
and devices, but the I2C subsystem does not take the vendor into account
when matching using the I2C table since it only has device entries.

But when matching using an OF table, both the vendor and device has to be
taken into account so the driver defines only a set of compatible strings
using the "atmel" vendor as a generic fallback for compatible I2C devices.

So add this generic fallback to the device node compatible string to make
the device to match the driver using the OF device ID table.

Signed-off-by: Javier Martinez Canillas <javier@osg.samsung.com>

---

Changes in v3: None
Changes in v2: None

 arch/powerpc/boot/dts/warp.dts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/powerpc/boot/dts/warp.dts b/arch/powerpc/boot/dts/warp.dts
index e576ee85c42f..19e0ec83b1a5 100644
--- a/arch/powerpc/boot/dts/warp.dts
+++ b/arch/powerpc/boot/dts/warp.dts
@@ -238,7 +238,7 @@
 
 				/* This will create 52 and 53 */
 				at24@52 {
-					compatible = "at,24c04";
+					compatible = "at,24c04", "atmel,24c04";
 					reg = <0x52>;
 				};
 			};
-- 
2.9.3

^ permalink raw reply related

* [PATCH v3 20/21] powerpc/83xx: Add generic compatible string for I2C EEPROM
From: Javier Martinez Canillas @ 2017-04-14  1:04 UTC (permalink / raw)
  To: linux-kernel
  Cc: Wolfram Sang, Javier Martinez Canillas, devicetree,
	Michael Ellerman, Benjamin Herrenschmidt, Paul Mackerras,
	Rob Herring, Mark Rutland, linuxppc-dev
In-Reply-To: <20170414010445.21727-1-javier@osg.samsung.com>

The at24 driver allows to register I2C EEPROM chips using different vendor
and devices, but the I2C subsystem does not take the vendor into account
when matching using the I2C table since it only has device entries.

But when matching using an OF table, both the vendor and device has to be
taken into account so the driver defines only a set of compatible strings
using the "atmel" vendor as a generic fallback for compatible I2C devices.

So add this generic fallback to the device node compatible string to make
the device to match the driver using the OF device ID table.

Signed-off-by: Javier Martinez Canillas <javier@osg.samsung.com>
---

Changes in v3: None
Changes in v2: None

 arch/powerpc/boot/dts/mpc8308_p1m.dts  | 2 +-
 arch/powerpc/boot/dts/mpc8349emitx.dts | 2 +-
 arch/powerpc/boot/dts/mpc8377_rdb.dts  | 2 +-
 arch/powerpc/boot/dts/mpc8377_wlan.dts | 2 +-
 arch/powerpc/boot/dts/mpc8378_rdb.dts  | 2 +-
 arch/powerpc/boot/dts/mpc8379_rdb.dts  | 2 +-
 6 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/arch/powerpc/boot/dts/mpc8308_p1m.dts b/arch/powerpc/boot/dts/mpc8308_p1m.dts
index 57f86cdf9f36..cab933b3957a 100644
--- a/arch/powerpc/boot/dts/mpc8308_p1m.dts
+++ b/arch/powerpc/boot/dts/mpc8308_p1m.dts
@@ -123,7 +123,7 @@
 			interrupt-parent = <&ipic>;
 			dfsrr;
 			fram@50 {
-				compatible = "ramtron,24c64";
+				compatible = "ramtron,24c64", "atmel,24c64";
 				reg = <0x50>;
 			};
 		};
diff --git a/arch/powerpc/boot/dts/mpc8349emitx.dts b/arch/powerpc/boot/dts/mpc8349emitx.dts
index 90aed3ac2f69..00c5ef08e474 100644
--- a/arch/powerpc/boot/dts/mpc8349emitx.dts
+++ b/arch/powerpc/boot/dts/mpc8349emitx.dts
@@ -92,7 +92,7 @@
 			dfsrr;
 
 			eeprom: at24@50 {
-				compatible = "st,24c256";
+				compatible = "st,24c256", "atmel,24c256";
 				reg = <0x50>;
 			};
 
diff --git a/arch/powerpc/boot/dts/mpc8377_rdb.dts b/arch/powerpc/boot/dts/mpc8377_rdb.dts
index e32613963ab0..02c59d05fe16 100644
--- a/arch/powerpc/boot/dts/mpc8377_rdb.dts
+++ b/arch/powerpc/boot/dts/mpc8377_rdb.dts
@@ -150,7 +150,7 @@
 				};
 
 				at24@50 {
-					compatible = "at24,24c256";
+					compatible = "at24,24c256", "atmel,24c256";
 					reg = <0x50>;
 				};
 
diff --git a/arch/powerpc/boot/dts/mpc8377_wlan.dts b/arch/powerpc/boot/dts/mpc8377_wlan.dts
index c0c790168b96..2bc3ed8a18c3 100644
--- a/arch/powerpc/boot/dts/mpc8377_wlan.dts
+++ b/arch/powerpc/boot/dts/mpc8377_wlan.dts
@@ -135,7 +135,7 @@
 				dfsrr;
 
 				at24@50 {
-					compatible = "at24,24c256";
+					compatible = "at24,24c256", "atmel,24c256";
 					reg = <0x50>;
 				};
 
diff --git a/arch/powerpc/boot/dts/mpc8378_rdb.dts b/arch/powerpc/boot/dts/mpc8378_rdb.dts
index 71842fcd621f..9e681e3d6064 100644
--- a/arch/powerpc/boot/dts/mpc8378_rdb.dts
+++ b/arch/powerpc/boot/dts/mpc8378_rdb.dts
@@ -150,7 +150,7 @@
 				};
 
 				at24@50 {
-					compatible = "at24,24c256";
+					compatible = "at24,24c256", "atmel,24c256";
 					reg = <0x50>;
 				};
 
diff --git a/arch/powerpc/boot/dts/mpc8379_rdb.dts b/arch/powerpc/boot/dts/mpc8379_rdb.dts
index e442a29b2fe0..3197bb78e19b 100644
--- a/arch/powerpc/boot/dts/mpc8379_rdb.dts
+++ b/arch/powerpc/boot/dts/mpc8379_rdb.dts
@@ -148,7 +148,7 @@
 				};
 
 				at24@50 {
-					compatible = "at24,24c256";
+					compatible = "at24,24c256", "atmel,24c256";
 					reg = <0x50>;
 				};
 
-- 
2.9.3

^ permalink raw reply related

* [PATCH v3 19/21] powerpc/512x: Add generic compatible string for I2C EEPROM
From: Javier Martinez Canillas @ 2017-04-14  1:04 UTC (permalink / raw)
  To: linux-kernel
  Cc: Wolfram Sang, Javier Martinez Canillas, devicetree,
	Michael Ellerman, Benjamin Herrenschmidt, Paul Mackerras,
	Rob Herring, Mark Rutland, linuxppc-dev
In-Reply-To: <20170414010445.21727-1-javier@osg.samsung.com>

The at24 driver allows to register I2C EEPROM chips using different vendor
and devices, but the I2C subsystem does not take the vendor into account
when matching using the I2C table since it only has device entries.

But when matching using an OF table, both the vendor and device has to be
taken into account so the driver defines only a set of compatible strings
using the "atmel" vendor as a generic fallback for compatible I2C devices.

So add this generic fallback to the device node compatible string to make
the device to match the driver using the OF device ID table.

Signed-off-by: Javier Martinez Canillas <javier@osg.samsung.com>
---

Changes in v3: None
Changes in v2: None

 arch/powerpc/boot/dts/mpc5121ads.dts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/powerpc/boot/dts/mpc5121ads.dts b/arch/powerpc/boot/dts/mpc5121ads.dts
index 75888ce2c792..ece5d60256ee 100644
--- a/arch/powerpc/boot/dts/mpc5121ads.dts
+++ b/arch/powerpc/boot/dts/mpc5121ads.dts
@@ -94,7 +94,7 @@
 			};
 
 			eeprom@50 {
-				compatible = "at,24c32";
+				compatible = "at,24c32", "atmel,24c32";
 				reg = <0x50>;
 			};
 
-- 
2.9.3

^ permalink raw reply related

* [PATCH v3 18/21] powerpc/fsl: Add generic compatible string for I2C EEPROM
From: Javier Martinez Canillas @ 2017-04-14  1:04 UTC (permalink / raw)
  To: linux-kernel
  Cc: Wolfram Sang, Javier Martinez Canillas, devicetree,
	Florian Larysch, Michael Ellerman, Scott Wood,
	Benjamin Herrenschmidt, Paul Mackerras, Rob Herring, Mark Rutland,
	linuxppc-dev
In-Reply-To: <20170414010445.21727-1-javier@osg.samsung.com>

The at24 driver allows to register I2C EEPROM chips using different vendor
and devices, but the I2C subsystem does not take the vendor into account
when matching using the I2C table since it only has device entries.

But when matching using an OF table, both the vendor and device has to be
taken into account so the driver defines only a set of compatible strings
using the "atmel" vendor as a generic fallback for compatible I2C devices.

So add this generic fallback to the device node compatible string to make
the device to match the driver using the OF device ID table.

Signed-off-by: Javier Martinez Canillas <javier@osg.samsung.com>
---

Changes in v3: None
Changes in v2: None

 arch/powerpc/boot/dts/fsl/b4qds.dtsi    |  8 ++++----
 arch/powerpc/boot/dts/fsl/c293pcie.dts  |  2 +-
 arch/powerpc/boot/dts/fsl/p1010rdb.dtsi |  2 +-
 arch/powerpc/boot/dts/fsl/p1023rdb.dts  |  2 +-
 arch/powerpc/boot/dts/fsl/p2041rdb.dts  |  4 ++--
 arch/powerpc/boot/dts/fsl/p3041ds.dts   |  4 ++--
 arch/powerpc/boot/dts/fsl/p4080ds.dts   |  4 ++--
 arch/powerpc/boot/dts/fsl/p5020ds.dts   |  4 ++--
 arch/powerpc/boot/dts/fsl/p5040ds.dts   |  4 ++--
 arch/powerpc/boot/dts/fsl/t208xqds.dtsi |  8 ++++----
 arch/powerpc/boot/dts/fsl/t4240qds.dts  | 12 ++++++------
 arch/powerpc/boot/dts/fsl/t4240rdb.dts  |  6 +++---
 12 files changed, 30 insertions(+), 30 deletions(-)

diff --git a/arch/powerpc/boot/dts/fsl/b4qds.dtsi b/arch/powerpc/boot/dts/fsl/b4qds.dtsi
index 3785ef826d07..18053d59be01 100644
--- a/arch/powerpc/boot/dts/fsl/b4qds.dtsi
+++ b/arch/powerpc/boot/dts/fsl/b4qds.dtsi
@@ -166,19 +166,19 @@
 					reg = <0>;
 
 					eeprom@50 {
-						compatible = "at24,24c64";
+						compatible = "at24,24c64", "atmel,24c64";
 						reg = <0x50>;
 					};
 					eeprom@51 {
-						compatible = "at24,24c256";
+						compatible = "at24,24c256", "atmel,24c256";
 						reg = <0x51>;
 					};
 					eeprom@53 {
-						compatible = "at24,24c256";
+						compatible = "at24,24c256", "atmel,24c256";
 						reg = <0x53>;
 					};
 					eeprom@57 {
-						compatible = "at24,24c256";
+						compatible = "at24,24c256", "atmel,24c256";
 						reg = <0x57>;
 					};
 					rtc@68 {
diff --git a/arch/powerpc/boot/dts/fsl/c293pcie.dts b/arch/powerpc/boot/dts/fsl/c293pcie.dts
index 66709788429d..5e905e0857cf 100644
--- a/arch/powerpc/boot/dts/fsl/c293pcie.dts
+++ b/arch/powerpc/boot/dts/fsl/c293pcie.dts
@@ -153,7 +153,7 @@
 &soc {
 	i2c@3000 {
 		eeprom@50 {
-			compatible = "st,24c1024";
+			compatible = "st,24c1024", "atmel,24c1024";
 			reg = <0x50>;
 		};
 
diff --git a/arch/powerpc/boot/dts/fsl/p1010rdb.dtsi b/arch/powerpc/boot/dts/fsl/p1010rdb.dtsi
index a8e4ba070104..2ca9cee2ddeb 100644
--- a/arch/powerpc/boot/dts/fsl/p1010rdb.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p1010rdb.dtsi
@@ -89,7 +89,7 @@
 &board_soc {
 	i2c@3000 {
 		eeprom@50 {
-			compatible = "st,24c256";
+			compatible = "st,24c256", "atmel,24c256";
 			reg = <0x50>;
 		};
 
diff --git a/arch/powerpc/boot/dts/fsl/p1023rdb.dts b/arch/powerpc/boot/dts/fsl/p1023rdb.dts
index 9716ca64651c..ae38ed66a7a4 100644
--- a/arch/powerpc/boot/dts/fsl/p1023rdb.dts
+++ b/arch/powerpc/boot/dts/fsl/p1023rdb.dts
@@ -79,7 +79,7 @@
 
 		i2c@3000 {
 			eeprom@53 {
-				compatible = "at24,24c04";
+				compatible = "at24,24c04", "atmel,24c04";
 				reg = <0x53>;
 			};
 
diff --git a/arch/powerpc/boot/dts/fsl/p2041rdb.dts b/arch/powerpc/boot/dts/fsl/p2041rdb.dts
index e50fea95a853..0c34e8c46961 100644
--- a/arch/powerpc/boot/dts/fsl/p2041rdb.dts
+++ b/arch/powerpc/boot/dts/fsl/p2041rdb.dts
@@ -127,7 +127,7 @@
 				reg = <0x48>;
 			};
 			eeprom@50 {
-				compatible = "at24,24c256";
+				compatible = "at24,24c256", "atmel,24c256";
 				reg = <0x50>;
 			};
 			rtc@68 {
@@ -142,7 +142,7 @@
 
 		i2c@118100 {
 			eeprom@50 {
-				compatible = "at24,24c256";
+				compatible = "at24,24c256", "atmel,24c256";
 				reg = <0x50>;
 			};
 		};
diff --git a/arch/powerpc/boot/dts/fsl/p3041ds.dts b/arch/powerpc/boot/dts/fsl/p3041ds.dts
index 40748e415adb..383656b73e61 100644
--- a/arch/powerpc/boot/dts/fsl/p3041ds.dts
+++ b/arch/powerpc/boot/dts/fsl/p3041ds.dts
@@ -124,11 +124,11 @@
 
 		i2c@118100 {
 			eeprom@51 {
-				compatible = "at24,24c256";
+				compatible = "at24,24c256", "atmel,24c256";
 				reg = <0x51>;
 			};
 			eeprom@52 {
-				compatible = "at24,24c256";
+				compatible = "at24,24c256", "atmel,24c256";
 				reg = <0x52>;
 			};
 		};
diff --git a/arch/powerpc/boot/dts/fsl/p4080ds.dts b/arch/powerpc/boot/dts/fsl/p4080ds.dts
index 816b9788d5f6..9ca8d7cf8d48 100644
--- a/arch/powerpc/boot/dts/fsl/p4080ds.dts
+++ b/arch/powerpc/boot/dts/fsl/p4080ds.dts
@@ -125,11 +125,11 @@
 
 		i2c@118100 {
 			eeprom@51 {
-				compatible = "at24,24c256";
+				compatible = "at24,24c256", "atmel,24c256";
 				reg = <0x51>;
 			};
 			eeprom@52 {
-				compatible = "at24,24c256";
+				compatible = "at24,24c256", "atmel,24c256";
 				reg = <0x52>;
 			};
 			rtc@68 {
diff --git a/arch/powerpc/boot/dts/fsl/p5020ds.dts b/arch/powerpc/boot/dts/fsl/p5020ds.dts
index cd6f37386111..4e6eab62f747 100644
--- a/arch/powerpc/boot/dts/fsl/p5020ds.dts
+++ b/arch/powerpc/boot/dts/fsl/p5020ds.dts
@@ -124,11 +124,11 @@
 
 		i2c@118100 {
 			eeprom@51 {
-				compatible = "at24,24c256";
+				compatible = "at24,24c256", "atmel,24c256";
 				reg = <0x51>;
 			};
 			eeprom@52 {
-				compatible = "at24,24c256";
+				compatible = "at24,24c256", "atmel,24c256";
 				reg = <0x52>;
 			};
 		};
diff --git a/arch/powerpc/boot/dts/fsl/p5040ds.dts b/arch/powerpc/boot/dts/fsl/p5040ds.dts
index 45084738cf4e..d164e731146e 100644
--- a/arch/powerpc/boot/dts/fsl/p5040ds.dts
+++ b/arch/powerpc/boot/dts/fsl/p5040ds.dts
@@ -133,11 +133,11 @@
 
 		i2c@118100 {
 			eeprom@51 {
-				compatible = "at24,24c256";
+				compatible = "at24,24c256", "atmel,24c256";
 				reg = <0x51>;
 			};
 			eeprom@52 {
-				compatible = "at24,24c256";
+				compatible = "at24,24c256", "atmel,24c256";
 				reg = <0x52>;
 			};
 		};
diff --git a/arch/powerpc/boot/dts/fsl/t208xqds.dtsi b/arch/powerpc/boot/dts/fsl/t208xqds.dtsi
index ec080bd01b09..780103e3eaae 100644
--- a/arch/powerpc/boot/dts/fsl/t208xqds.dtsi
+++ b/arch/powerpc/boot/dts/fsl/t208xqds.dtsi
@@ -147,17 +147,17 @@
 					reg = <0x0>;
 
 					eeprom@50 {
-						compatible = "at24,24c512";
+						compatible = "at24,24c512", "atmel,24c512";
 						reg = <0x50>;
 					};
 
 					eeprom@51 {
-						compatible = "at24,24c02";
+						compatible = "at24,24c02", "atmel,24c02";
 						reg = <0x51>;
 					};
 
 					eeprom@57 {
-						compatible = "at24,24c02";
+						compatible = "at24,24c02", "atmel,24c02";
 						reg = <0x57>;
 					};
 
@@ -174,7 +174,7 @@
 					reg = <0x1>;
 
 					eeprom@55 {
-						compatible = "at24,24c02";
+						compatible = "at24,24c02", "atmel,24c02";
 						reg = <0x55>;
 					};
 				};
diff --git a/arch/powerpc/boot/dts/fsl/t4240qds.dts b/arch/powerpc/boot/dts/fsl/t4240qds.dts
index 9573ceada07c..9f01bcfad699 100644
--- a/arch/powerpc/boot/dts/fsl/t4240qds.dts
+++ b/arch/powerpc/boot/dts/fsl/t4240qds.dts
@@ -377,27 +377,27 @@
 					reg = <0>;
 
 					eeprom@51 {
-						compatible = "at24,24c256";
+						compatible = "at24,24c256", "atmel,24c256";
 						reg = <0x51>;
 					};
 					eeprom@52 {
-						compatible = "at24,24c256";
+						compatible = "at24,24c256", "atmel,24c256";
 						reg = <0x52>;
 					};
 					eeprom@53 {
-						compatible = "at24,24c256";
+						compatible = "at24,24c256", "atmel,24c256";
 						reg = <0x53>;
 					};
 					eeprom@54 {
-						compatible = "at24,24c256";
+						compatible = "at24,24c256", "atmel,24c256";
 						reg = <0x54>;
 					};
 					eeprom@55 {
-						compatible = "at24,24c256";
+						compatible = "at24,24c256", "atmel,24c256";
 						reg = <0x55>;
 					};
 					eeprom@56 {
-						compatible = "at24,24c256";
+						compatible = "at24,24c256", "atmel,24c256";
 						reg = <0x56>;
 					};
 					rtc@68 {
diff --git a/arch/powerpc/boot/dts/fsl/t4240rdb.dts b/arch/powerpc/boot/dts/fsl/t4240rdb.dts
index 8166c660712a..9fb192e36bf0 100644
--- a/arch/powerpc/boot/dts/fsl/t4240rdb.dts
+++ b/arch/powerpc/boot/dts/fsl/t4240rdb.dts
@@ -130,15 +130,15 @@
 				reg = <0x2f>;
 			};
 			eeprom@52 {
-				compatible = "at24,24c256";
+				compatible = "at24,24c256", "atmel,24c256";
 				reg = <0x52>;
 			};
 			eeprom@54 {
-				compatible = "at24,24c256";
+				compatible = "at24,24c256", "atmel,24c256";
 				reg = <0x54>;
 			};
 			eeprom@56 {
-				compatible = "at24,24c256";
+				compatible = "at24,24c256", "atmel,24c256";
 				reg = <0x56>;
 			};
 			rtc@68 {
-- 
2.9.3

^ permalink raw reply related

* [PATCH v3 17/21] powerpc/5200: Add generic compatible string for I2C EEPROM
From: Javier Martinez Canillas @ 2017-04-14  1:04 UTC (permalink / raw)
  To: linux-kernel
  Cc: Wolfram Sang, Javier Martinez Canillas, devicetree,
	Michael Ellerman, Benjamin Herrenschmidt, Paul Mackerras,
	Rob Herring, Mark Rutland, linuxppc-dev
In-Reply-To: <20170414010445.21727-1-javier@osg.samsung.com>

The at24 driver allows to register I2C EEPROM chips using different vendor
and devices, but the I2C subsystem does not take the vendor into account
when matching using the I2C table since it only has device entries.

But when matching using an OF table, both the vendor and device has to be
taken into account so the driver defines only a set of compatible strings
using the "atmel" vendor as a generic fallback for compatible I2C devices.

So add this generic fallback to the device node compatible string to make
the device to match the driver using the OF device ID table.

Signed-off-by: Javier Martinez Canillas <javier@osg.samsung.com>
---

Changes in v3: None
Changes in v2: None

 arch/powerpc/boot/dts/digsy_mtc.dts | 2 +-
 arch/powerpc/boot/dts/pcm030.dts    | 2 +-
 arch/powerpc/boot/dts/pcm032.dts    | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/boot/dts/digsy_mtc.dts b/arch/powerpc/boot/dts/digsy_mtc.dts
index 955bff629df3..0acb6ff7fc22 100644
--- a/arch/powerpc/boot/dts/digsy_mtc.dts
+++ b/arch/powerpc/boot/dts/digsy_mtc.dts
@@ -73,7 +73,7 @@
 
 		i2c@3d00 {
 			eeprom@50 {
-				compatible = "at,24c08";
+				compatible = "at,24c08", "atmel,24c08";
 				reg = <0x50>;
 			};
 
diff --git a/arch/powerpc/boot/dts/pcm030.dts b/arch/powerpc/boot/dts/pcm030.dts
index 192e66af0001..836e47cc4bed 100644
--- a/arch/powerpc/boot/dts/pcm030.dts
+++ b/arch/powerpc/boot/dts/pcm030.dts
@@ -71,7 +71,7 @@
 				reg = <0x51>;
 			};
 			eeprom@52 {
-				compatible = "catalyst,24c32";
+				compatible = "catalyst,24c32", "atmel,24c32";
 				reg = <0x52>;
 				pagesize = <32>;
 			};
diff --git a/arch/powerpc/boot/dts/pcm032.dts b/arch/powerpc/boot/dts/pcm032.dts
index 96b139bf50e9..576249bf2fb9 100644
--- a/arch/powerpc/boot/dts/pcm032.dts
+++ b/arch/powerpc/boot/dts/pcm032.dts
@@ -75,7 +75,7 @@
 				reg = <0x51>;
 			};
 			eeprom@52 {
-				compatible = "catalyst,24c32";
+				compatible = "catalyst,24c32", "atmel,24c32";
 				reg = <0x52>;
 				pagesize = <32>;
 			};
-- 
2.9.3

^ permalink raw reply related

* [PATCH v3 16/21] arm64: zynqmp: Add generic compatible string for I2C EEPROM
From: Javier Martinez Canillas @ 2017-04-14  1:04 UTC (permalink / raw)
  To: linux-kernel
  Cc: Wolfram Sang, Javier Martinez Canillas, Sören Brinkmann,
	devicetree, Michal Simek, Rob Herring, Will Deacon, Mark Rutland,
	Catalin Marinas, linux-arm-kernel
In-Reply-To: <20170414010445.21727-1-javier@osg.samsung.com>

The at24 driver allows to register I2C EEPROM chips using different vendor
and devices, but the I2C subsystem does not take the vendor into account
when matching using the I2C table since it only has device entries.

But when matching using an OF table, both the vendor and device has to be
taken into account so the driver defines only a set of compatible strings
using the "atmel" vendor as a generic fallback for compatible I2C devices.

So add this generic fallback to the device node compatible string to make
the device to match the driver using the OF device ID table.

Signed-off-by: Javier Martinez Canillas <javier@osg.samsung.com>
---

Changes in v3: None
Changes in v2: None

 arch/arm64/boot/dts/xilinx/zynqmp-ep108.dts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-ep108.dts b/arch/arm64/boot/dts/xilinx/zynqmp-ep108.dts
index ef1b9e573af0..9f29f99984f7 100644
--- a/arch/arm64/boot/dts/xilinx/zynqmp-ep108.dts
+++ b/arch/arm64/boot/dts/xilinx/zynqmp-ep108.dts
@@ -55,7 +55,7 @@
 	status = "okay";
 	clock-frequency = <400000>;
 	eeprom@54 {
-		compatible = "at,24c64";
+		compatible = "at,24c64", "atmel,24c64";
 		reg = <0x54>;
 	};
 };
@@ -64,7 +64,7 @@
 	status = "okay";
 	clock-frequency = <400000>;
 	eeprom@55 {
-		compatible = "at,24c64";
+		compatible = "at,24c64", "atmel,24c64";
 		reg = <0x55>;
 	};
 };
-- 
2.9.3

^ permalink raw reply related

* [PATCH v3 15/21] arm64: dts: ls1043a: Add generic compatible string for I2C EEPROM
From: Javier Martinez Canillas @ 2017-04-14  1:04 UTC (permalink / raw)
  To: linux-kernel
  Cc: Wolfram Sang, Javier Martinez Canillas, devicetree, Stuart Yoder,
	Rob Herring, Hongtao Jia, linux-arm-kernel, Will Deacon,
	Herbert Xu, Mark Rutland, Catalin Marinas, Shawn Guo,
	Horia Geantă
In-Reply-To: <20170414010445.21727-1-javier@osg.samsung.com>

The at24 driver allows to register I2C EEPROM chips using different vendor
and devices, but the I2C subsystem does not take the vendor into account
when matching using the I2C table since it only has device entries.

But when matching using an OF table, both the vendor and device has to be
taken into account so the driver defines only a set of compatible strings
using the "atmel" vendor as a generic fallback for compatible I2C devices.

So add this generic fallback to the device node compatible string to make
the device to match the driver using the OF device ID table.

Signed-off-by: Javier Martinez Canillas <javier@osg.samsung.com>
---

Changes in v3: None
Changes in v2: None

 arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts
index c37110bc1506..5389eae627e5 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts
@@ -75,11 +75,11 @@
 		reg = <0x4c>;
 	};
 	eeprom@52 {
-		compatible = "at24,24c512";
+		compatible = "at24,24c512", "atmel,24c512";
 		reg = <0x52>;
 	};
 	eeprom@53 {
-		compatible = "at24,24c512";
+		compatible = "at24,24c512", "atmel,24c512";
 		reg = <0x53>;
 	};
 	rtc@68 {
-- 
2.9.3

^ permalink raw reply related

* [PATCH v3 14/21] ARM: dts: zynq: Add generic compatible string for I2C EEPROM
From: Javier Martinez Canillas @ 2017-04-14  1:04 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: Wolfram Sang, Javier Martinez Canillas, Sören Brinkmann,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Michal Simek, Rob Herring,
	Mark Rutland, Russell King,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <20170414010445.21727-1-javier-JPH+aEBZ4P+UEJcrhfAQsw@public.gmane.org>

The at24 driver allows to register I2C EEPROM chips using different vendor
and devices, but the I2C subsystem does not take the vendor into account
when matching using the I2C table since it only has device entries.

But when matching using an OF table, both the vendor and device has to be
taken into account so the driver defines only a set of compatible strings
using the "atmel" vendor as a generic fallback for compatible I2C devices.

So add this generic fallback to the device node compatible string to make
the device to match the driver using the OF device ID table.

Signed-off-by: Javier Martinez Canillas <javier-JPH+aEBZ4P+UEJcrhfAQsw@public.gmane.org>
---

Changes in v3: None
Changes in v2: None

 arch/arm/boot/dts/zynq-zc702.dts | 2 +-
 arch/arm/boot/dts/zynq-zc706.dts | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/zynq-zc702.dts b/arch/arm/boot/dts/zynq-zc702.dts
index 0cdad2cc8b78..9aae7e061d19 100644
--- a/arch/arm/boot/dts/zynq-zc702.dts
+++ b/arch/arm/boot/dts/zynq-zc702.dts
@@ -136,7 +136,7 @@
 			#size-cells = <0>;
 			reg = <2>;
 			eeprom@54 {
-				compatible = "at,24c08";
+				compatible = "at,24c08", "atmel,24c08";
 				reg = <0x54>;
 			};
 		};
diff --git a/arch/arm/boot/dts/zynq-zc706.dts b/arch/arm/boot/dts/zynq-zc706.dts
index ad4bb06dba25..ff0fca1c41c8 100644
--- a/arch/arm/boot/dts/zynq-zc706.dts
+++ b/arch/arm/boot/dts/zynq-zc706.dts
@@ -92,7 +92,7 @@
 			#size-cells = <0>;
 			reg = <2>;
 			eeprom@54 {
-				compatible = "at,24c08";
+				compatible = "at,24c08", "atmel,24c08";
 				reg = <0x54>;
 			};
 		};
-- 
2.9.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v3 13/21] ARM: dts: uniphier: Add generic compatible string for I2C EEPROM
From: Javier Martinez Canillas @ 2017-04-14  1:04 UTC (permalink / raw)
  To: linux-kernel
  Cc: Wolfram Sang, Javier Martinez Canillas, devicetree,
	Masahiro Yamada, Rob Herring, Mark Rutland, Russell King,
	linux-arm-kernel
In-Reply-To: <20170414010445.21727-1-javier@osg.samsung.com>

The at24 driver allows to register I2C EEPROM chips using different vendor
and devices, but the I2C subsystem does not take the vendor into account
when matching using the I2C table since it only has device entries.

But when matching using an OF table, both the vendor and device has to be
taken into account so the driver defines only a set of compatible strings
using the "atmel" vendor as a generic fallback for compatible I2C devices.

So add this generic fallback to the device node compatible string to make
the device to match the driver using the OF device ID table.

Signed-off-by: Javier Martinez Canillas <javier@osg.samsung.com>
---

Changes in v3: None
Changes in v2: None

 arch/arm/boot/dts/uniphier-pro4-ace.dts    | 2 +-
 arch/arm/boot/dts/uniphier-pro4-sanji.dts  | 2 +-
 arch/arm/boot/dts/uniphier-pxs2-gentil.dts | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm/boot/dts/uniphier-pro4-ace.dts b/arch/arm/boot/dts/uniphier-pro4-ace.dts
index fefc89149234..b9a4919d7c93 100644
--- a/arch/arm/boot/dts/uniphier-pro4-ace.dts
+++ b/arch/arm/boot/dts/uniphier-pro4-ace.dts
@@ -88,7 +88,7 @@
 	status = "okay";
 
 	eeprom@54 {
-		compatible = "st,24c64";
+		compatible = "st,24c64", "atmel,24c64";
 		reg = <0x54>;
 		pagesize = <32>;
 	};
diff --git a/arch/arm/boot/dts/uniphier-pro4-sanji.dts b/arch/arm/boot/dts/uniphier-pro4-sanji.dts
index 6c63c8bad825..3950baa8d55d 100644
--- a/arch/arm/boot/dts/uniphier-pro4-sanji.dts
+++ b/arch/arm/boot/dts/uniphier-pro4-sanji.dts
@@ -83,7 +83,7 @@
 	status = "okay";
 
 	eeprom@54 {
-		compatible = "st,24c64";
+		compatible = "st,24c64", "atmel,24c64";
 		reg = <0x54>;
 		pagesize = <32>;
 	};
diff --git a/arch/arm/boot/dts/uniphier-pxs2-gentil.dts b/arch/arm/boot/dts/uniphier-pxs2-gentil.dts
index cccc86658d20..afba587ffbbc 100644
--- a/arch/arm/boot/dts/uniphier-pxs2-gentil.dts
+++ b/arch/arm/boot/dts/uniphier-pxs2-gentil.dts
@@ -80,7 +80,7 @@
 	status = "okay";
 
 	eeprom@54 {
-		compatible = "st,24c64";
+		compatible = "st,24c64", "atmel,24c64";
 		reg = <0x54>;
 		pagesize = <32>;
 	};
-- 
2.9.3

^ permalink raw reply related

* [PATCH v3 12/21] ARM: dts: socfpga: Add generic compatible string for I2C EEPROM
From: Javier Martinez Canillas @ 2017-04-14  1:04 UTC (permalink / raw)
  To: linux-kernel
  Cc: Mark Rutland, devicetree, Dinh Nguyen, Wolfram Sang, Russell King,
	Javier Martinez Canillas, Rob Herring, linux-arm-kernel
In-Reply-To: <20170414010445.21727-1-javier@osg.samsung.com>

The at24 driver allows to register I2C EEPROM chips using different vendor
and devices, but the I2C subsystem does not take the vendor into account
when matching using the I2C table since it only has device entries.

But when matching using an OF table, both the vendor and device has to be
taken into account so the driver defines only a set of compatible strings
using the "atmel" vendor as a generic fallback for compatible I2C devices.

So add this generic fallback to the device node compatible string to make
the device to match the driver using the OF device ID table.

Signed-off-by: Javier Martinez Canillas <javier@osg.samsung.com>
---

Changes in v3: None
Changes in v2: None

 arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts b/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts
index 363ee62457fe..24f566d81667 100644
--- a/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts
+++ b/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts
@@ -294,7 +294,7 @@
 	clock-frequency = <100000>;
 
 	at24@50 {
-		compatible = "at24,24c02";
+		compatible = "at24,24c02", "atmel,24c02";
 		pagesize = <8>;
 		reg = <0x50>;
 	};
-- 
2.9.3

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox