diff options
author | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-09-06 18:39:07 +0100 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-09-06 18:39:07 +0100 |
commit | ed129684f8f1715a59248d413db621a71c96e285 (patch) | |
tree | c1885a9dafa95a57475321f1ed328aeed2e27754 /linux/drivers/media/video/tuner-core.c | |
parent | 254094433ada550c4411ed47b20d0fd13f490d21 (diff) | |
parent | 6b59fbe5fa40581818289f66c6337c300056bda8 (diff) | |
download | mediapointer-dvb-s2-ed129684f8f1715a59248d413db621a71c96e285.tar.gz mediapointer-dvb-s2-ed129684f8f1715a59248d413db621a71c96e285.tar.bz2 |
merge: http://linuxtv.org/hg/~mkrufky/fusionhdtv
From: Mauro Carvalho Chehab <mchehab@infradead.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'linux/drivers/media/video/tuner-core.c')
-rw-r--r-- | linux/drivers/media/video/tuner-core.c | 230 |
1 files changed, 190 insertions, 40 deletions
diff --git a/linux/drivers/media/video/tuner-core.c b/linux/drivers/media/video/tuner-core.c index dd37aed8b..d4d3fcf8e 100644 --- a/linux/drivers/media/video/tuner-core.c +++ b/linux/drivers/media/video/tuner-core.c @@ -18,11 +18,17 @@ #include "compat.h" #include <linux/videodev.h> #include <media/tuner.h> +#include <media/tuner-types.h> #include <media/v4l2-common.h> #include "tuner-driver.h" #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) #include "i2c-compat.h" #endif +#include "mt20xx.h" +#include "tda8290.h" +#include "tea5761.h" +#include "tea5767.h" +#include "tuner-simple.h" #define UNSET (-1U) @@ -95,6 +101,51 @@ static struct i2c_client client_template; /* ---------------------------------------------------------------------- */ +static void fe_set_freq(struct tuner *t, unsigned int freq) +{ + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + + struct analog_parameters params = { + .frequency = freq, + .mode = t->mode, + .audmode = t->audmode, + .std = t->std + }; + + if (NULL == fe_tuner_ops->set_analog_params) { + tuner_warn("Tuner frontend module has no way to set freq\n"); + return; + } + fe_tuner_ops->set_analog_params(&t->fe, ¶ms); +} + +static void fe_release(struct tuner *t) +{ + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + + if (fe_tuner_ops->release) + fe_tuner_ops->release(&t->fe); +} + +static void fe_standby(struct tuner *t) +{ + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + + if (fe_tuner_ops->sleep) + fe_tuner_ops->sleep(&t->fe); +} + +static int fe_has_signal(struct tuner *t) +{ + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + u16 strength; + + if (fe_tuner_ops->get_rf_strength) + fe_tuner_ops->get_rf_strength(&t->fe, &strength); + + return strength; +} + /* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */ static void set_tv_freq(struct i2c_client *c, unsigned int freq) { @@ -119,7 +170,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) else freq = tv_range[1] * 16; } - t->ops.set_tv_freq(c, freq); + t->ops.set_tv_freq(t, freq); } static void set_radio_freq(struct i2c_client *c, unsigned int freq) @@ -146,7 +197,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) freq = radio_range[1] * 16000; } - t->ops.set_radio_freq(c, freq); + t->ops.set_radio_freq(t, freq); } static void set_freq(struct i2c_client *c, unsigned long freq) @@ -170,11 +221,51 @@ static void set_freq(struct i2c_client *c, unsigned long freq) } } +static void tuner_i2c_address_check(struct tuner *t) +{ + if ((t->type == UNSET || t->type == TUNER_ABSENT) || + ((t->i2c.addr < 0x64) || (t->i2c.addr > 0x6f))) + return; + + tuner_warn("====================== WARNING! ======================\n"); + tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n"); + tuner_warn("will soon be dropped. This message indicates that your\n"); + tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n", + t->i2c.name, t->i2c.addr); + tuner_warn("To ensure continued support for your device, please\n"); + tuner_warn("send a copy of this message, along with full dmesg\n"); + tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n"); + tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n"); + tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n", + t->i2c.adapter->name, t->i2c.addr, t->type, + tuners[t->type].name); + tuner_warn("====================== WARNING! ======================\n"); +} + +static void attach_tda8290(struct tuner *t) +{ + struct tda8290_config cfg = { + .lna_cfg = &t->config, + .tuner_callback = t->tuner_callback + }; + tda8290_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg); +} + +static void attach_simple_tuner(struct tuner *t) +{ + struct simple_tuner_config cfg = { + .type = t->type, + .tun = &tuners[t->type] + }; + simple_tuner_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg); +} + static void set_type(struct i2c_client *c, unsigned int type, unsigned int new_mode_mask, unsigned int new_config, int (*tuner_callback) (void *dev, int command,int arg)) { struct tuner *t = i2c_get_clientdata(c); + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; unsigned char buffer[4]; if (type == UNSET || type == TUNER_ABSENT) { @@ -205,7 +296,7 @@ static void set_type(struct i2c_client *c, unsigned int type, /* discard private data, in case set_type() was previously called */ if (t->ops.release) - t->ops.release(c); + t->ops.release(t); else { kfree(t->priv); t->priv = NULL; @@ -213,13 +304,15 @@ static void set_type(struct i2c_client *c, unsigned int type, switch (t->type) { case TUNER_MT2032: - microtune_init(c); + microtune_attach(&t->fe, t->i2c.adapter, t->i2c.addr); break; case TUNER_PHILIPS_TDA8290: - tda8290_init(c); + { + attach_tda8290(t); break; + } case TUNER_TEA5767: - if (tea5767_tuner_init(c) == EINVAL) { + if (tea5767_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) { t->type = TUNER_ABSENT; t->mode_mask = T_UNINITIALIZED; return; @@ -228,7 +321,7 @@ static void set_type(struct i2c_client *c, unsigned int type, break; #ifdef CONFIG_TUNER_TEA5761 case TUNER_TEA5761: - if (tea5761_tuner_init(c) == EINVAL) { + if (tea5761_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) { t->type = TUNER_ABSENT; t->mode_mask = T_UNINITIALIZED; return; @@ -246,7 +339,7 @@ static void set_type(struct i2c_client *c, unsigned int type, buffer[2] = 0x86; buffer[3] = 0x54; i2c_master_send(c, buffer, 4); - default_tuner_init(c); + attach_simple_tuner(t); break; case TUNER_PHILIPS_TD1316: buffer[0] = 0x0b; @@ -254,10 +347,10 @@ static void set_type(struct i2c_client *c, unsigned int type, buffer[2] = 0x86; buffer[3] = 0xa4; i2c_master_send(c,buffer,4); - default_tuner_init(c); + attach_simple_tuner(t); break; case TUNER_TDA9887: - tda9887_tuner_init(c); + tda9887_tuner_init(t); break; #ifdef CONFIG_XC3028 case TUNER_XCEIVE_XC3028: @@ -265,10 +358,22 @@ static void set_type(struct i2c_client *c, unsigned int type, break; #endif default: - default_tuner_init(c); + attach_simple_tuner(t); break; } + if (fe_tuner_ops->set_analog_params) { + strlcpy(t->i2c.name, fe_tuner_ops->info.name, sizeof(t->i2c.name)); + + t->ops.set_tv_freq = fe_set_freq; + t->ops.set_radio_freq = fe_set_freq; + t->ops.standby = fe_standby; + t->ops.release = fe_release; + t->ops.has_signal = fe_has_signal; + } + + tuner_info("type set to %s\n", t->i2c.name); + if (t->mode_mask == T_UNINITIALIZED) t->mode_mask = new_mode_mask; @@ -282,6 +387,7 @@ static void set_type(struct i2c_client *c, unsigned int type, c->adapter->name, c->driver->driver.name, c->addr << 1, type, t->mode_mask); #endif + tuner_i2c_address_check(t); } /* @@ -445,10 +551,10 @@ static int tuner_fixup_std(struct tuner *t) return 0; } -static void tuner_status(struct i2c_client *client) +static void tuner_status(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(client); unsigned long freq, freq_fraction; + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; const char *p; switch (t->mode) { @@ -469,11 +575,20 @@ static void tuner_status(struct i2c_client *client) tuner_info("Standard: 0x%08lx\n", (unsigned long)t->std); if (t->mode != V4L2_TUNER_RADIO) return; + if (fe_tuner_ops->get_status) { + u32 tuner_status; + + fe_tuner_ops->get_status(&t->fe, &tuner_status); + if (tuner_status & TUNER_STATUS_LOCKED) + tuner_info("Tuner is locked.\n"); + if (tuner_status & TUNER_STATUS_STEREO) + tuner_info("Stereo: yes\n"); + } if (t->ops.has_signal) { - tuner_info("Signal strength: %d\n", t->ops.has_signal(client)); + tuner_info("Signal strength: %d\n", t->ops.has_signal(t)); } if (t->ops.is_stereo) { - tuner_info("Stereo: %s\n", t->ops.is_stereo(client) ? "yes" : "no"); + tuner_info("Stereo: %s\n", t->ops.is_stereo(t) ? "yes" : "no"); } } @@ -527,7 +642,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, switch (addr) { #ifdef CONFIG_TUNER_TEA5761 case 0x10: - if (tea5761_autodetection(&t->i2c) != EINVAL) { + if (tea5761_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) { t->type = TUNER_TEA5761; t->mode_mask = T_RADIO; t->mode = T_STANDBY; @@ -544,7 +659,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, case 0x4b: /* If chip is not tda8290, don't register. since it can be tda9887*/ - if (tda8290_probe(&t->i2c) == 0) { + if (tda8290_probe(t->i2c.adapter, t->i2c.addr) == 0) { tuner_dbg("chip at addr %x is a tda8290\n", addr); } else { /* Default is being tda9887 */ @@ -555,7 +670,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, } break; case 0x60: - if (tea5767_autodetection(&t->i2c) != EINVAL) { + if (tea5767_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) { t->type = TUNER_TEA5767; t->mode_mask = T_RADIO; t->mode = T_STANDBY; @@ -644,7 +759,7 @@ static int tuner_detach(struct i2c_client *client) MOD_DEC_USE_COUNT; #endif if (t->ops.release) - t->ops.release(client); + t->ops.release(t); else { kfree(t->priv); #if 0 @@ -672,7 +787,7 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, if (check_mode(t, cmd) == EINVAL) { t->mode = T_STANDBY; if (t->ops.standby) - t->ops.standby (client); + t->ops.standby(t); return EINVAL; } return 0; @@ -700,6 +815,7 @@ static inline int check_v4l2(struct tuner *t) static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct tuner *t = i2c_get_clientdata(client); + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; if (tuner_debug>1) v4l_i2c_print_ioctl(&(t->i2c),cmd); @@ -727,7 +843,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; t->mode = T_STANDBY; if (t->ops.standby) - t->ops.standby (client); + t->ops.standby(t); break; #ifdef CONFIG_VIDEO_V4L1 case VIDIOCSAUDIO: @@ -786,16 +902,27 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; if (V4L2_TUNER_RADIO == t->mode) { - if (t->ops.has_signal) - vt->signal = t->ops.has_signal(client); - if (t->ops.is_stereo) { - if (t->ops.is_stereo(client)) - vt->flags |= - VIDEO_TUNER_STEREO_ON; + if (fe_tuner_ops->get_status) { + u32 tuner_status; + + fe_tuner_ops->get_status(&t->fe, &tuner_status); + if (tuner_status & TUNER_STATUS_STEREO) + vt->flags |= VIDEO_TUNER_STEREO_ON; else - vt->flags &= - ~VIDEO_TUNER_STEREO_ON; + vt->flags &= ~VIDEO_TUNER_STEREO_ON; + } else { + if (t->ops.is_stereo) { + if (t->ops.is_stereo(t)) + vt->flags |= + VIDEO_TUNER_STEREO_ON; + else + vt->flags &= + ~VIDEO_TUNER_STEREO_ON; + } } + if (t->ops.has_signal) + vt->signal = t->ops.has_signal(t); + vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */ vt->rangelow = radio_range[0] * 16000; @@ -817,9 +944,17 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) if (check_v4l2(t) == EINVAL) return 0; - if (V4L2_TUNER_RADIO == t->mode && t->ops.is_stereo) - va->mode = t->ops.is_stereo(client) - ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; + if (V4L2_TUNER_RADIO == t->mode) { + if (fe_tuner_ops->get_status) { + u32 tuner_status; + + fe_tuner_ops->get_status(&t->fe, &tuner_status); + va->mode = (tuner_status & TUNER_STATUS_STEREO) + ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; + } else if (t->ops.is_stereo) + va->mode = t->ops.is_stereo(t) + ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; + } return 0; } #endif @@ -870,6 +1005,15 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; switch_v4l2(); f->type = t->mode; + if (fe_tuner_ops->get_frequency) { + u32 abs_freq; + + fe_tuner_ops->get_frequency(&t->fe, &abs_freq); + f->frequency = (V4L2_TUNER_RADIO == t->mode) ? + (abs_freq * 2 + 125/2) / 125 : + (abs_freq + 62500/2) / 62500; + break; + } f->frequency = (V4L2_TUNER_RADIO == t->mode) ? t->radio_freq : t->tv_freq; break; @@ -884,7 +1028,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) tuner->type = t->mode; if (t->ops.get_afc) - tuner->afc=t->ops.get_afc(client); + tuner->afc=t->ops.get_afc(t); if (t->mode == V4L2_TUNER_ANALOG_TV) tuner->capability |= V4L2_TUNER_CAP_NORM; if (t->mode != V4L2_TUNER_RADIO) { @@ -894,16 +1038,22 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) } /* radio mode */ - if (t->ops.has_signal) - tuner->signal = t->ops.has_signal(client); - tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; - if (t->ops.is_stereo) { - tuner->rxsubchans = t->ops.is_stereo(client) ? + if (fe_tuner_ops->get_status) { + u32 tuner_status; + + fe_tuner_ops->get_status(&t->fe, &tuner_status); + tuner->rxsubchans = (tuner_status & TUNER_STATUS_STEREO) ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; + } else { + if (t->ops.is_stereo) { + tuner->rxsubchans = t->ops.is_stereo(t) ? + V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; + } } - + if (t->ops.has_signal) + tuner->signal = t->ops.has_signal(t); tuner->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; tuner->audmode = t->audmode; @@ -929,7 +1079,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) } case VIDIOC_LOG_STATUS: if (t->ops.tuner_status) - t->ops.tuner_status(client); + t->ops.tuner_status(t); break; } |