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

2014-02-26 Thread Antti Palosaari
Add gain control for LNA, Mixer and IF. Expose controls via
V4L control framework.

Cc: Mauro Carvalho Chehab m.che...@samsung.com
Signed-off-by: Antti Palosaari cr...@iki.fi
---
 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_headhybrid_tuner_instance_list;
+   struct dvb_frontend *fe;
const struct r820t_config   *cfg;
struct tuner_i2c_props  i2c_props;
struct mutexlock;
@@ -100,6 +102,15 @@ struct r820t_priv {
enum v4l2_tuner_typetype;
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,
 

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

2014-02-10 Thread Antti Palosaari
Add gain control for LNA, Mixer and IF. Expose controls via
V4L control framework.

Cc: Mauro Carvalho Chehab m.che...@samsung.com
Signed-off-by: Antti Palosaari cr...@iki.fi
---
 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..5150a18 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_headhybrid_tuner_instance_list;
+   struct dvb_frontend *fe;
const struct r820t_config   *cfg;
struct tuner_i2c_props  i2c_props;
struct mutexlock;
@@ -100,6 +102,15 @@ struct r820t_priv {
enum v4l2_tuner_typetype;
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_LNA_GAIN_AUTO:
+   case  V4L2_CID_LNA_GAIN:
+   rc = r820t_set_lna_gain(priv);
+   break;
+   case  V4L2_CID_MIXER_GAIN_AUTO:
+   case  V4L2_CID_MIXER_GAIN:
+   rc = r820t_set_mixer_gain(priv);
+   break;
+   case  V4L2_CID_IF_GAIN_AUTO:
+   case  V4L2_CID_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