From e47b78f036bf1c30a5263ccdf1f638d1612b0586 Mon Sep 17 00:00:00 2001
From: Antti Palosaari <crope@iki.fi>
Date: Tue, 3 May 2011 20:31:36 -0300
Subject: [PATCH] [media] cxd2820r: switch automatically between DVB-T and
 DVB-T2

Remove old DVB-T2 freq module param and detect DVB-T/T2 automatically.

Implementation is trial and error, if DVB-T does not lock try DVB-T2
and vice versa. That's done by replacing normal DVBFE_ALGO_SW with
DVBFE_ALGO_CUSTOM which gives better control for tuning process.

DVB-C still uses normal software ZigZag, DVBFE_ALGO_SW.

Signed-off-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
---
 drivers/media/dvb/frontends/cxd2820r_core.c | 111 +++++++++++++-------
 drivers/media/dvb/frontends/cxd2820r_priv.h |   1 +
 2 files changed, 73 insertions(+), 39 deletions(-)

diff --git a/drivers/media/dvb/frontends/cxd2820r_core.c b/drivers/media/dvb/frontends/cxd2820r_core.c
index 59d302f7a8f1..e900c4cad7fd 100644
--- a/drivers/media/dvb/frontends/cxd2820r_core.c
+++ b/drivers/media/dvb/frontends/cxd2820r_core.c
@@ -25,13 +25,6 @@ int cxd2820r_debug;
 module_param_named(debug, cxd2820r_debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
 
-/* TODO: temporary hack, will be removed later when there is app support */
-unsigned int cxd2820r_dvbt2_freq[5];
-int cxd2820r_dvbt2_count;
-module_param_array_named(dvbt2_freq, cxd2820r_dvbt2_freq, int,
-	&cxd2820r_dvbt2_count, 0644);
-MODULE_PARM_DESC(dvbt2_freq, "RF frequencies forced to DVB-T2 (unit Hz)");
-
 /* write multiple registers */
 static int cxd2820r_wr_regs_i2c(struct cxd2820r_priv *priv, u8 i2c, u8 reg,
 	u8 *val, int len)
@@ -626,8 +619,7 @@ static int cxd2820r_get_tune_settings(struct dvb_frontend *fe,
 	struct dvb_frontend_tune_settings *s)
 {
 	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	int ret, i;
-	unsigned int rf1, rf2;
+	int ret;
 	dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
 
 	if (fe->ops.info.type == FE_OFDM) {
@@ -636,35 +628,6 @@ static int cxd2820r_get_tune_settings(struct dvb_frontend *fe,
 		if (ret)
 			return ret;
 
-		/* TODO: hack! This will be removed later when there is better
-		 * app support for DVB-T2... */
-
-		/* Hz => MHz */
-		rf1 = DIV_ROUND_CLOSEST(fe->dtv_property_cache.frequency,
-			1000000);
-		for (i = 0; i < cxd2820r_dvbt2_count; i++) {
-			if (cxd2820r_dvbt2_freq[i] > 100000000) {
-				/* Hz => MHz */
-				rf2 = DIV_ROUND_CLOSEST(cxd2820r_dvbt2_freq[i],
-					1000000);
-			} else if (cxd2820r_dvbt2_freq[i] > 100000) {
-				/* kHz => MHz */
-				rf2 = DIV_ROUND_CLOSEST(cxd2820r_dvbt2_freq[i],
-					1000);
-			} else {
-				rf2 = cxd2820r_dvbt2_freq[i];
-			}
-
-			dbg("%s: rf1=%d rf2=%d", __func__, rf1, rf2);
-
-			if (rf1 == rf2) {
-				dbg("%s: forcing DVB-T2, frequency=%d",
-				__func__, fe->dtv_property_cache.frequency);
-				fe->dtv_property_cache.delivery_system =
-					SYS_DVBT2;
-			}
-		}
-
 		switch (fe->dtv_property_cache.delivery_system) {
 		case SYS_DVBT:
 			ret = cxd2820r_get_tune_settings_t(fe, s);
@@ -687,6 +650,74 @@ static int cxd2820r_get_tune_settings(struct dvb_frontend *fe,
 	return ret;
 }
 
+static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe,
+	struct dvb_frontend_parameters *p)
+{
+	struct cxd2820r_priv *priv = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret, i;
+	fe_status_t status = 0;
+	dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+
+	/* switch between DVB-T and DVB-T2 when tune fails */
+	if (priv->last_tune_failed) {
+		if (priv->delivery_system == SYS_DVBT)
+			c->delivery_system = SYS_DVBT2;
+		else
+			c->delivery_system = SYS_DVBT;
+	}
+
+	/* set frontend */
+	ret = cxd2820r_set_frontend(fe, p);
+	if (ret)
+		goto error;
+
+
+	/* frontend lock wait loop count */
+	switch (priv->delivery_system) {
+	case SYS_DVBT:
+		i = 20;
+		break;
+	case SYS_DVBT2:
+		i = 40;
+		break;
+	case SYS_UNDEFINED:
+	default:
+		i = 0;
+		break;
+	}
+
+	/* wait frontend lock */
+	for (; i > 0; i--) {
+		dbg("%s: LOOP=%d", __func__, i);
+		msleep(50);
+		ret = cxd2820r_read_status(fe, &status);
+		if (ret)
+			goto error;
+
+		if (status & FE_HAS_SIGNAL)
+			break;
+	}
+
+	/* check if we have a valid signal */
+	if (status) {
+		priv->last_tune_failed = 0;
+		return DVBFE_ALGO_SEARCH_SUCCESS;
+	} else {
+		priv->last_tune_failed = 1;
+		return DVBFE_ALGO_SEARCH_AGAIN;
+	}
+
+error:
+	dbg("%s: failed:%d", __func__, ret);
+	return DVBFE_ALGO_SEARCH_ERROR;
+}
+
+static int cxd2820r_get_frontend_algo(struct dvb_frontend *fe)
+{
+	return DVBFE_ALGO_CUSTOM;
+}
+
 static void cxd2820r_release(struct dvb_frontend *fe)
 {
 	struct cxd2820r_priv *priv = fe->demodulator_priv;
@@ -838,9 +869,11 @@ static struct dvb_frontend_ops cxd2820r_ops[2] = {
 
 		.get_tune_settings = cxd2820r_get_tune_settings,
 
-		.set_frontend = cxd2820r_set_frontend,
 		.get_frontend = cxd2820r_get_frontend,
 
+		.get_frontend_algo = cxd2820r_get_frontend_algo,
+		.search = cxd2820r_search,
+
 		.read_status = cxd2820r_read_status,
 		.read_snr = cxd2820r_read_snr,
 		.read_ber = cxd2820r_read_ber,
diff --git a/drivers/media/dvb/frontends/cxd2820r_priv.h b/drivers/media/dvb/frontends/cxd2820r_priv.h
index 835e37b98049..d4e2e0b76c10 100644
--- a/drivers/media/dvb/frontends/cxd2820r_priv.h
+++ b/drivers/media/dvb/frontends/cxd2820r_priv.h
@@ -73,6 +73,7 @@ struct cxd2820r_priv {
 	u8 gpio[3];
 
 	fe_delivery_system_t delivery_system;
+	int last_tune_failed:1; /* for switch between T and T2 tune */
 };
 
 /* cxd2820r_core.c */
-- 
GitLab