X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fmedia%2Fvideo%2Ftda9887.c;h=0d54f6c1982bc9e66adce1d68bc2981b20e09608;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=e46fbdbc46e656db2349eb98d393c30052d4c4de;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index e46fbdbc4..0d54f6c19 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -6,10 +7,11 @@ #include #include #include +#include -#include +#include #include -#include + /* Chips: TDA9885 (PAL, NTSC) @@ -21,36 +23,43 @@ TDA9887 (world), TDA9885 (USA) Note: OP2 of tda988x must be set to 1, else MT2032 is disabled! - KNC One TV-Station RDS (saa7134) + - Hauppauge PVR-150/500 (possibly more) */ /* Addresses to scan */ static unsigned short normal_i2c[] = { + 0x84 >>1, 0x86 >>1, 0x96 >>1, I2C_CLIENT_END, }; -static unsigned short normal_i2c_range[] = {I2C_CLIENT_END,I2C_CLIENT_END}; I2C_CLIENT_INSMOD; /* insmod options */ static unsigned int debug = 0; -MODULE_PARM(debug,"i"); +module_param(debug, int, 0644); MODULE_LICENSE("GPL"); /* ---------------------------------------------------------------------- */ #define UNSET (-1U) -#define PREFIX "tda9885/6/7: " -#define dprintk if (debug) printk +#define tda9887_info(fmt, arg...) do {\ + printk(KERN_INFO "%s %d-%04x: " fmt, t->client.name, \ + i2c_adapter_id(t->client.adapter), t->client.addr , ##arg); } while (0) +#define tda9887_dbg(fmt, arg...) do {\ + if (debug) \ + printk(KERN_INFO "%s %d-%04x: " fmt, t->client.name, \ + i2c_adapter_id(t->client.adapter), t->client.addr , ##arg); } while (0) struct tda9887 { struct i2c_client client; v4l2_std_id std; - unsigned int radio; + enum tuner_mode mode; unsigned int config; - unsigned int pinnacle_id; unsigned int using_v4l2; + unsigned int radio_mode; + unsigned char data[4]; }; struct tvnorm { @@ -105,6 +114,9 @@ static struct i2c_client client_template; #define cAudioGain0 0x00 // bit c7 #define cAudioGain6 0x80 // bit c7 +#define cTopMask 0x1f // bit c0:4 +#define cTopPalSecamDefault 0x14 // bit c0:4 +#define cTopNtscRadioDefault 0x10 // bit c0:4 //// third reg (e) #define cAudioIF_4_5 0x00 // bit e0:1 @@ -136,13 +148,15 @@ static struct i2c_client client_template; static struct tvnorm tvnorms[] = { { - .std = V4L2_STD_PAL_BG, - .name = "PAL-BG", + .std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N, + .name = "PAL-BGHN", .b = ( cNegativeFmTV | cQSS ), .c = ( cDeemphasisON | - cDeemphasis50 ), - .e = ( cAudioIF_5_5 | + cDeemphasis50 | + cTopPalSecamDefault), + .e = ( cGating_36 | + cAudioIF_5_5 | cVideoIF_38_90 ), },{ .std = V4L2_STD_PAL_I, @@ -150,8 +164,10 @@ static struct tvnorm tvnorms[] = { .b = ( cNegativeFmTV | cQSS ), .c = ( cDeemphasisON | - cDeemphasis50 ), - .e = ( cAudioIF_6_0 | + cDeemphasis50 | + cTopPalSecamDefault), + .e = ( cGating_36 | + cAudioIF_6_0 | cVideoIF_38_90 ), },{ .std = V4L2_STD_PAL_DK, @@ -159,70 +175,113 @@ static struct tvnorm tvnorms[] = { .b = ( cNegativeFmTV | cQSS ), .c = ( cDeemphasisON | - cDeemphasis50 ), - .e = ( cAudioIF_6_5 | - cVideoIF_38_00 ), + cDeemphasis50 | + cTopPalSecamDefault), + .e = ( cGating_36 | + cAudioIF_6_5 | + cVideoIF_38_90 ), },{ - .std = V4L2_STD_PAL_M | V4L2_STD_PAL_N, - .name = "PAL-M/N", + .std = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc, + .name = "PAL-M/Nc", .b = ( cNegativeFmTV | cQSS ), .c = ( cDeemphasisON | - cDeemphasis75 ), - .e = ( cAudioIF_4_5 | + cDeemphasis75 | + cTopNtscRadioDefault), + .e = ( cGating_36 | + cAudioIF_4_5 | cVideoIF_45_75 ), + },{ + .std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, + .name = "SECAM-BGH", + .b = ( cPositiveAmTV | + cQSS ), + .c = ( cTopPalSecamDefault), + .e = ( cGating_36 | + cAudioIF_5_5 | + cVideoIF_38_90 ), },{ .std = V4L2_STD_SECAM_L, .name = "SECAM-L", .b = ( cPositiveAmTV | cQSS ), - .e = ( cAudioIF_6_5 | + .c = ( cTopPalSecamDefault), + .e = ( cGating_36 | + cAudioIF_6_5 | cVideoIF_38_90 ), + },{ + .std = V4L2_STD_SECAM_LC, + .name = "SECAM-L'", + .b = ( cOutputPort2Inactive | + cPositiveAmTV | + cQSS ), + .c = ( cTopPalSecamDefault), + .e = ( cGating_36 | + cAudioIF_6_5 | + cVideoIF_33_90 ), },{ .std = V4L2_STD_SECAM_DK, .name = "SECAM-DK", .b = ( cNegativeFmTV | cQSS ), .c = ( cDeemphasisON | - cDeemphasis50 ), - .e = ( cAudioIF_6_5 | - cVideoIF_38_00 ), + cDeemphasis50 | + cTopPalSecamDefault), + .e = ( cGating_36 | + cAudioIF_6_5 | + cVideoIF_38_90 ), },{ - .std = V4L2_STD_NTSC_M, + .std = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR, .name = "NTSC-M", .b = ( cNegativeFmTV | cQSS ), .c = ( cDeemphasisON | - cDeemphasis50 ), + cDeemphasis75 | + cTopNtscRadioDefault), .e = ( cGating_36 | cAudioIF_4_5 | cVideoIF_45_75 ), },{ .std = V4L2_STD_NTSC_M_JP, - .name = "NTSC-JP", + .name = "NTSC-M-JP", .b = ( cNegativeFmTV | cQSS ), .c = ( cDeemphasisON | - cDeemphasis50 ), + cDeemphasis50 | + cTopNtscRadioDefault), .e = ( cGating_36 | cAudioIF_4_5 | cVideoIF_58_75 ), } }; -static struct tvnorm radio = { - .name = "radio", +static struct tvnorm radio_stereo = { + .name = "Radio Stereo", + .b = ( cFmRadio | + cQSS ), + .c = ( cDeemphasisOFF | + cAudioGain6 | + cTopNtscRadioDefault), + .e = ( cTunerGainLow | + cAudioIF_5_5 | + cRadioIF_38_90 ), +}; + +static struct tvnorm radio_mono = { + .name = "Radio Mono", .b = ( cFmRadio | cQSS ), .c = ( cDeemphasisON | - cDeemphasis50 ), - .e = ( cAudioIF_5_5 | + cDeemphasis75 | + cTopNtscRadioDefault), + .e = ( cTunerGainLow | + cAudioIF_5_5 | cRadioIF_38_90 ), }; /* ---------------------------------------------------------------------- */ -static void dump_read_message(unsigned char *buf) +static void dump_read_message(struct tda9887 *t, unsigned char *buf) { static char *afc[16] = { "- 12.5 kHz", @@ -242,14 +301,15 @@ static void dump_read_message(unsigned char *buf) "+ 37.5 kHz", "+ 12.5 kHz", }; - printk(PREFIX "read: 0x%2x\n", buf[0]); - printk(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no"); - printk(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]); - printk(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out"); - printk(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low"); + 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"); } -static void dump_write_message(unsigned char *buf) +static void dump_write_message(struct tda9887 *t, unsigned char *buf) { static char *sound[4] = { "AM/TV", @@ -289,58 +349,58 @@ static void dump_write_message(unsigned char *buf) "44 MHz", }; - printk(PREFIX "write: byte B 0x%02x\n",buf[1]); - printk(" B0 video mode : %s\n", + tda9887_info("write: byte B 0x%02x\n",buf[1]); + tda9887_info(" B0 video mode : %s\n", (buf[1] & 0x01) ? "video trap" : "sound trap"); - printk(" B1 auto mute fm : %s\n", + tda9887_info(" B1 auto mute fm : %s\n", (buf[1] & 0x02) ? "yes" : "no"); - printk(" B2 carrier mode : %s\n", + tda9887_info(" B2 carrier mode : %s\n", (buf[1] & 0x04) ? "QSS" : "Intercarrier"); - printk(" B3-4 tv sound/radio : %s\n", + tda9887_info(" B3-4 tv sound/radio : %s\n", sound[(buf[1] & 0x18) >> 3]); - printk(" B5 force mute audio: %s\n", + tda9887_info(" B5 force mute audio: %s\n", (buf[1] & 0x20) ? "yes" : "no"); - printk(" B6 output port 1 : %s\n", - (buf[1] & 0x40) ? "high" : "low"); - printk(" B7 output port 2 : %s\n", - (buf[1] & 0x80) ? "high" : "low"); - - printk(PREFIX "write: byte C 0x%02x\n",buf[2]); - printk(" C0-4 top adjustment : %s dB\n", adjust[buf[2] & 0x1f]); - printk(" C5-6 de-emphasis : %s\n", deemph[(buf[2] & 0x60) >> 5]); - printk(" C7 audio gain : %s\n", + 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"); - printk(PREFIX "write: byte E 0x%02x\n",buf[3]); - printk(" E0-1 sound carrier : %s\n", + tda9887_info("write: byte E 0x%02x\n",buf[3]); + tda9887_info(" E0-1 sound carrier : %s\n", carrier[(buf[3] & 0x03)]); - printk(" E6 l pll ganting : %s\n", + tda9887_info(" E6 l pll gating : %s\n", (buf[3] & 0x40) ? "36" : "13"); if (buf[1] & 0x08) { /* radio */ - printk(" E2-4 video if : %s\n", + tda9887_info(" E2-4 video if : %s\n", rif[(buf[3] & 0x0c) >> 2]); - printk(" E7 vif agc output : %s\n", + tda9887_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 */ - printk(" E2-4 video if : %s\n", + tda9887_info(" E2-4 video if : %s\n", vif[(buf[3] & 0x1c) >> 2]); - printk(" E5 tuner gain : %s\n", + tda9887_info(" E5 tuner gain : %s\n", (buf[3] & 0x80) ? ((buf[3] & 0x20) ? "external" : "normal") : ((buf[3] & 0x20) ? "minimum" : "normal")); - printk(" E7 vif agc output : %s\n", + 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"); } - printk("--\n"); + tda9887_info("--\n"); } /* ---------------------------------------------------------------------- */ @@ -350,8 +410,11 @@ static int tda9887_set_tvnorm(struct tda9887 *t, char *buf) struct tvnorm *norm = NULL; int i; - if (t->radio) { - norm = &radio; + if (t->mode == T_RADIO) { + if (t->radio_mode == 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) { @@ -361,32 +424,42 @@ static int tda9887_set_tvnorm(struct tda9887 *t, char *buf) } } if (NULL == norm) { - dprintk(PREFIX "Oops: no tvnorm entry found\n"); + tda9887_dbg("Unsupported tvnorm entry - audio muted\n"); return -1; } - dprintk(PREFIX "configure for: %s\n",norm->name); + tda9887_dbg("configure for: %s\n",norm->name); buf[1] = norm->b; buf[2] = norm->c; buf[3] = norm->e; return 0; } -static unsigned int port1 = 1; -static unsigned int port2 = 1; +static unsigned int port1 = UNSET; +static unsigned int port2 = UNSET; static unsigned int qss = UNSET; -static unsigned int adjust = 0x10; -MODULE_PARM(port1,"i"); -MODULE_PARM(port2,"i"); -MODULE_PARM(qss,"i"); -MODULE_PARM(adjust,"i"); +static unsigned int adjust = UNSET; + +module_param(port1, int, 0644); +module_param(port2, int, 0644); +module_param(qss, int, 0644); +module_param(adjust, int, 0644); static int tda9887_set_insmod(struct tda9887 *t, char *buf) { - if (port1) - buf[1] |= cOutputPort1Inactive; - if (port2) - buf[1] |= cOutputPort2Inactive; + if (UNSET != port1) { + if (port1) + buf[1] |= cOutputPort1Inactive; + else + buf[1] &= ~cOutputPort1Inactive; + } + if (UNSET != port2) { + if (port2) + buf[1] |= cOutputPort2Inactive; + else + buf[1] &= ~cOutputPort2Inactive; + } + if (UNSET != qss) { if (qss) buf[1] |= cQSS; @@ -394,17 +467,24 @@ static int tda9887_set_insmod(struct tda9887 *t, char *buf) buf[1] &= ~cQSS; } - if (adjust >= 0x00 && adjust < 0x20) + if (adjust >= 0x00 && adjust < 0x20) { + buf[2] &= ~cTopMask; buf[2] |= adjust; + } return 0; } static int tda9887_set_config(struct tda9887 *t, char *buf) { - if (t->config & TDA9887_PORT1) + if (t->config & TDA9887_PORT1_ACTIVE) + buf[1] &= ~cOutputPort1Inactive; + if (t->config & TDA9887_PORT1_INACTIVE) buf[1] |= cOutputPort1Inactive; - if (t->config & TDA9887_PORT2) + if (t->config & TDA9887_PORT2_ACTIVE) + buf[1] &= ~cOutputPort2Inactive; + if (t->config & TDA9887_PORT2_INACTIVE) buf[1] |= cOutputPort2Inactive; + if (t->config & TDA9887_QSS) buf[1] |= cQSS; if (t->config & TDA9887_INTERCARRIER) @@ -426,43 +506,24 @@ static int tda9887_set_config(struct tda9887 *t, char *buf) break; } } - return 0; -} - -/* ---------------------------------------------------------------------- */ - -static int tda9887_set_pinnacle(struct tda9887 *t, char *buf) -{ - unsigned int bCarrierMode = UNSET; - - if (t->std & V4L2_STD_PAL) { - if ((1 == t->pinnacle_id) || (7 == t->pinnacle_id)) { - bCarrierMode = cIntercarrier; - } else { - bCarrierMode = cQSS; - } - } - if (t->std & V4L2_STD_NTSC) { - if ((5 == t->pinnacle_id) || (6 == t->pinnacle_id)) { - bCarrierMode = cIntercarrier; - } else { - bCarrierMode = cQSS; - } - } - - if (bCarrierMode != UNSET) { - buf[1] &= ~0x04; - buf[1] |= bCarrierMode; + if (t->config & TDA9887_TOP_SET) { + buf[2] &= ~cTopMask; + buf[2] |= (t->config >> 8) & cTopMask; } + if ((t->config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC)) + buf[1] &= ~cQSS; return 0; } /* ---------------------------------------------------------------------- */ -static char *pal = "-"; -MODULE_PARM(pal,"s"); -static char *secam = "-"; -MODULE_PARM(secam,"s"); +static char pal[] = "--"; +static char secam[] = "--"; +static char ntsc[] = "-"; + +module_param_string(pal, pal, sizeof(pal), 0644); +module_param_string(secam, secam, sizeof(secam), 0644); +module_param_string(ntsc, ntsc, sizeof(ntsc), 0644); static int tda9887_fixup_std(struct tda9887 *t) { @@ -473,36 +534,101 @@ static int tda9887_fixup_std(struct tda9887 *t) case 'B': case 'g': case 'G': - dprintk(PREFIX "insmod fixup: PAL => PAL-BG\n"); - t->std = V4L2_STD_PAL_BG; + case 'h': + case 'H': + case 'n': + case 'N': + if (pal[1] == 'c' || pal[1] == 'C') { + tda9887_dbg("insmod fixup: PAL => PAL-Nc\n"); + t->std = V4L2_STD_PAL_Nc; + } else { + tda9887_dbg("insmod fixup: PAL => PAL-BGHN\n"); + t->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N; + } break; case 'i': case 'I': - dprintk(PREFIX "insmod fixup: PAL => PAL-I\n"); + tda9887_dbg("insmod fixup: PAL => PAL-I\n"); t->std = V4L2_STD_PAL_I; break; case 'd': case 'D': case 'k': case 'K': - dprintk(PREFIX "insmod fixup: PAL => PAL-DK\n"); + tda9887_dbg("insmod fixup: PAL => PAL-DK\n"); t->std = V4L2_STD_PAL_DK; break; + case 'm': + case 'M': + tda9887_dbg("insmod fixup: PAL => PAL-M\n"); + t->std = V4L2_STD_PAL_M; + break; + case '-': + /* default parameter, do nothing */ + break; + default: + tda9887_info("pal= argument not recognised\n"); + break; } } if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) { switch (secam[0]) { + case 'b': + case 'B': + case 'g': + case 'G': + case 'h': + case 'H': + tda9887_dbg("insmod fixup: SECAM => SECAM-BGH\n"); + t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H; + break; case 'd': case 'D': case 'k': case 'K': - dprintk(PREFIX "insmod fixup: SECAM => SECAM-DK\n"); + tda9887_dbg("insmod fixup: SECAM => SECAM-DK\n"); t->std = V4L2_STD_SECAM_DK; break; case 'l': case 'L': - dprintk(PREFIX "insmod fixup: SECAM => SECAM-L\n"); - t->std = V4L2_STD_SECAM_L; + if (secam[1] == 'c' || secam[1] == 'C') { + tda9887_dbg("insmod fixup: SECAM => SECAM-L'\n"); + t->std = V4L2_STD_SECAM_LC; + } else { + tda9887_dbg("insmod fixup: SECAM => SECAM-L\n"); + t->std = V4L2_STD_SECAM_L; + } + break; + case '-': + /* default parameter, do nothing */ + break; + default: + tda9887_info("secam= argument not recognised\n"); + break; + } + } + if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) { + switch (ntsc[0]) { + case 'm': + case 'M': + tda9887_dbg("insmod fixup: NTSC => NTSC-M\n"); + t->std = V4L2_STD_NTSC_M; + break; + case 'j': + case 'J': + tda9887_dbg("insmod fixup: NTSC => NTSC_M_JP\n"); + t->std = V4L2_STD_NTSC_M_JP; + break; + case 'k': + case 'K': + tda9887_dbg("insmod fixup: NTSC => NTSC_M_KR\n"); + t->std = V4L2_STD_NTSC_M_KR; + break; + case '-': + /* default parameter, do nothing */ + break; + default: + tda9887_info("ntsc= argument not recognised\n"); break; } } @@ -515,36 +641,52 @@ static int tda9887_status(struct tda9887 *t) int rc; memset(buf,0,sizeof(buf)); - if (1 != (rc = i2c_master_recv(&t->client,buf,1))) - printk(PREFIX "i2c i/o error: rc == %d (should be 1)\n",rc); - dump_read_message(buf); + if (1 != (rc = i2c_master_recv(&t->client,buf,1))) + tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc); + dump_read_message(t, buf); return 0; } static int tda9887_configure(struct tda9887 *t) { - unsigned char buf[4]; int rc; - memset(buf,0,sizeof(buf)); - tda9887_set_tvnorm(t,buf); - if (UNSET != t->pinnacle_id) { - tda9887_set_pinnacle(t,buf); + memset(t->data,0,sizeof(t->data)); + tda9887_set_tvnorm(t,t->data); + + /* A note on the port settings: + These settings tend to depend on the specifics of the board. + By default they are set to inactive (bit value 1) by this driver, + overwriting any changes made by the tvnorm. This means that it + is the responsibility of the module using the tda9887 to set + these values in case of changes in the tvnorm. + In many cases port 2 should be made active (0) when selecting + SECAM-L, and port 2 should remain inactive (1) for SECAM-L'. + + For the other standards the tda9887 application note says that + the ports should be set to active (0), but, again, that may + differ depending on the precise hardware configuration. + */ + t->data[1] |= cOutputPort1Inactive; + t->data[1] |= cOutputPort2Inactive; + + tda9887_set_config(t,t->data); + tda9887_set_insmod(t,t->data); + + if (t->mode == T_STANDBY) { + t->data[1] |= cForcedMuteAudioON; } - tda9887_set_config(t,buf); - tda9887_set_insmod(t,buf); - dprintk(PREFIX "writing: b=0x%02x c=0x%02x e=0x%02x\n", - buf[1],buf[2],buf[3]); + tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n", + t->data[1],t->data[2],t->data[3]); if (debug > 1) - dump_write_message(buf); + dump_write_message(t, t->data); - if (4 != (rc = i2c_master_send(&t->client,buf,4))) - printk(PREFIX "i2c i/o error: rc == %d (should be 4)\n",rc); + if (4 != (rc = i2c_master_send(&t->client,t->data,4))) + tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc); if (debug > 2) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); + msleep_interruptible(1000); tda9887_status(t); } return 0; @@ -556,37 +698,28 @@ static int tda9887_attach(struct i2c_adapter *adap, int addr, int kind) { struct tda9887 *t; - client_template.adapter = adap; - client_template.addr = addr; + client_template.adapter = adap; + client_template.addr = addr; - printk(PREFIX "chip found @ 0x%x\n", addr<<1); + if (NULL == (t = kzalloc(sizeof(*t), GFP_KERNEL))) + return -ENOMEM; - if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL))) - return -ENOMEM; - memset(t,0,sizeof(*t)); t->client = client_template; - t->std = 0;; - t->pinnacle_id = UNSET; - i2c_set_clientdata(&t->client, t); - i2c_attach_client(&t->client); - + t->std = 0; + t->radio_mode = V4L2_TUNER_MODE_STEREO; + + tda9887_info("chip found @ 0x%x (%s)\n", addr<<1, adap->name); + + i2c_set_clientdata(&t->client, t); + i2c_attach_client(&t->client); + return 0; } static int tda9887_probe(struct i2c_adapter *adap) { -#ifdef I2C_CLASS_TV_ANALOG if (adap->class & I2C_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, tda9887_attach); -#else - switch (adap->id) { - case I2C_ALGO_BIT | I2C_HW_B_BT848: - case I2C_ALGO_BIT | I2C_HW_B_RIVA: - case I2C_ALGO_SAA7134: - return i2c_probe(adap, &addr_data, tda9887_attach); - break; - } -#endif return 0; } @@ -600,30 +733,29 @@ static int tda9887_detach(struct i2c_client *client) } #define SWITCH_V4L2 if (!t->using_v4l2 && debug) \ - printk(PREFIX "switching to v4l2\n"); \ - t->using_v4l2 = 1; + tda9887_info("switching to v4l2\n"); \ + t->using_v4l2 = 1; #define CHECK_V4L2 if (t->using_v4l2) { if (debug) \ - printk(PREFIX "ignore v4l1 call\n"); \ - return 0; } + tda9887_info("ignore v4l1 call\n"); \ + return 0; } static int tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct tda9887 *t = i2c_get_clientdata(client); - switch (cmd) { + switch (cmd) { /* --- configuration --- */ case AUDC_SET_RADIO: - t->radio = 1; + { + t->mode = T_RADIO; tda9887_configure(t); break; - - case AUDC_CONFIG_PINNACLE: + } + case TUNER_SET_STANDBY: { - int *i = arg; - - t->pinnacle_id = *i; + t->mode = T_STANDBY; tda9887_configure(t); break; } @@ -651,7 +783,7 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) struct video_channel *vc = arg; CHECK_V4L2; - t->radio = 0; + t->mode = T_ANALOG_TV; if (vc->norm < ARRAY_SIZE(map)) t->std = map[vc->norm]; tda9887_fixup_std(t); @@ -663,7 +795,7 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) v4l2_std_id *id = arg; SWITCH_V4L2; - t->radio = 0; + t->mode = T_ANALOG_TV; t->std = *id; tda9887_fixup_std(t); tda9887_configure(t); @@ -675,14 +807,14 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) SWITCH_V4L2; if (V4L2_TUNER_ANALOG_TV == f->type) { - if (t->radio == 0) + if (t->mode == T_ANALOG_TV) return 0; - t->radio = 0; + t->mode = T_ANALOG_TV; } if (V4L2_TUNER_RADIO == f->type) { - if (t->radio == 1) + if (t->mode == T_RADIO) return 0; - t->radio = 1; + t->mode = T_RADIO; } tda9887_configure(t); break; @@ -697,7 +829,7 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) }; struct v4l2_tuner* tuner = arg; - if (t->radio) { + if (t->mode == T_RADIO) { __u8 reg = 0; tuner->afc=0; if (1 == i2c_master_recv(&t->client,®,1)) @@ -705,6 +837,21 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) } break; } + case VIDIOC_S_TUNER: + { + struct v4l2_tuner* tuner = arg; + + if (t->mode == T_RADIO) { + t->radio_mode = tuner->audmode; + tda9887_configure (t); + } + break; + } + case VIDIOC_LOG_STATUS: + { + tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", t->data[1], t->data[2], t->data[3]); + break; + } default: /* nothing */ break; @@ -712,22 +859,42 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; } +static int tda9887_suspend(struct device * dev, pm_message_t state) +{ + struct i2c_client *c = container_of(dev, struct i2c_client, dev); + struct tda9887 *t = i2c_get_clientdata(c); + + tda9887_dbg("suspend\n"); + return 0; +} + +static int tda9887_resume(struct device * dev) +{ + struct i2c_client *c = container_of(dev, struct i2c_client, dev); + struct tda9887 *t = i2c_get_clientdata(c); + + tda9887_dbg("resume\n"); + tda9887_configure(t); + return 0; +} + /* ----------------------------------------------------------------------- */ static struct i2c_driver driver = { - .owner = THIS_MODULE, - .name = "i2c tda9887 driver", - .id = -1, /* FIXME */ - .flags = I2C_DF_NOTIFY, - .attach_adapter = tda9887_probe, - .detach_client = tda9887_detach, - .command = tda9887_command, + .id = I2C_DRIVERID_TDA9887, + .attach_adapter = tda9887_probe, + .detach_client = tda9887_detach, + .command = tda9887_command, + .driver = { + .name = "tda9887", + .suspend = tda9887_suspend, + .resume = tda9887_resume, + }, }; static struct i2c_client client_template = { - I2C_DEVNAME("tda9887"), - .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, + .name = "tda9887", + .driver = &driver, }; static int __init tda9887_init_module(void)