Path: blob/master/drivers/media/common/tuners/tda9887.c
15112 views
#include <linux/module.h>1#include <linux/kernel.h>2#include <linux/i2c.h>3#include <linux/types.h>4#include <linux/init.h>5#include <linux/errno.h>6#include <linux/delay.h>7#include <linux/videodev2.h>8#include <media/v4l2-common.h>9#include <media/tuner.h>10#include "tuner-i2c.h"11#include "tda9887.h"121314/* Chips:15TDA9885 (PAL, NTSC)16TDA9886 (PAL, SECAM, NTSC)17TDA9887 (PAL, SECAM, NTSC, FM Radio)1819Used as part of several tuners20*/2122static int debug;23module_param(debug, int, 0644);24MODULE_PARM_DESC(debug, "enable verbose debug messages");2526static DEFINE_MUTEX(tda9887_list_mutex);27static LIST_HEAD(hybrid_tuner_instance_list);2829struct tda9887_priv {30struct tuner_i2c_props i2c_props;31struct list_head hybrid_tuner_instance_list;3233unsigned char data[4];34unsigned int config;35unsigned int mode;36unsigned int audmode;37v4l2_std_id std;3839bool standby;40};4142/* ---------------------------------------------------------------------- */4344#define UNSET (-1U)4546struct tvnorm {47v4l2_std_id std;48char *name;49unsigned char b;50unsigned char c;51unsigned char e;52};5354/* ---------------------------------------------------------------------- */5556//57// TDA defines58//5960//// first reg (b)61#define cVideoTrapBypassOFF 0x00 // bit b062#define cVideoTrapBypassON 0x01 // bit b06364#define cAutoMuteFmInactive 0x00 // bit b165#define cAutoMuteFmActive 0x02 // bit b16667#define cIntercarrier 0x00 // bit b268#define cQSS 0x04 // bit b26970#define cPositiveAmTV 0x00 // bit b3:471#define cFmRadio 0x08 // bit b3:472#define cNegativeFmTV 0x10 // bit b3:4737475#define cForcedMuteAudioON 0x20 // bit b576#define cForcedMuteAudioOFF 0x00 // bit b57778#define cOutputPort1Active 0x00 // bit b679#define cOutputPort1Inactive 0x40 // bit b68081#define cOutputPort2Active 0x00 // bit b782#define cOutputPort2Inactive 0x80 // bit b7838485//// second reg (c)86#define cDeemphasisOFF 0x00 // bit c587#define cDeemphasisON 0x20 // bit c58889#define cDeemphasis75 0x00 // bit c690#define cDeemphasis50 0x40 // bit c69192#define cAudioGain0 0x00 // bit c793#define cAudioGain6 0x80 // bit c79495#define cTopMask 0x1f // bit c0:496#define cTopDefault 0x10 // bit c0:49798//// third reg (e)99#define cAudioIF_4_5 0x00 // bit e0:1100#define cAudioIF_5_5 0x01 // bit e0:1101#define cAudioIF_6_0 0x02 // bit e0:1102#define cAudioIF_6_5 0x03 // bit e0:1103104105#define cVideoIFMask 0x1c // bit e2:4106/* Video IF selection in TV Mode (bit B3=0) */107#define cVideoIF_58_75 0x00 // bit e2:4108#define cVideoIF_45_75 0x04 // bit e2:4109#define cVideoIF_38_90 0x08 // bit e2:4110#define cVideoIF_38_00 0x0C // bit e2:4111#define cVideoIF_33_90 0x10 // bit e2:4112#define cVideoIF_33_40 0x14 // bit e2:4113#define cRadioIF_45_75 0x18 // bit e2:4114#define cRadioIF_38_90 0x1C // bit e2:4115116/* IF1 selection in Radio Mode (bit B3=1) */117#define cRadioIF_33_30 0x00 // bit e2,4 (also 0x10,0x14)118#define cRadioIF_41_30 0x04 // bit e2,4119120/* Output of AFC pin in radio mode when bit E7=1 */121#define cRadioAGC_SIF 0x00 // bit e3122#define cRadioAGC_FM 0x08 // bit e3123124#define cTunerGainNormal 0x00 // bit e5125#define cTunerGainLow 0x20 // bit e5126127#define cGating_18 0x00 // bit e6128#define cGating_36 0x40 // bit e6129130#define cAgcOutON 0x80 // bit e7131#define cAgcOutOFF 0x00 // bit e7132133/* ---------------------------------------------------------------------- */134135static struct tvnorm tvnorms[] = {136{137.std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N,138.name = "PAL-BGHN",139.b = ( cNegativeFmTV |140cQSS ),141.c = ( cDeemphasisON |142cDeemphasis50 |143cTopDefault),144.e = ( cGating_36 |145cAudioIF_5_5 |146cVideoIF_38_90 ),147},{148.std = V4L2_STD_PAL_I,149.name = "PAL-I",150.b = ( cNegativeFmTV |151cQSS ),152.c = ( cDeemphasisON |153cDeemphasis50 |154cTopDefault),155.e = ( cGating_36 |156cAudioIF_6_0 |157cVideoIF_38_90 ),158},{159.std = V4L2_STD_PAL_DK,160.name = "PAL-DK",161.b = ( cNegativeFmTV |162cQSS ),163.c = ( cDeemphasisON |164cDeemphasis50 |165cTopDefault),166.e = ( cGating_36 |167cAudioIF_6_5 |168cVideoIF_38_90 ),169},{170.std = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc,171.name = "PAL-M/Nc",172.b = ( cNegativeFmTV |173cQSS ),174.c = ( cDeemphasisON |175cDeemphasis75 |176cTopDefault),177.e = ( cGating_36 |178cAudioIF_4_5 |179cVideoIF_45_75 ),180},{181.std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H,182.name = "SECAM-BGH",183.b = ( cNegativeFmTV |184cQSS ),185.c = ( cTopDefault),186.e = ( cAudioIF_5_5 |187cVideoIF_38_90 ),188},{189.std = V4L2_STD_SECAM_L,190.name = "SECAM-L",191.b = ( cPositiveAmTV |192cQSS ),193.c = ( cTopDefault),194.e = ( cGating_36 |195cAudioIF_6_5 |196cVideoIF_38_90 ),197},{198.std = V4L2_STD_SECAM_LC,199.name = "SECAM-L'",200.b = ( cOutputPort2Inactive |201cPositiveAmTV |202cQSS ),203.c = ( cTopDefault),204.e = ( cGating_36 |205cAudioIF_6_5 |206cVideoIF_33_90 ),207},{208.std = V4L2_STD_SECAM_DK,209.name = "SECAM-DK",210.b = ( cNegativeFmTV |211cQSS ),212.c = ( cDeemphasisON |213cDeemphasis50 |214cTopDefault),215.e = ( cGating_36 |216cAudioIF_6_5 |217cVideoIF_38_90 ),218},{219.std = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,220.name = "NTSC-M",221.b = ( cNegativeFmTV |222cQSS ),223.c = ( cDeemphasisON |224cDeemphasis75 |225cTopDefault),226.e = ( cGating_36 |227cAudioIF_4_5 |228cVideoIF_45_75 ),229},{230.std = V4L2_STD_NTSC_M_JP,231.name = "NTSC-M-JP",232.b = ( cNegativeFmTV |233cQSS ),234.c = ( cDeemphasisON |235cDeemphasis50 |236cTopDefault),237.e = ( cGating_36 |238cAudioIF_4_5 |239cVideoIF_58_75 ),240}241};242243static struct tvnorm radio_stereo = {244.name = "Radio Stereo",245.b = ( cFmRadio |246cQSS ),247.c = ( cDeemphasisOFF |248cAudioGain6 |249cTopDefault),250.e = ( cTunerGainLow |251cAudioIF_5_5 |252cRadioIF_38_90 ),253};254255static struct tvnorm radio_mono = {256.name = "Radio Mono",257.b = ( cFmRadio |258cQSS ),259.c = ( cDeemphasisON |260cDeemphasis75 |261cTopDefault),262.e = ( cTunerGainLow |263cAudioIF_5_5 |264cRadioIF_38_90 ),265};266267/* ---------------------------------------------------------------------- */268269static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf)270{271struct tda9887_priv *priv = fe->analog_demod_priv;272273static char *afc[16] = {274"- 12.5 kHz",275"- 37.5 kHz",276"- 62.5 kHz",277"- 87.5 kHz",278"-112.5 kHz",279"-137.5 kHz",280"-162.5 kHz",281"-187.5 kHz [min]",282"+187.5 kHz [max]",283"+162.5 kHz",284"+137.5 kHz",285"+112.5 kHz",286"+ 87.5 kHz",287"+ 62.5 kHz",288"+ 37.5 kHz",289"+ 12.5 kHz",290};291tuner_info("read: 0x%2x\n", buf[0]);292tuner_info(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");293tuner_info(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]);294tuner_info(" fmif level : %s\n", (buf[0] & 0x20) ? "high" : "low");295tuner_info(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out");296tuner_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low");297}298299static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf)300{301struct tda9887_priv *priv = fe->analog_demod_priv;302303static char *sound[4] = {304"AM/TV",305"FM/radio",306"FM/TV",307"FM/radio"308};309static char *adjust[32] = {310"-16", "-15", "-14", "-13", "-12", "-11", "-10", "-9",311"-8", "-7", "-6", "-5", "-4", "-3", "-2", "-1",312"0", "+1", "+2", "+3", "+4", "+5", "+6", "+7",313"+8", "+9", "+10", "+11", "+12", "+13", "+14", "+15"314};315static char *deemph[4] = {316"no", "no", "75", "50"317};318static char *carrier[4] = {319"4.5 MHz",320"5.5 MHz",321"6.0 MHz",322"6.5 MHz / AM"323};324static char *vif[8] = {325"58.75 MHz",326"45.75 MHz",327"38.9 MHz",328"38.0 MHz",329"33.9 MHz",330"33.4 MHz",331"45.75 MHz + pin13",332"38.9 MHz + pin13",333};334static char *rif[4] = {335"44 MHz",336"52 MHz",337"52 MHz",338"44 MHz",339};340341tuner_info("write: byte B 0x%02x\n", buf[1]);342tuner_info(" B0 video mode : %s\n",343(buf[1] & 0x01) ? "video trap" : "sound trap");344tuner_info(" B1 auto mute fm : %s\n",345(buf[1] & 0x02) ? "yes" : "no");346tuner_info(" B2 carrier mode : %s\n",347(buf[1] & 0x04) ? "QSS" : "Intercarrier");348tuner_info(" B3-4 tv sound/radio : %s\n",349sound[(buf[1] & 0x18) >> 3]);350tuner_info(" B5 force mute audio: %s\n",351(buf[1] & 0x20) ? "yes" : "no");352tuner_info(" B6 output port 1 : %s\n",353(buf[1] & 0x40) ? "high (inactive)" : "low (active)");354tuner_info(" B7 output port 2 : %s\n",355(buf[1] & 0x80) ? "high (inactive)" : "low (active)");356357tuner_info("write: byte C 0x%02x\n", buf[2]);358tuner_info(" C0-4 top adjustment : %s dB\n",359adjust[buf[2] & 0x1f]);360tuner_info(" C5-6 de-emphasis : %s\n",361deemph[(buf[2] & 0x60) >> 5]);362tuner_info(" C7 audio gain : %s\n",363(buf[2] & 0x80) ? "-6" : "0");364365tuner_info("write: byte E 0x%02x\n", buf[3]);366tuner_info(" E0-1 sound carrier : %s\n",367carrier[(buf[3] & 0x03)]);368tuner_info(" E6 l pll gating : %s\n",369(buf[3] & 0x40) ? "36" : "13");370371if (buf[1] & 0x08) {372/* radio */373tuner_info(" E2-4 video if : %s\n",374rif[(buf[3] & 0x0c) >> 2]);375tuner_info(" E7 vif agc output : %s\n",376(buf[3] & 0x80)377? ((buf[3] & 0x10) ? "fm-agc radio" :378"sif-agc radio")379: "fm radio carrier afc");380} else {381/* video */382tuner_info(" E2-4 video if : %s\n",383vif[(buf[3] & 0x1c) >> 2]);384tuner_info(" E5 tuner gain : %s\n",385(buf[3] & 0x80)386? ((buf[3] & 0x20) ? "external" : "normal")387: ((buf[3] & 0x20) ? "minimum" : "normal"));388tuner_info(" E7 vif agc output : %s\n",389(buf[3] & 0x80) ? ((buf[3] & 0x20)390? "pin3 port, pin22 vif agc out"391: "pin22 port, pin3 vif acg ext in")392: "pin3+pin22 port");393}394tuner_info("--\n");395}396397/* ---------------------------------------------------------------------- */398399static int tda9887_set_tvnorm(struct dvb_frontend *fe)400{401struct tda9887_priv *priv = fe->analog_demod_priv;402struct tvnorm *norm = NULL;403char *buf = priv->data;404int i;405406if (priv->mode == V4L2_TUNER_RADIO) {407if (priv->audmode == V4L2_TUNER_MODE_MONO)408norm = &radio_mono;409else410norm = &radio_stereo;411} else {412for (i = 0; i < ARRAY_SIZE(tvnorms); i++) {413if (tvnorms[i].std & priv->std) {414norm = tvnorms+i;415break;416}417}418}419if (NULL == norm) {420tuner_dbg("Unsupported tvnorm entry - audio muted\n");421return -1;422}423424tuner_dbg("configure for: %s\n", norm->name);425buf[1] = norm->b;426buf[2] = norm->c;427buf[3] = norm->e;428return 0;429}430431static unsigned int port1 = UNSET;432static unsigned int port2 = UNSET;433static unsigned int qss = UNSET;434static unsigned int adjust = UNSET;435436module_param(port1, int, 0644);437module_param(port2, int, 0644);438module_param(qss, int, 0644);439module_param(adjust, int, 0644);440441static int tda9887_set_insmod(struct dvb_frontend *fe)442{443struct tda9887_priv *priv = fe->analog_demod_priv;444char *buf = priv->data;445446if (UNSET != port1) {447if (port1)448buf[1] |= cOutputPort1Inactive;449else450buf[1] &= ~cOutputPort1Inactive;451}452if (UNSET != port2) {453if (port2)454buf[1] |= cOutputPort2Inactive;455else456buf[1] &= ~cOutputPort2Inactive;457}458459if (UNSET != qss) {460if (qss)461buf[1] |= cQSS;462else463buf[1] &= ~cQSS;464}465466if (adjust < 0x20) {467buf[2] &= ~cTopMask;468buf[2] |= adjust;469}470return 0;471}472473static int tda9887_do_config(struct dvb_frontend *fe)474{475struct tda9887_priv *priv = fe->analog_demod_priv;476char *buf = priv->data;477478if (priv->config & TDA9887_PORT1_ACTIVE)479buf[1] &= ~cOutputPort1Inactive;480if (priv->config & TDA9887_PORT1_INACTIVE)481buf[1] |= cOutputPort1Inactive;482if (priv->config & TDA9887_PORT2_ACTIVE)483buf[1] &= ~cOutputPort2Inactive;484if (priv->config & TDA9887_PORT2_INACTIVE)485buf[1] |= cOutputPort2Inactive;486487if (priv->config & TDA9887_QSS)488buf[1] |= cQSS;489if (priv->config & TDA9887_INTERCARRIER)490buf[1] &= ~cQSS;491492if (priv->config & TDA9887_AUTOMUTE)493buf[1] |= cAutoMuteFmActive;494if (priv->config & TDA9887_DEEMPHASIS_MASK) {495buf[2] &= ~0x60;496switch (priv->config & TDA9887_DEEMPHASIS_MASK) {497case TDA9887_DEEMPHASIS_NONE:498buf[2] |= cDeemphasisOFF;499break;500case TDA9887_DEEMPHASIS_50:501buf[2] |= cDeemphasisON | cDeemphasis50;502break;503case TDA9887_DEEMPHASIS_75:504buf[2] |= cDeemphasisON | cDeemphasis75;505break;506}507}508if (priv->config & TDA9887_TOP_SET) {509buf[2] &= ~cTopMask;510buf[2] |= (priv->config >> 8) & cTopMask;511}512if ((priv->config & TDA9887_INTERCARRIER_NTSC) &&513(priv->std & V4L2_STD_NTSC))514buf[1] &= ~cQSS;515if (priv->config & TDA9887_GATING_18)516buf[3] &= ~cGating_36;517518if (priv->mode == V4L2_TUNER_RADIO) {519if (priv->config & TDA9887_RIF_41_3) {520buf[3] &= ~cVideoIFMask;521buf[3] |= cRadioIF_41_30;522}523if (priv->config & TDA9887_GAIN_NORMAL)524buf[3] &= ~cTunerGainLow;525}526527return 0;528}529530/* ---------------------------------------------------------------------- */531532static int tda9887_status(struct dvb_frontend *fe)533{534struct tda9887_priv *priv = fe->analog_demod_priv;535unsigned char buf[1];536int rc;537538memset(buf,0,sizeof(buf));539if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1)))540tuner_info("i2c i/o error: rc == %d (should be 1)\n", rc);541dump_read_message(fe, buf);542return 0;543}544545static void tda9887_configure(struct dvb_frontend *fe)546{547struct tda9887_priv *priv = fe->analog_demod_priv;548int rc;549550memset(priv->data,0,sizeof(priv->data));551tda9887_set_tvnorm(fe);552553/* A note on the port settings:554These settings tend to depend on the specifics of the board.555By default they are set to inactive (bit value 1) by this driver,556overwriting any changes made by the tvnorm. This means that it557is the responsibility of the module using the tda9887 to set558these values in case of changes in the tvnorm.559In many cases port 2 should be made active (0) when selecting560SECAM-L, and port 2 should remain inactive (1) for SECAM-L'.561562For the other standards the tda9887 application note says that563the ports should be set to active (0), but, again, that may564differ depending on the precise hardware configuration.565*/566priv->data[1] |= cOutputPort1Inactive;567priv->data[1] |= cOutputPort2Inactive;568569tda9887_do_config(fe);570tda9887_set_insmod(fe);571572if (priv->standby)573priv->data[1] |= cForcedMuteAudioON;574575tuner_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",576priv->data[1], priv->data[2], priv->data[3]);577if (debug > 1)578dump_write_message(fe, priv->data);579580if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4)))581tuner_info("i2c i/o error: rc == %d (should be 4)\n", rc);582583if (debug > 2) {584msleep_interruptible(1000);585tda9887_status(fe);586}587}588589/* ---------------------------------------------------------------------- */590591static void tda9887_tuner_status(struct dvb_frontend *fe)592{593struct tda9887_priv *priv = fe->analog_demod_priv;594tuner_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n",595priv->data[1], priv->data[2], priv->data[3]);596}597598static int tda9887_get_afc(struct dvb_frontend *fe)599{600struct tda9887_priv *priv = fe->analog_demod_priv;601static int AFC_BITS_2_kHz[] = {602-12500, -37500, -62500, -97500,603-112500, -137500, -162500, -187500,604187500, 162500, 137500, 112500,60597500 , 62500, 37500 , 12500606};607int afc=0;608__u8 reg = 0;609610if (1 == tuner_i2c_xfer_recv(&priv->i2c_props,®,1))611afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];612613return afc;614}615616static void tda9887_standby(struct dvb_frontend *fe)617{618struct tda9887_priv *priv = fe->analog_demod_priv;619620priv->standby = true;621622tda9887_configure(fe);623}624625static void tda9887_set_params(struct dvb_frontend *fe,626struct analog_parameters *params)627{628struct tda9887_priv *priv = fe->analog_demod_priv;629630priv->standby = false;631priv->mode = params->mode;632priv->audmode = params->audmode;633priv->std = params->std;634tda9887_configure(fe);635}636637static int tda9887_set_config(struct dvb_frontend *fe, void *priv_cfg)638{639struct tda9887_priv *priv = fe->analog_demod_priv;640641priv->config = *(unsigned int *)priv_cfg;642tda9887_configure(fe);643644return 0;645}646647static void tda9887_release(struct dvb_frontend *fe)648{649struct tda9887_priv *priv = fe->analog_demod_priv;650651mutex_lock(&tda9887_list_mutex);652653if (priv)654hybrid_tuner_release_state(priv);655656mutex_unlock(&tda9887_list_mutex);657658fe->analog_demod_priv = NULL;659}660661static struct analog_demod_ops tda9887_ops = {662.info = {663.name = "tda9887",664},665.set_params = tda9887_set_params,666.standby = tda9887_standby,667.tuner_status = tda9887_tuner_status,668.get_afc = tda9887_get_afc,669.release = tda9887_release,670.set_config = tda9887_set_config,671};672673struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,674struct i2c_adapter *i2c_adap,675u8 i2c_addr)676{677struct tda9887_priv *priv = NULL;678int instance;679680mutex_lock(&tda9887_list_mutex);681682instance = hybrid_tuner_request_state(struct tda9887_priv, priv,683hybrid_tuner_instance_list,684i2c_adap, i2c_addr, "tda9887");685switch (instance) {686case 0:687mutex_unlock(&tda9887_list_mutex);688return NULL;689case 1:690fe->analog_demod_priv = priv;691priv->standby = true;692tuner_info("tda988[5/6/7] found\n");693break;694default:695fe->analog_demod_priv = priv;696break;697}698699mutex_unlock(&tda9887_list_mutex);700701memcpy(&fe->ops.analog_ops, &tda9887_ops,702sizeof(struct analog_demod_ops));703704return fe;705}706EXPORT_SYMBOL_GPL(tda9887_attach);707708MODULE_LICENSE("GPL");709710/*711* Overrides for Emacs so that we follow Linus's tabbing style.712* ---------------------------------------------------------------------------713* Local variables:714* c-basic-offset: 8715* End:716*/717718719