[REVIEW PATCH 14/16] r820t: add manual gain controls

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add gain control for LNA, Mixer and IF. Expose controls via
V4L control framework.

Cc: Mauro Carvalho Chehab <m.chehab@xxxxxxxxxxx>
Signed-off-by: Antti Palosaari <crope@xxxxxx>
---
 drivers/media/tuners/r820t.c | 137 ++++++++++++++++++++++++++++++++++++++++++-
 drivers/media/tuners/r820t.h |  10 ++++
 2 files changed, 146 insertions(+), 1 deletion(-)

diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c
index 319adc4..452a486 100644
--- a/drivers/media/tuners/r820t.c
+++ b/drivers/media/tuners/r820t.c
@@ -36,6 +36,7 @@
 #include <linux/mutex.h>
 #include <linux/slab.h>
 #include <linux/bitrev.h>
+#include <media/v4l2-ctrls.h>
 
 #include "tuner-i2c.h"
 #include "r820t.h"
@@ -80,6 +81,7 @@ struct r820t_sect_type {
 
 struct r820t_priv {
 	struct list_head		hybrid_tuner_instance_list;
+	struct dvb_frontend		*fe;
 	const struct r820t_config	*cfg;
 	struct tuner_i2c_props		i2c_props;
 	struct mutex			lock;
@@ -100,6 +102,15 @@ struct r820t_priv {
 	enum v4l2_tuner_type		type;
 	v4l2_std_id			std;
 	u32				bw;	/* in MHz */
+
+	/* Controls */
+	struct v4l2_ctrl_handler hdl;
+	struct v4l2_ctrl *lna_gain_auto;
+	struct v4l2_ctrl *lna_gain;
+	struct v4l2_ctrl *mixer_gain_auto;
+	struct v4l2_ctrl *mixer_gain;
+	struct v4l2_ctrl *if_gain_auto;
+	struct v4l2_ctrl *if_gain;
 };
 
 struct r820t_freq_range {
@@ -2255,8 +2266,10 @@ static int r820t_release(struct dvb_frontend *fe)
 
 	mutex_lock(&r820t_list_mutex);
 
-	if (priv)
+	if (priv) {
+		v4l2_ctrl_handler_free(&priv->hdl);
 		hybrid_tuner_release_state(priv);
+	}
 
 	mutex_unlock(&r820t_list_mutex);
 
@@ -2265,6 +2278,96 @@ static int r820t_release(struct dvb_frontend *fe)
 	return 0;
 }
 
+static int r820t_set_lna_gain(struct r820t_priv *priv)
+{
+	struct dvb_frontend *fe = priv->fe;
+	int rc;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	if (priv->lna_gain_auto->val)
+		rc = r820t_write_reg_mask(priv, 0x05, 0x00, 0x10);
+	else
+		rc = r820t_write_reg_mask(priv, 0x05,
+				0x10 | priv->lna_gain->val, 0x1f);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return rc;
+}
+
+static int r820t_set_mixer_gain(struct r820t_priv *priv)
+{
+	struct dvb_frontend *fe = priv->fe;
+	int rc;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	if (priv->mixer_gain_auto->val)
+		rc = r820t_write_reg_mask(priv, 0x07, 0x10, 0x10);
+	else
+		rc = r820t_write_reg_mask(priv, 0x07,
+				0x00 | priv->mixer_gain->val, 0x1f);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return rc;
+}
+
+static int r820t_set_if_gain(struct r820t_priv *priv)
+{
+	struct dvb_frontend *fe = priv->fe;
+	int rc;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	if (priv->if_gain_auto->val)
+		rc = r820t_write_reg_mask(priv, 0x0c, 0x10, 0x10);
+	else
+		rc = r820t_write_reg_mask(priv, 0x0c,
+				0x00 | priv->if_gain->val, 0x1f);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return rc;
+}
+
+static int r820t_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct r820t_priv *priv =
+			container_of(ctrl->handler, struct r820t_priv, hdl);
+	int rc;
+
+	switch (ctrl->id) {
+	case  V4L2_CID_RF_TUNER_LNA_GAIN_AUTO:
+	case  V4L2_CID_RF_TUNER_LNA_GAIN:
+		rc = r820t_set_lna_gain(priv);
+		break;
+	case  V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO:
+	case  V4L2_CID_RF_TUNER_MIXER_GAIN:
+		rc = r820t_set_mixer_gain(priv);
+		break;
+	case  V4L2_CID_RF_TUNER_IF_GAIN_AUTO:
+	case  V4L2_CID_RF_TUNER_IF_GAIN:
+		rc = r820t_set_if_gain(priv);
+		break;
+	default:
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+static const struct v4l2_ctrl_ops r820t_ctrl_ops = {
+	.s_ctrl = r820t_s_ctrl,
+};
+
 static const struct dvb_tuner_ops r820t_tuner_ops = {
 	.info = {
 		.name           = "Rafael Micro R820T",
@@ -2280,6 +2383,13 @@ static const struct dvb_tuner_ops r820t_tuner_ops = {
 	.get_rf_strength = r820t_signal,
 };
 
+struct v4l2_ctrl_handler *r820t_get_ctrl_handler(struct dvb_frontend *fe)
+{
+	struct r820t_priv *priv = fe->tuner_priv;
+	return &priv->hdl;
+}
+EXPORT_SYMBOL(r820t_get_ctrl_handler);
+
 struct dvb_frontend *r820t_attach(struct dvb_frontend *fe,
 				  struct i2c_adapter *i2c,
 				  const struct r820t_config *cfg)
@@ -2314,6 +2424,8 @@ struct dvb_frontend *r820t_attach(struct dvb_frontend *fe,
 		break;
 	}
 
+	priv->fe = fe;
+
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
 
@@ -2326,6 +2438,29 @@ struct dvb_frontend *r820t_attach(struct dvb_frontend *fe,
 	if (rc < 0)
 		goto err;
 
+	/* Register controls */
+	v4l2_ctrl_handler_init(&priv->hdl, 6);
+	priv->lna_gain_auto = v4l2_ctrl_new_std(&priv->hdl, &r820t_ctrl_ops,
+			V4L2_CID_RF_TUNER_LNA_GAIN_AUTO, 0, 1, 1, 1);
+	priv->lna_gain = v4l2_ctrl_new_std(&priv->hdl, &r820t_ctrl_ops,
+			V4L2_CID_RF_TUNER_LNA_GAIN, 0, 15, 1, 6);
+	v4l2_ctrl_auto_cluster(2, &priv->lna_gain_auto, 0, false);
+	priv->mixer_gain_auto = v4l2_ctrl_new_std(&priv->hdl, &r820t_ctrl_ops,
+			V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO, 0, 1, 1, 1);
+	priv->mixer_gain = v4l2_ctrl_new_std(&priv->hdl, &r820t_ctrl_ops,
+			V4L2_CID_RF_TUNER_MIXER_GAIN, 0, 15, 1, 5);
+	v4l2_ctrl_auto_cluster(2, &priv->mixer_gain_auto, 0, false);
+	priv->if_gain_auto = v4l2_ctrl_new_std(&priv->hdl, &r820t_ctrl_ops,
+			V4L2_CID_RF_TUNER_IF_GAIN_AUTO, 0, 1, 1, 1);
+	priv->if_gain = v4l2_ctrl_new_std(&priv->hdl, &r820t_ctrl_ops,
+			V4L2_CID_RF_TUNER_IF_GAIN, 0, 15, 1, 4);
+	v4l2_ctrl_auto_cluster(2, &priv->if_gain_auto, 0, false);
+	if (priv->hdl.error) {
+		rc = priv->hdl.error;
+		tuner_info("Could not initialize controls\n");
+		goto err;
+	}
+
 	tuner_info("Rafael Micro r820t successfully identified\n");
 
 	if (fe->ops.i2c_gate_ctrl)
diff --git a/drivers/media/tuners/r820t.h b/drivers/media/tuners/r820t.h
index 48af354..b61d6ea 100644
--- a/drivers/media/tuners/r820t.h
+++ b/drivers/media/tuners/r820t.h
@@ -46,6 +46,9 @@ struct r820t_config {
 struct dvb_frontend *r820t_attach(struct dvb_frontend *fe,
 				  struct i2c_adapter *i2c,
 				  const struct r820t_config *cfg);
+
+extern struct v4l2_ctrl_handler *r820t_get_ctrl_handler(
+				struct dvb_frontend *fe);
 #else
 static inline struct dvb_frontend *r820t_attach(struct dvb_frontend *fe,
 						struct i2c_adapter *i2c,
@@ -54,6 +57,13 @@ static inline struct dvb_frontend *r820t_attach(struct dvb_frontend *fe,
 	pr_warn("%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
+
+static inline struct v4l2_ctrl_handler *r820t_get_ctrl_handler(
+				struct dvb_frontend *fe)
+{
+	pr_warn("%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
 #endif
 
 #endif
-- 
1.8.5.3

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




[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux