aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video
diff options
context:
space:
mode:
authorMichael Krufky <mkrufky@linuxtv.org>2008-04-22 13:45:52 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-04-24 13:07:49 -0400
commit62325497db6ef3b13cae41d5038e2693997d7d3e (patch)
treeedd38f653b28734ea22864a652ce17abebe84209 /drivers/media/video
parentac8b63b30a320699e602a18af6101528b408d41d (diff)
V4L/DVB (7347): tuner-simple: add basic support for digital tuning of hybrid devices
Add entry points used for digital tuning via the dvb_frontend. Share state data between multiple instances of the driver for hybrid tuners. Signed-off-by: Michael Krufky <mkrufky@linuxtv.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video')
-rw-r--r--drivers/media/video/tuner-simple.c156
1 files changed, 146 insertions, 10 deletions
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
index ee5ef860700..d6d922c32bc 100644
--- a/drivers/media/video/tuner-simple.c
+++ b/drivers/media/video/tuner-simple.c
@@ -88,14 +88,20 @@ MODULE_PARM_DESC(offset, "Allows to specify an offset for tuner");
88#define TUNER_PLL_LOCKED 0x40 88#define TUNER_PLL_LOCKED 0x40
89#define TUNER_STEREO_MK3 0x04 89#define TUNER_STEREO_MK3 0x04
90 90
91static DEFINE_MUTEX(tuner_simple_list_mutex);
92static LIST_HEAD(hybrid_tuner_instance_list);
93
91struct tuner_simple_priv { 94struct tuner_simple_priv {
92 u16 last_div; 95 u16 last_div;
96
93 struct tuner_i2c_props i2c_props; 97 struct tuner_i2c_props i2c_props;
98 struct list_head hybrid_tuner_instance_list;
94 99
95 unsigned int type; 100 unsigned int type;
96 struct tunertype *tun; 101 struct tunertype *tun;
97 102
98 u32 frequency; 103 u32 frequency;
104 u32 bandwidth;
99}; 105};
100 106
101/* ---------------------------------------------------------------------- */ 107/* ---------------------------------------------------------------------- */
@@ -188,6 +194,9 @@ static inline char *tuner_param_name(enum param_type type)
188 case TUNER_PARAM_TYPE_NTSC: 194 case TUNER_PARAM_TYPE_NTSC:
189 name = "ntsc"; 195 name = "ntsc";
190 break; 196 break;
197 case TUNER_PARAM_TYPE_DIGITAL:
198 name = "digital";
199 break;
191 default: 200 default:
192 name = "unknown"; 201 name = "unknown";
193 break; 202 break;
@@ -687,14 +696,118 @@ static int simple_set_params(struct dvb_frontend *fe,
687 priv->frequency = params->frequency * 62500; 696 priv->frequency = params->frequency * 62500;
688 break; 697 break;
689 } 698 }
699 priv->bandwidth = 0;
690 700
691 return ret; 701 return ret;
692} 702}
693 703
704static int simple_dvb_configure(struct dvb_frontend *fe, u8 *buf,
705 const struct dvb_frontend_parameters *params)
706{
707 struct tuner_simple_priv *priv = fe->tuner_priv;
708 struct tunertype *tun = priv->tun;
709 static struct tuner_params *t_params;
710 u8 config, cb;
711 u32 div;
712 int ret, frequency = params->frequency / 62500;
713
714 t_params = simple_tuner_params(fe, TUNER_PARAM_TYPE_DIGITAL);
715 ret = simple_config_lookup(fe, t_params, &frequency, &config, &cb);
716 if (ret < 0)
717 return ret;
718
719 div = ((frequency + t_params->iffreq) * 62500 + offset +
720 tun->stepsize/2) / tun->stepsize;
721
722 buf[0] = div >> 8;
723 buf[1] = div & 0xff;
724 buf[2] = config;
725 buf[3] = cb;
726
727 tuner_dbg("%s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
728 tun->name, div, buf[0], buf[1], buf[2], buf[3]);
729
730 /* calculate the frequency we set it to */
731 return (div * tun->stepsize) - t_params->iffreq;
732}
733
734static int simple_dvb_calc_regs(struct dvb_frontend *fe,
735 struct dvb_frontend_parameters *params,
736 u8 *buf, int buf_len)
737{
738 struct tuner_simple_priv *priv = fe->tuner_priv;
739 int ret;
740 u32 frequency;
741
742 if (buf_len < 5)
743 return -EINVAL;
744
745 ret = simple_dvb_configure(fe, buf+1, params);
746 if (ret < 0)
747 return ret;
748 else
749 frequency = ret;
750
751 buf[0] = priv->i2c_props.addr;
752
753 priv->frequency = frequency;
754 priv->bandwidth = (fe->ops.info.type == FE_OFDM) ?
755 params->u.ofdm.bandwidth : 0;
756
757 return 5;
758}
759
760static int simple_dvb_set_params(struct dvb_frontend *fe,
761 struct dvb_frontend_parameters *params)
762{
763 struct tuner_simple_priv *priv = fe->tuner_priv;
764 u32 prev_freq, prev_bw;
765 int ret;
766 u8 buf[5];
767
768 if (priv->i2c_props.adap == NULL)
769 return -EINVAL;
770
771 prev_freq = priv->frequency;
772 prev_bw = priv->bandwidth;
773
774 ret = simple_dvb_calc_regs(fe, params, buf, 5);
775 if (ret != 5)
776 goto fail;
777
778 /* put analog demod in standby when tuning digital */
779 if (fe->ops.analog_ops.standby)
780 fe->ops.analog_ops.standby(fe);
781
782 if (fe->ops.i2c_gate_ctrl)
783 fe->ops.i2c_gate_ctrl(fe, 1);
784
785 /* buf[0] contains the i2c address, but *
786 * we already have it in i2c_props.addr */
787 ret = tuner_i2c_xfer_send(&priv->i2c_props, buf+1, 4);
788 if (ret != 4)
789 goto fail;
790
791 return 0;
792fail:
793 /* calc_regs sets frequency and bandwidth. if we failed, unset them */
794 priv->frequency = prev_freq;
795 priv->bandwidth = prev_bw;
796
797 return ret;
798}
694 799
695static int simple_release(struct dvb_frontend *fe) 800static int simple_release(struct dvb_frontend *fe)
696{ 801{
697 kfree(fe->tuner_priv); 802 struct tuner_simple_priv *priv = fe->tuner_priv;
803
804 mutex_lock(&tuner_simple_list_mutex);
805
806 if (priv)
807 hybrid_tuner_release_state(priv);
808
809 mutex_unlock(&tuner_simple_list_mutex);
810
698 fe->tuner_priv = NULL; 811 fe->tuner_priv = NULL;
699 812
700 return 0; 813 return 0;
@@ -707,10 +820,20 @@ static int simple_get_frequency(struct dvb_frontend *fe, u32 *frequency)
707 return 0; 820 return 0;
708} 821}
709 822
823static int simple_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
824{
825 struct tuner_simple_priv *priv = fe->tuner_priv;
826 *bandwidth = priv->bandwidth;
827 return 0;
828}
829
710static struct dvb_tuner_ops simple_tuner_ops = { 830static struct dvb_tuner_ops simple_tuner_ops = {
711 .set_analog_params = simple_set_params, 831 .set_analog_params = simple_set_params,
832 .set_params = simple_dvb_set_params,
833 .calc_regs = simple_dvb_calc_regs,
712 .release = simple_release, 834 .release = simple_release,
713 .get_frequency = simple_get_frequency, 835 .get_frequency = simple_get_frequency,
836 .get_bandwidth = simple_get_bandwidth,
714 .get_status = simple_get_status, 837 .get_status = simple_get_status,
715 .get_rf_strength = simple_get_rf_strength, 838 .get_rf_strength = simple_get_rf_strength,
716}; 839};
@@ -721,6 +844,7 @@ struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
721 unsigned int type) 844 unsigned int type)
722{ 845{
723 struct tuner_simple_priv *priv = NULL; 846 struct tuner_simple_priv *priv = NULL;
847 int instance;
724 848
725 if (type >= tuner_count) { 849 if (type >= tuner_count) {
726 printk(KERN_WARNING "%s: invalid tuner type: %d (max: %d)\n", 850 printk(KERN_WARNING "%s: invalid tuner type: %d (max: %d)\n",
@@ -728,22 +852,34 @@ struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
728 return NULL; 852 return NULL;
729 } 853 }
730 854
731 priv = kzalloc(sizeof(struct tuner_simple_priv), GFP_KERNEL); 855 mutex_lock(&tuner_simple_list_mutex);
732 if (priv == NULL) 856
857 instance = hybrid_tuner_request_state(struct tuner_simple_priv, priv,
858 hybrid_tuner_instance_list,
859 i2c_adap, i2c_addr,
860 "tuner-simple");
861 switch (instance) {
862 case 0:
863 mutex_unlock(&tuner_simple_list_mutex);
733 return NULL; 864 return NULL;
734 fe->tuner_priv = priv; 865 break;
866 case 1:
867 fe->tuner_priv = priv;
735 868
736 priv->i2c_props.addr = i2c_addr; 869 priv->type = type;
737 priv->i2c_props.adap = i2c_adap; 870 priv->tun = &tuners[type];
738 priv->i2c_props.name = "tuner-simple"; 871 break;
872 default:
873 fe->tuner_priv = priv;
874 break;
875 }
739 876
740 priv->type = type; 877 mutex_unlock(&tuner_simple_list_mutex);
741 priv->tun = &tuners[type];
742 878
743 memcpy(&fe->ops.tuner_ops, &simple_tuner_ops, 879 memcpy(&fe->ops.tuner_ops, &simple_tuner_ops,
744 sizeof(struct dvb_tuner_ops)); 880 sizeof(struct dvb_tuner_ops));
745 881
746 tuner_info("type set to %d (%s)\n", priv->type, priv->tun->name); 882 tuner_info("type set to %d (%s)\n", type, priv->tun->name);
747 883
748 strlcpy(fe->ops.tuner_ops.info.name, priv->tun->name, 884 strlcpy(fe->ops.tuner_ops.info.name, priv->tun->name,
749 sizeof(fe->ops.tuner_ops.info.name)); 885 sizeof(fe->ops.tuner_ops.info.name));