diff options
Diffstat (limited to 'drivers/media/video/tda9887.c')
-rw-r--r-- | drivers/media/video/tda9887.c | 305 |
1 files changed, 175 insertions, 130 deletions
diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index be5387f11af..106c93b8203 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -9,7 +9,8 @@ #include <linux/videodev.h> #include <media/v4l2-common.h> #include <media/tuner.h> -#include "tuner-driver.h" +#include "tuner-i2c.h" +#include "tda9887.h" /* Chips: @@ -20,18 +21,20 @@ Used as part of several tuners */ -#define tda9887_info(fmt, arg...) do {\ - printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \ - i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) -#define tda9887_dbg(fmt, arg...) do {\ - if (tuner_debug) \ - printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \ - i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +#define PREFIX "tda9887" struct tda9887_priv { struct tuner_i2c_props i2c_props; unsigned char data[4]; + unsigned int config; + unsigned int mode; + unsigned int audmode; + v4l2_std_id std; }; /* ---------------------------------------------------------------------- */ @@ -262,8 +265,10 @@ static struct tvnorm radio_mono = { /* ---------------------------------------------------------------------- */ -static void dump_read_message(struct tuner *t, unsigned char *buf) +static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf) { + struct tda9887_priv *priv = fe->analog_demod_priv; + static char *afc[16] = { "- 12.5 kHz", "- 37.5 kHz", @@ -282,16 +287,18 @@ static void dump_read_message(struct tuner *t, unsigned char *buf) "+ 37.5 kHz", "+ 12.5 kHz", }; - tda9887_info("read: 0x%2x\n", buf[0]); - tda9887_info(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no"); - tda9887_info(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]); - tda9887_info(" fmif level : %s\n", (buf[0] & 0x20) ? "high" : "low"); - tda9887_info(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out"); - tda9887_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low"); + tuner_info("read: 0x%2x\n", buf[0]); + tuner_info(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no"); + tuner_info(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]); + tuner_info(" fmif level : %s\n", (buf[0] & 0x20) ? "high" : "low"); + tuner_info(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out"); + tuner_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low"); } -static void dump_write_message(struct tuner *t, unsigned char *buf) +static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf) { + struct tda9887_priv *priv = fe->analog_demod_priv; + static char *sound[4] = { "AM/TV", "FM/radio", @@ -330,86 +337,90 @@ static void dump_write_message(struct tuner *t, unsigned char *buf) "44 MHz", }; - tda9887_info("write: byte B 0x%02x\n",buf[1]); - tda9887_info(" B0 video mode : %s\n", - (buf[1] & 0x01) ? "video trap" : "sound trap"); - tda9887_info(" B1 auto mute fm : %s\n", - (buf[1] & 0x02) ? "yes" : "no"); - tda9887_info(" B2 carrier mode : %s\n", - (buf[1] & 0x04) ? "QSS" : "Intercarrier"); - tda9887_info(" B3-4 tv sound/radio : %s\n", - sound[(buf[1] & 0x18) >> 3]); - tda9887_info(" B5 force mute audio: %s\n", - (buf[1] & 0x20) ? "yes" : "no"); - tda9887_info(" B6 output port 1 : %s\n", - (buf[1] & 0x40) ? "high (inactive)" : "low (active)"); - tda9887_info(" B7 output port 2 : %s\n", - (buf[1] & 0x80) ? "high (inactive)" : "low (active)"); - - tda9887_info("write: byte C 0x%02x\n",buf[2]); - tda9887_info(" C0-4 top adjustment : %s dB\n", adjust[buf[2] & 0x1f]); - tda9887_info(" C5-6 de-emphasis : %s\n", deemph[(buf[2] & 0x60) >> 5]); - tda9887_info(" C7 audio gain : %s\n", - (buf[2] & 0x80) ? "-6" : "0"); - - tda9887_info("write: byte E 0x%02x\n",buf[3]); - tda9887_info(" E0-1 sound carrier : %s\n", - carrier[(buf[3] & 0x03)]); - tda9887_info(" E6 l pll gating : %s\n", - (buf[3] & 0x40) ? "36" : "13"); + tuner_info("write: byte B 0x%02x\n", buf[1]); + tuner_info(" B0 video mode : %s\n", + (buf[1] & 0x01) ? "video trap" : "sound trap"); + tuner_info(" B1 auto mute fm : %s\n", + (buf[1] & 0x02) ? "yes" : "no"); + tuner_info(" B2 carrier mode : %s\n", + (buf[1] & 0x04) ? "QSS" : "Intercarrier"); + tuner_info(" B3-4 tv sound/radio : %s\n", + sound[(buf[1] & 0x18) >> 3]); + tuner_info(" B5 force mute audio: %s\n", + (buf[1] & 0x20) ? "yes" : "no"); + tuner_info(" B6 output port 1 : %s\n", + (buf[1] & 0x40) ? "high (inactive)" : "low (active)"); + tuner_info(" B7 output port 2 : %s\n", + (buf[1] & 0x80) ? "high (inactive)" : "low (active)"); + + tuner_info("write: byte C 0x%02x\n", buf[2]); + tuner_info(" C0-4 top adjustment : %s dB\n", + adjust[buf[2] & 0x1f]); + tuner_info(" C5-6 de-emphasis : %s\n", + deemph[(buf[2] & 0x60) >> 5]); + tuner_info(" C7 audio gain : %s\n", + (buf[2] & 0x80) ? "-6" : "0"); + + tuner_info("write: byte E 0x%02x\n", buf[3]); + tuner_info(" E0-1 sound carrier : %s\n", + carrier[(buf[3] & 0x03)]); + tuner_info(" E6 l pll gating : %s\n", + (buf[3] & 0x40) ? "36" : "13"); if (buf[1] & 0x08) { /* radio */ - tda9887_info(" E2-4 video if : %s\n", - rif[(buf[3] & 0x0c) >> 2]); - tda9887_info(" E7 vif agc output : %s\n", - (buf[3] & 0x80) - ? ((buf[3] & 0x10) ? "fm-agc radio" : "sif-agc radio") - : "fm radio carrier afc"); + tuner_info(" E2-4 video if : %s\n", + rif[(buf[3] & 0x0c) >> 2]); + tuner_info(" E7 vif agc output : %s\n", + (buf[3] & 0x80) + ? ((buf[3] & 0x10) ? "fm-agc radio" : + "sif-agc radio") + : "fm radio carrier afc"); } else { /* video */ - tda9887_info(" E2-4 video if : %s\n", - vif[(buf[3] & 0x1c) >> 2]); - tda9887_info(" E5 tuner gain : %s\n", - (buf[3] & 0x80) - ? ((buf[3] & 0x20) ? "external" : "normal") - : ((buf[3] & 0x20) ? "minimum" : "normal")); - tda9887_info(" E7 vif agc output : %s\n", - (buf[3] & 0x80) - ? ((buf[3] & 0x20) - ? "pin3 port, pin22 vif agc out" - : "pin22 port, pin3 vif acg ext in") - : "pin3+pin22 port"); + tuner_info(" E2-4 video if : %s\n", + vif[(buf[3] & 0x1c) >> 2]); + tuner_info(" E5 tuner gain : %s\n", + (buf[3] & 0x80) + ? ((buf[3] & 0x20) ? "external" : "normal") + : ((buf[3] & 0x20) ? "minimum" : "normal")); + tuner_info(" E7 vif agc output : %s\n", + (buf[3] & 0x80) ? ((buf[3] & 0x20) + ? "pin3 port, pin22 vif agc out" + : "pin22 port, pin3 vif acg ext in") + : "pin3+pin22 port"); } - tda9887_info("--\n"); + tuner_info("--\n"); } /* ---------------------------------------------------------------------- */ -static int tda9887_set_tvnorm(struct tuner *t, char *buf) +static int tda9887_set_tvnorm(struct dvb_frontend *fe) { + struct tda9887_priv *priv = fe->analog_demod_priv; struct tvnorm *norm = NULL; + char *buf = priv->data; int i; - if (t->mode == V4L2_TUNER_RADIO) { - if (t->audmode == V4L2_TUNER_MODE_MONO) + if (priv->mode == V4L2_TUNER_RADIO) { + if (priv->audmode == V4L2_TUNER_MODE_MONO) norm = &radio_mono; else norm = &radio_stereo; } else { for (i = 0; i < ARRAY_SIZE(tvnorms); i++) { - if (tvnorms[i].std & t->std) { + if (tvnorms[i].std & priv->std) { norm = tvnorms+i; break; } } } if (NULL == norm) { - tda9887_dbg("Unsupported tvnorm entry - audio muted\n"); + tuner_dbg("Unsupported tvnorm entry - audio muted\n"); return -1; } - tda9887_dbg("configure for: %s\n",norm->name); + tuner_dbg("configure for: %s\n", norm->name); buf[1] = norm->b; buf[2] = norm->c; buf[3] = norm->e; @@ -426,8 +437,11 @@ module_param(port2, int, 0644); module_param(qss, int, 0644); module_param(adjust, int, 0644); -static int tda9887_set_insmod(struct tuner *t, char *buf) +static int tda9887_set_insmod(struct dvb_frontend *fe) { + struct tda9887_priv *priv = fe->analog_demod_priv; + char *buf = priv->data; + if (UNSET != port1) { if (port1) buf[1] |= cOutputPort1Inactive; @@ -455,27 +469,30 @@ static int tda9887_set_insmod(struct tuner *t, char *buf) return 0; } -static int tda9887_set_config(struct tuner *t, char *buf) +static int tda9887_do_config(struct dvb_frontend *fe) { - if (t->tda9887_config & TDA9887_PORT1_ACTIVE) + struct tda9887_priv *priv = fe->analog_demod_priv; + char *buf = priv->data; + + if (priv->config & TDA9887_PORT1_ACTIVE) buf[1] &= ~cOutputPort1Inactive; - if (t->tda9887_config & TDA9887_PORT1_INACTIVE) + if (priv->config & TDA9887_PORT1_INACTIVE) buf[1] |= cOutputPort1Inactive; - if (t->tda9887_config & TDA9887_PORT2_ACTIVE) + if (priv->config & TDA9887_PORT2_ACTIVE) buf[1] &= ~cOutputPort2Inactive; - if (t->tda9887_config & TDA9887_PORT2_INACTIVE) + if (priv->config & TDA9887_PORT2_INACTIVE) buf[1] |= cOutputPort2Inactive; - if (t->tda9887_config & TDA9887_QSS) + if (priv->config & TDA9887_QSS) buf[1] |= cQSS; - if (t->tda9887_config & TDA9887_INTERCARRIER) + if (priv->config & TDA9887_INTERCARRIER) buf[1] &= ~cQSS; - if (t->tda9887_config & TDA9887_AUTOMUTE) + if (priv->config & TDA9887_AUTOMUTE) buf[1] |= cAutoMuteFmActive; - if (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) { + if (priv->config & TDA9887_DEEMPHASIS_MASK) { buf[2] &= ~0x60; - switch (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) { + switch (priv->config & TDA9887_DEEMPHASIS_MASK) { case TDA9887_DEEMPHASIS_NONE: buf[2] |= cDeemphasisOFF; break; @@ -487,21 +504,22 @@ static int tda9887_set_config(struct tuner *t, char *buf) break; } } - if (t->tda9887_config & TDA9887_TOP_SET) { + if (priv->config & TDA9887_TOP_SET) { buf[2] &= ~cTopMask; - buf[2] |= (t->tda9887_config >> 8) & cTopMask; + buf[2] |= (priv->config >> 8) & cTopMask; } - if ((t->tda9887_config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC)) + if ((priv->config & TDA9887_INTERCARRIER_NTSC) && + (priv->std & V4L2_STD_NTSC)) buf[1] &= ~cQSS; - if (t->tda9887_config & TDA9887_GATING_18) + if (priv->config & TDA9887_GATING_18) buf[3] &= ~cGating_36; - if (t->mode == V4L2_TUNER_RADIO) { - if (t->tda9887_config & TDA9887_RIF_41_3) { + if (priv->mode == V4L2_TUNER_RADIO) { + if (priv->config & TDA9887_RIF_41_3) { buf[3] &= ~cVideoIFMask; buf[3] |= cRadioIF_41_30; } - if (t->tda9887_config & TDA9887_GAIN_NORMAL) + if (priv->config & TDA9887_GAIN_NORMAL) buf[3] &= ~cTunerGainLow; } @@ -510,26 +528,26 @@ static int tda9887_set_config(struct tuner *t, char *buf) /* ---------------------------------------------------------------------- */ -static int tda9887_status(struct tuner *t) +static int tda9887_status(struct dvb_frontend *fe) { - struct tda9887_priv *priv = t->priv; + struct tda9887_priv *priv = fe->analog_demod_priv; unsigned char buf[1]; int rc; memset(buf,0,sizeof(buf)); if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1))) - tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc); - dump_read_message(t, buf); + tuner_info("i2c i/o error: rc == %d (should be 1)\n", rc); + dump_read_message(fe, buf); return 0; } -static void tda9887_configure(struct tuner *t) +static void tda9887_configure(struct dvb_frontend *fe) { - struct tda9887_priv *priv = t->priv; + struct tda9887_priv *priv = fe->analog_demod_priv; int rc; memset(priv->data,0,sizeof(priv->data)); - tda9887_set_tvnorm(t,priv->data); + tda9887_set_tvnorm(fe); /* A note on the port settings: These settings tend to depend on the specifics of the board. @@ -547,38 +565,38 @@ static void tda9887_configure(struct tuner *t) priv->data[1] |= cOutputPort1Inactive; priv->data[1] |= cOutputPort2Inactive; - tda9887_set_config(t,priv->data); - tda9887_set_insmod(t,priv->data); + tda9887_do_config(fe); + tda9887_set_insmod(fe); - if (t->mode == T_STANDBY) { + if (priv->mode == T_STANDBY) priv->data[1] |= cForcedMuteAudioON; - } - tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n", - priv->data[1],priv->data[2],priv->data[3]); - if (tuner_debug > 1) - dump_write_message(t, priv->data); + tuner_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n", + priv->data[1], priv->data[2], priv->data[3]); + if (debug > 1) + dump_write_message(fe, priv->data); if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4))) - tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc); + tuner_info("i2c i/o error: rc == %d (should be 4)\n", rc); - if (tuner_debug > 2) { + if (debug > 2) { msleep_interruptible(1000); - tda9887_status(t); + tda9887_status(fe); } } /* ---------------------------------------------------------------------- */ -static void tda9887_tuner_status(struct tuner *t) +static void tda9887_tuner_status(struct dvb_frontend *fe) { - struct tda9887_priv *priv = t->priv; - tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", priv->data[1], priv->data[2], priv->data[3]); + struct tda9887_priv *priv = fe->analog_demod_priv; + tuner_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", + priv->data[1], priv->data[2], priv->data[3]); } -static int tda9887_get_afc(struct tuner *t) +static int tda9887_get_afc(struct dvb_frontend *fe) { - struct tda9887_priv *priv = t->priv; + struct tda9887_priv *priv = fe->analog_demod_priv; static int AFC_BITS_2_kHz[] = { -12500, -37500, -62500, -97500, -112500, -137500, -162500, -187500, @@ -594,52 +612,79 @@ static int tda9887_get_afc(struct tuner *t) return afc; } -static void tda9887_standby(struct tuner *t) +static void tda9887_standby(struct dvb_frontend *fe) +{ + struct tda9887_priv *priv = fe->analog_demod_priv; + + priv->mode = T_STANDBY; + + tda9887_configure(fe); +} + +static void tda9887_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) { - tda9887_configure(t); + struct tda9887_priv *priv = fe->analog_demod_priv; + + priv->mode = params->mode; + priv->audmode = params->audmode; + priv->std = params->std; + tda9887_configure(fe); } -static void tda9887_set_freq(struct tuner *t, unsigned int freq) +static int tda9887_set_config(struct dvb_frontend *fe, void *priv_cfg) { - tda9887_configure(t); + struct tda9887_priv *priv = fe->analog_demod_priv; + + priv->config = *(unsigned int *)priv_cfg; + tda9887_configure(fe); + + return 0; } -static void tda9887_release(struct tuner *t) +static void tda9887_release(struct dvb_frontend *fe) { - kfree(t->priv); - t->priv = NULL; + kfree(fe->analog_demod_priv); + fe->analog_demod_priv = NULL; } -static struct tuner_operations tda9887_tuner_ops = { - .set_tv_freq = tda9887_set_freq, - .set_radio_freq = tda9887_set_freq, +static struct analog_demod_ops tda9887_ops = { + .info = { + .name = "tda9887", + }, + .set_params = tda9887_set_params, .standby = tda9887_standby, .tuner_status = tda9887_tuner_status, .get_afc = tda9887_get_afc, .release = tda9887_release, + .set_config = tda9887_set_config, }; -int tda9887_tuner_init(struct tuner *t) +struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr) { struct tda9887_priv *priv = NULL; priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL); if (priv == NULL) - return -ENOMEM; - t->priv = priv; - - priv->i2c_props.addr = t->i2c.addr; - priv->i2c_props.adap = t->i2c.adapter; + return NULL; + fe->analog_demod_priv = priv; - strlcpy(t->i2c.name, "tda9887", sizeof(t->i2c.name)); + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; + priv->mode = T_STANDBY; - tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr, - t->i2c.driver->driver.name); + tuner_info("tda988[5/6/7] found\n"); - memcpy(&t->ops, &tda9887_tuner_ops, sizeof(struct tuner_operations)); + memcpy(&fe->ops.analog_ops, &tda9887_ops, + sizeof(struct analog_demod_ops)); - return 0; + return fe; } +EXPORT_SYMBOL_GPL(tda9887_attach); + +MODULE_LICENSE("GPL"); /* * Overrides for Emacs so that we follow Linus's tabbing style. |